1 // Copyright 2014 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/js-typed-lowering.h"
6
7 #include "src/ast/modules.h"
8 #include "src/builtins/builtins-utils.h"
9 #include "src/code-factory.h"
10 #include "src/compilation-dependencies.h"
11 #include "src/compiler/access-builder.h"
12 #include "src/compiler/js-graph.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/node-properties.h"
16 #include "src/compiler/operator-properties.h"
17 #include "src/compiler/type-cache.h"
18 #include "src/compiler/types.h"
19 #include "src/objects-inl.h"
20
21 namespace v8 {
22 namespace internal {
23 namespace compiler {
24
25 // A helper class to simplify the process of reducing a single binop node with a
26 // JSOperator. This class manages the rewriting of context, control, and effect
27 // dependencies during lowering of a binop and contains numerous helper
28 // functions for matching the types of inputs to an operation.
29 class JSBinopReduction final {
30 public:
JSBinopReduction(JSTypedLowering * lowering,Node * node)31 JSBinopReduction(JSTypedLowering* lowering, Node* node)
32 : lowering_(lowering), node_(node) {}
33
GetCompareNumberOperationHint(NumberOperationHint * hint)34 bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
35 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
36 DCHECK_EQ(1, node_->op()->EffectOutputCount());
37 switch (CompareOperationHintOf(node_->op())) {
38 case CompareOperationHint::kSignedSmall:
39 *hint = NumberOperationHint::kSignedSmall;
40 return true;
41 case CompareOperationHint::kNumber:
42 *hint = NumberOperationHint::kNumber;
43 return true;
44 case CompareOperationHint::kNumberOrOddball:
45 *hint = NumberOperationHint::kNumberOrOddball;
46 return true;
47 case CompareOperationHint::kAny:
48 case CompareOperationHint::kNone:
49 case CompareOperationHint::kString:
50 case CompareOperationHint::kReceiver:
51 case CompareOperationHint::kInternalizedString:
52 break;
53 }
54 }
55 return false;
56 }
57
IsInternalizedStringCompareOperation()58 bool IsInternalizedStringCompareOperation() {
59 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
60 DCHECK_EQ(1, node_->op()->EffectOutputCount());
61 return (CompareOperationHintOf(node_->op()) ==
62 CompareOperationHint::kInternalizedString) &&
63 BothInputsMaybe(Type::InternalizedString());
64 }
65 return false;
66 }
67
IsReceiverCompareOperation()68 bool IsReceiverCompareOperation() {
69 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
70 DCHECK_EQ(1, node_->op()->EffectOutputCount());
71 return (CompareOperationHintOf(node_->op()) ==
72 CompareOperationHint::kReceiver) &&
73 BothInputsMaybe(Type::Receiver());
74 }
75 return false;
76 }
77
IsStringCompareOperation()78 bool IsStringCompareOperation() {
79 if (lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) {
80 DCHECK_EQ(1, node_->op()->EffectOutputCount());
81 return (CompareOperationHintOf(node_->op()) ==
82 CompareOperationHint::kString) &&
83 BothInputsMaybe(Type::String());
84 }
85 return false;
86 }
87
88 // Check if a string addition will definitely result in creating a ConsString,
89 // i.e. if the combined length of the resulting string exceeds the ConsString
90 // minimum length.
ShouldCreateConsString()91 bool ShouldCreateConsString() {
92 DCHECK_EQ(IrOpcode::kJSAdd, node_->opcode());
93 DCHECK(OneInputIs(Type::String()));
94 if (BothInputsAre(Type::String()) ||
95 ((lowering_->flags() & JSTypedLowering::kDeoptimizationEnabled) &&
96 BinaryOperationHintOf(node_->op()) == BinaryOperationHint::kString)) {
97 HeapObjectBinopMatcher m(node_);
98 if (m.right().HasValue() && m.right().Value()->IsString()) {
99 Handle<String> right_string = Handle<String>::cast(m.right().Value());
100 if (right_string->length() >= ConsString::kMinLength) return true;
101 }
102 if (m.left().HasValue() && m.left().Value()->IsString()) {
103 Handle<String> left_string = Handle<String>::cast(m.left().Value());
104 if (left_string->length() >= ConsString::kMinLength) {
105 // The invariant for ConsString requires the left hand side to be
106 // a sequential or external string if the right hand side is the
107 // empty string. Since we don't know anything about the right hand
108 // side here, we must ensure that the left hand side satisfy the
109 // constraints independent of the right hand side.
110 return left_string->IsSeqString() || left_string->IsExternalString();
111 }
112 }
113 }
114 return false;
115 }
116
117 // Inserts a CheckReceiver for the left input.
CheckLeftInputToReceiver()118 void CheckLeftInputToReceiver() {
119 Node* left_input = graph()->NewNode(simplified()->CheckReceiver(), left(),
120 effect(), control());
121 node_->ReplaceInput(0, left_input);
122 update_effect(left_input);
123 }
124
125 // Checks that both inputs are Receiver, and if we don't know
126 // statically that one side is already a Receiver, insert a
127 // CheckReceiver node.
CheckInputsToReceiver()128 void CheckInputsToReceiver() {
129 if (!left_type()->Is(Type::Receiver())) {
130 CheckLeftInputToReceiver();
131 }
132 if (!right_type()->Is(Type::Receiver())) {
133 Node* right_input = graph()->NewNode(simplified()->CheckReceiver(),
134 right(), effect(), control());
135 node_->ReplaceInput(1, right_input);
136 update_effect(right_input);
137 }
138 }
139
140 // Checks that both inputs are String, and if we don't know
141 // statically that one side is already a String, insert a
142 // CheckString node.
CheckInputsToString()143 void CheckInputsToString() {
144 if (!left_type()->Is(Type::String())) {
145 Node* left_input = graph()->NewNode(simplified()->CheckString(), left(),
146 effect(), control());
147 node_->ReplaceInput(0, left_input);
148 update_effect(left_input);
149 }
150 if (!right_type()->Is(Type::String())) {
151 Node* right_input = graph()->NewNode(simplified()->CheckString(), right(),
152 effect(), control());
153 node_->ReplaceInput(1, right_input);
154 update_effect(right_input);
155 }
156 }
157
158 // Checks that both inputs are InternalizedString, and if we don't know
159 // statically that one side is already an InternalizedString, insert a
160 // CheckInternalizedString node.
CheckInputsToInternalizedString()161 void CheckInputsToInternalizedString() {
162 if (!left_type()->Is(Type::UniqueName())) {
163 Node* left_input = graph()->NewNode(
164 simplified()->CheckInternalizedString(), left(), effect(), control());
165 node_->ReplaceInput(0, left_input);
166 update_effect(left_input);
167 }
168 if (!right_type()->Is(Type::UniqueName())) {
169 Node* right_input =
170 graph()->NewNode(simplified()->CheckInternalizedString(), right(),
171 effect(), control());
172 node_->ReplaceInput(1, right_input);
173 update_effect(right_input);
174 }
175 }
176
ConvertInputsToNumber()177 void ConvertInputsToNumber() {
178 // To convert the inputs to numbers, we have to provide frame states
179 // for lazy bailouts in the ToNumber conversions.
180 // We use a little hack here: we take the frame state before the binary
181 // operation and use it to construct the frame states for the conversion
182 // so that after the deoptimization, the binary operation IC gets
183 // already converted values from full code. This way we are sure that we
184 // will not re-do any of the side effects.
185
186 Node* left_input = nullptr;
187 Node* right_input = nullptr;
188 bool left_is_primitive = left_type()->Is(Type::PlainPrimitive());
189 bool right_is_primitive = right_type()->Is(Type::PlainPrimitive());
190 bool handles_exception = NodeProperties::IsExceptionalCall(node_);
191
192 if (!left_is_primitive && !right_is_primitive && handles_exception) {
193 ConvertBothInputsToNumber(&left_input, &right_input);
194 } else {
195 left_input = left_is_primitive
196 ? ConvertPlainPrimitiveToNumber(left())
197 : ConvertSingleInputToNumber(
198 left(), CreateFrameStateForLeftInput());
199 right_input =
200 right_is_primitive
201 ? ConvertPlainPrimitiveToNumber(right())
202 : ConvertSingleInputToNumber(
203 right(), CreateFrameStateForRightInput(left_input));
204 }
205
206 node_->ReplaceInput(0, left_input);
207 node_->ReplaceInput(1, right_input);
208 }
209
ConvertInputsToUI32(Signedness left_signedness,Signedness right_signedness)210 void ConvertInputsToUI32(Signedness left_signedness,
211 Signedness right_signedness) {
212 node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
213 node_->ReplaceInput(1, ConvertToUI32(right(), right_signedness));
214 }
215
SwapInputs()216 void SwapInputs() {
217 Node* l = left();
218 Node* r = right();
219 node_->ReplaceInput(0, r);
220 node_->ReplaceInput(1, l);
221 }
222
223 // Remove all effect and control inputs and outputs to this node and change
224 // to the pure operator {op}, possibly inserting a boolean inversion.
ChangeToPureOperator(const Operator * op,bool invert=false,Type * type=Type::Any ())225 Reduction ChangeToPureOperator(const Operator* op, bool invert = false,
226 Type* type = Type::Any()) {
227 DCHECK_EQ(0, op->EffectInputCount());
228 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
229 DCHECK_EQ(0, op->ControlInputCount());
230 DCHECK_EQ(2, op->ValueInputCount());
231
232 // Remove the effects from the node, and update its effect/control usages.
233 if (node_->op()->EffectInputCount() > 0) {
234 lowering_->RelaxEffectsAndControls(node_);
235 }
236 // Remove the inputs corresponding to context, effect, and control.
237 NodeProperties::RemoveNonValueInputs(node_);
238 // Finally, update the operator to the new one.
239 NodeProperties::ChangeOp(node_, op);
240
241 // TODO(jarin): Replace the explicit typing hack with a call to some method
242 // that encapsulates changing the operator and re-typing.
243 Type* node_type = NodeProperties::GetType(node_);
244 NodeProperties::SetType(node_, Type::Intersect(node_type, type, zone()));
245
246 if (invert) {
247 // Insert an boolean not to invert the value.
248 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
249 node_->ReplaceUses(value);
250 // Note: ReplaceUses() smashes all uses, so smash it back here.
251 value->ReplaceInput(0, node_);
252 return lowering_->Replace(value);
253 }
254 return lowering_->Changed(node_);
255 }
256
ChangeToSpeculativeOperator(const Operator * op,bool invert,Type * upper_bound)257 Reduction ChangeToSpeculativeOperator(const Operator* op, bool invert,
258 Type* upper_bound) {
259 DCHECK_EQ(1, op->EffectInputCount());
260 DCHECK_EQ(1, op->EffectOutputCount());
261 DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
262 DCHECK_EQ(1, op->ControlInputCount());
263 DCHECK_EQ(0, op->ControlOutputCount());
264 DCHECK_EQ(0, OperatorProperties::GetFrameStateInputCount(op));
265 DCHECK_EQ(2, op->ValueInputCount());
266
267 DCHECK_EQ(1, node_->op()->EffectInputCount());
268 DCHECK_EQ(1, node_->op()->EffectOutputCount());
269 DCHECK_EQ(1, node_->op()->ControlInputCount());
270 DCHECK_EQ(2, node_->op()->ValueInputCount());
271
272 // Reconnect the control output to bypass the IfSuccess node and
273 // possibly disconnect from the IfException node.
274 for (Edge edge : node_->use_edges()) {
275 Node* const user = edge.from();
276 DCHECK(!user->IsDead());
277 if (NodeProperties::IsControlEdge(edge)) {
278 if (user->opcode() == IrOpcode::kIfSuccess) {
279 user->ReplaceUses(NodeProperties::GetControlInput(node_));
280 user->Kill();
281 } else {
282 DCHECK_EQ(user->opcode(), IrOpcode::kIfException);
283 edge.UpdateTo(jsgraph()->Dead());
284 }
285 }
286 }
287
288 // Remove the frame state and the context.
289 if (OperatorProperties::HasFrameStateInput(node_->op())) {
290 node_->RemoveInput(NodeProperties::FirstFrameStateIndex(node_));
291 }
292 node_->RemoveInput(NodeProperties::FirstContextIndex(node_));
293
294 NodeProperties::ChangeOp(node_, op);
295
296 // Update the type to number.
297 Type* node_type = NodeProperties::GetType(node_);
298 NodeProperties::SetType(node_,
299 Type::Intersect(node_type, upper_bound, zone()));
300
301 if (invert) {
302 // Insert an boolean not to invert the value.
303 Node* value = graph()->NewNode(simplified()->BooleanNot(), node_);
304 node_->ReplaceUses(value);
305 // Note: ReplaceUses() smashes all uses, so smash it back here.
306 value->ReplaceInput(0, node_);
307 return lowering_->Replace(value);
308 }
309 return lowering_->Changed(node_);
310 }
311
ChangeToPureOperator(const Operator * op,Type * type)312 Reduction ChangeToPureOperator(const Operator* op, Type* type) {
313 return ChangeToPureOperator(op, false, type);
314 }
315
ChangeToSpeculativeOperator(const Operator * op,Type * type)316 Reduction ChangeToSpeculativeOperator(const Operator* op, Type* type) {
317 return ChangeToSpeculativeOperator(op, false, type);
318 }
319
NumberOp()320 const Operator* NumberOp() {
321 switch (node_->opcode()) {
322 case IrOpcode::kJSAdd:
323 return simplified()->NumberAdd();
324 case IrOpcode::kJSSubtract:
325 return simplified()->NumberSubtract();
326 case IrOpcode::kJSMultiply:
327 return simplified()->NumberMultiply();
328 case IrOpcode::kJSDivide:
329 return simplified()->NumberDivide();
330 case IrOpcode::kJSModulus:
331 return simplified()->NumberModulus();
332 case IrOpcode::kJSBitwiseAnd:
333 return simplified()->NumberBitwiseAnd();
334 case IrOpcode::kJSBitwiseOr:
335 return simplified()->NumberBitwiseOr();
336 case IrOpcode::kJSBitwiseXor:
337 return simplified()->NumberBitwiseXor();
338 case IrOpcode::kJSShiftLeft:
339 return simplified()->NumberShiftLeft();
340 case IrOpcode::kJSShiftRight:
341 return simplified()->NumberShiftRight();
342 case IrOpcode::kJSShiftRightLogical:
343 return simplified()->NumberShiftRightLogical();
344 default:
345 break;
346 }
347 UNREACHABLE();
348 return nullptr;
349 }
350
NumberOpFromSpeculativeNumberOp()351 const Operator* NumberOpFromSpeculativeNumberOp() {
352 switch (node_->opcode()) {
353 case IrOpcode::kSpeculativeNumberAdd:
354 return simplified()->NumberAdd();
355 case IrOpcode::kSpeculativeNumberSubtract:
356 return simplified()->NumberSubtract();
357 case IrOpcode::kSpeculativeNumberMultiply:
358 return simplified()->NumberMultiply();
359 case IrOpcode::kSpeculativeNumberDivide:
360 return simplified()->NumberDivide();
361 case IrOpcode::kSpeculativeNumberModulus:
362 return simplified()->NumberModulus();
363 default:
364 break;
365 }
366 UNREACHABLE();
367 return nullptr;
368 }
369
LeftInputIs(Type * t)370 bool LeftInputIs(Type* t) { return left_type()->Is(t); }
371
RightInputIs(Type * t)372 bool RightInputIs(Type* t) { return right_type()->Is(t); }
373
OneInputIs(Type * t)374 bool OneInputIs(Type* t) { return LeftInputIs(t) || RightInputIs(t); }
375
BothInputsAre(Type * t)376 bool BothInputsAre(Type* t) { return LeftInputIs(t) && RightInputIs(t); }
377
BothInputsMaybe(Type * t)378 bool BothInputsMaybe(Type* t) {
379 return left_type()->Maybe(t) && right_type()->Maybe(t);
380 }
381
OneInputCannotBe(Type * t)382 bool OneInputCannotBe(Type* t) {
383 return !left_type()->Maybe(t) || !right_type()->Maybe(t);
384 }
385
NeitherInputCanBe(Type * t)386 bool NeitherInputCanBe(Type* t) {
387 return !left_type()->Maybe(t) && !right_type()->Maybe(t);
388 }
389
effect()390 Node* effect() { return NodeProperties::GetEffectInput(node_); }
control()391 Node* control() { return NodeProperties::GetControlInput(node_); }
context()392 Node* context() { return NodeProperties::GetContextInput(node_); }
left()393 Node* left() { return NodeProperties::GetValueInput(node_, 0); }
right()394 Node* right() { return NodeProperties::GetValueInput(node_, 1); }
left_type()395 Type* left_type() { return NodeProperties::GetType(node_->InputAt(0)); }
right_type()396 Type* right_type() { return NodeProperties::GetType(node_->InputAt(1)); }
type()397 Type* type() { return NodeProperties::GetType(node_); }
398
simplified()399 SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
graph() const400 Graph* graph() const { return lowering_->graph(); }
jsgraph()401 JSGraph* jsgraph() { return lowering_->jsgraph(); }
javascript()402 JSOperatorBuilder* javascript() { return lowering_->javascript(); }
common()403 CommonOperatorBuilder* common() { return jsgraph()->common(); }
zone() const404 Zone* zone() const { return graph()->zone(); }
405
406 private:
407 JSTypedLowering* lowering_; // The containing lowering instance.
408 Node* node_; // The original node.
409
CreateFrameStateForLeftInput()410 Node* CreateFrameStateForLeftInput() {
411 // Deoptimization is disabled => return dummy frame state instead.
412 Node* dummy_state = NodeProperties::GetFrameStateInput(node_);
413 DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone());
414 return dummy_state;
415 }
416
CreateFrameStateForRightInput(Node * converted_left)417 Node* CreateFrameStateForRightInput(Node* converted_left) {
418 // Deoptimization is disabled => return dummy frame state instead.
419 Node* dummy_state = NodeProperties::GetFrameStateInput(node_);
420 DCHECK(OpParameter<FrameStateInfo>(dummy_state).bailout_id().IsNone());
421 return dummy_state;
422 }
423
ConvertPlainPrimitiveToNumber(Node * node)424 Node* ConvertPlainPrimitiveToNumber(Node* node) {
425 DCHECK(NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
426 // Avoid inserting too many eager ToNumber() operations.
427 Reduction const reduction = lowering_->ReduceJSToNumberInput(node);
428 if (reduction.Changed()) return reduction.replacement();
429 if (NodeProperties::GetType(node)->Is(Type::Number())) {
430 return node;
431 }
432 return graph()->NewNode(simplified()->PlainPrimitiveToNumber(), node);
433 }
434
ConvertSingleInputToNumber(Node * node,Node * frame_state)435 Node* ConvertSingleInputToNumber(Node* node, Node* frame_state) {
436 DCHECK(!NodeProperties::GetType(node)->Is(Type::PlainPrimitive()));
437 Node* const n = graph()->NewNode(javascript()->ToNumber(), node, context(),
438 frame_state, effect(), control());
439 Node* const if_success = graph()->NewNode(common()->IfSuccess(), n);
440 NodeProperties::ReplaceControlInput(node_, if_success);
441 NodeProperties::ReplaceUses(node_, node_, node_, node_, n);
442 update_effect(n);
443 return n;
444 }
445
ConvertBothInputsToNumber(Node ** left_result,Node ** right_result)446 void ConvertBothInputsToNumber(Node** left_result, Node** right_result) {
447 Node* projections[2];
448
449 // Find {IfSuccess} and {IfException} continuations of the operation.
450 NodeProperties::CollectControlProjections(node_, projections, 2);
451 Node* if_exception = projections[1];
452 Node* if_success = projections[0];
453
454 // Insert two ToNumber() operations that both potentially throw.
455 Node* left_state = CreateFrameStateForLeftInput();
456 Node* left_conv =
457 graph()->NewNode(javascript()->ToNumber(), left(), context(),
458 left_state, effect(), control());
459 Node* left_success = graph()->NewNode(common()->IfSuccess(), left_conv);
460 Node* right_state = CreateFrameStateForRightInput(left_conv);
461 Node* right_conv =
462 graph()->NewNode(javascript()->ToNumber(), right(), context(),
463 right_state, left_conv, left_success);
464 Node* left_exception =
465 graph()->NewNode(common()->IfException(), left_conv, left_conv);
466 Node* right_exception =
467 graph()->NewNode(common()->IfException(), right_conv, right_conv);
468 NodeProperties::ReplaceControlInput(if_success, right_conv);
469 update_effect(right_conv);
470
471 // Wire conversions to existing {IfException} continuation.
472 Node* exception_merge = if_exception;
473 Node* exception_value =
474 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
475 left_exception, right_exception, exception_merge);
476 Node* exception_effect =
477 graph()->NewNode(common()->EffectPhi(2), left_exception,
478 right_exception, exception_merge);
479 for (Edge edge : exception_merge->use_edges()) {
480 if (NodeProperties::IsEffectEdge(edge)) edge.UpdateTo(exception_effect);
481 if (NodeProperties::IsValueEdge(edge)) edge.UpdateTo(exception_value);
482 }
483 NodeProperties::RemoveType(exception_merge);
484 exception_merge->ReplaceInput(0, left_exception);
485 exception_merge->ReplaceInput(1, right_exception);
486 NodeProperties::ChangeOp(exception_merge, common()->Merge(2));
487
488 *left_result = left_conv;
489 *right_result = right_conv;
490 }
491
ConvertToUI32(Node * node,Signedness signedness)492 Node* ConvertToUI32(Node* node, Signedness signedness) {
493 // Avoid introducing too many eager NumberToXXnt32() operations.
494 Type* type = NodeProperties::GetType(node);
495 if (signedness == kSigned) {
496 if (!type->Is(Type::Signed32())) {
497 node = graph()->NewNode(simplified()->NumberToInt32(), node);
498 }
499 } else {
500 DCHECK_EQ(kUnsigned, signedness);
501 if (!type->Is(Type::Unsigned32())) {
502 node = graph()->NewNode(simplified()->NumberToUint32(), node);
503 }
504 }
505 return node;
506 }
507
update_effect(Node * effect)508 void update_effect(Node* effect) {
509 NodeProperties::ReplaceEffectInput(node_, effect);
510 }
511 };
512
513
514 // TODO(turbofan): js-typed-lowering improvements possible
515 // - immediately put in type bounds for all new nodes
516 // - relax effects from generic but not-side-effecting operations
517
JSTypedLowering(Editor * editor,CompilationDependencies * dependencies,Flags flags,JSGraph * jsgraph,Zone * zone)518 JSTypedLowering::JSTypedLowering(Editor* editor,
519 CompilationDependencies* dependencies,
520 Flags flags, JSGraph* jsgraph, Zone* zone)
521 : AdvancedReducer(editor),
522 dependencies_(dependencies),
523 flags_(flags),
524 jsgraph_(jsgraph),
525 pointer_comparable_type_(Type::Union(
526 Type::Oddball(),
527 Type::Union(
528 Type::SymbolOrReceiver(),
529 Type::HeapConstant(factory()->empty_string(), graph()->zone()),
530 graph()->zone()),
531 graph()->zone())),
532 type_cache_(TypeCache::Get()) {
533 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) {
534 double min = kMinInt / (1 << k);
535 double max = kMaxInt / (1 << k);
536 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone());
537 }
538 }
539
ReduceSpeculativeNumberAdd(Node * node)540 Reduction JSTypedLowering::ReduceSpeculativeNumberAdd(Node* node) {
541 JSBinopReduction r(this, node);
542 NumberOperationHint hint = NumberOperationHintOf(node->op());
543 if (hint == NumberOperationHint::kNumberOrOddball &&
544 r.BothInputsAre(Type::PlainPrimitive()) &&
545 r.NeitherInputCanBe(Type::StringOrReceiver())) {
546 // SpeculativeNumberAdd(x:-string, y:-string) =>
547 // NumberAdd(ToNumber(x), ToNumber(y))
548 r.ConvertInputsToNumber();
549 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
550 }
551 return NoChange();
552 }
553
ReduceJSAdd(Node * node)554 Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
555 JSBinopReduction r(this, node);
556 if (r.BothInputsAre(Type::Number())) {
557 // JSAdd(x:number, y:number) => NumberAdd(x, y)
558 r.ConvertInputsToNumber();
559 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
560 }
561 if ((r.BothInputsAre(Type::PlainPrimitive()) ||
562 !(flags() & kDeoptimizationEnabled)) &&
563 r.NeitherInputCanBe(Type::StringOrReceiver())) {
564 // JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
565 r.ConvertInputsToNumber();
566 return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
567 }
568 if (r.OneInputIs(Type::String())) {
569 if (r.ShouldCreateConsString()) {
570 return ReduceCreateConsString(node);
571 }
572 StringAddFlags flags = STRING_ADD_CHECK_NONE;
573 if (!r.LeftInputIs(Type::String())) {
574 flags = STRING_ADD_CONVERT_LEFT;
575 } else if (!r.RightInputIs(Type::String())) {
576 flags = STRING_ADD_CONVERT_RIGHT;
577 }
578 Operator::Properties properties = node->op()->properties();
579 if (r.NeitherInputCanBe(Type::Receiver())) {
580 // Both sides are already strings, so we know that the
581 // string addition will not cause any observable side
582 // effects; it can still throw obviously.
583 properties = Operator::kNoWrite | Operator::kNoDeopt;
584 }
585 // JSAdd(x:string, y) => CallStub[StringAdd](x, y)
586 // JSAdd(x, y:string) => CallStub[StringAdd](x, y)
587 Callable const callable =
588 CodeFactory::StringAdd(isolate(), flags, NOT_TENURED);
589 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
590 isolate(), graph()->zone(), callable.descriptor(), 0,
591 CallDescriptor::kNeedsFrameState, properties);
592 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
593 node->InsertInput(graph()->zone(), 0,
594 jsgraph()->HeapConstant(callable.code()));
595 NodeProperties::ChangeOp(node, common()->Call(desc));
596 return Changed(node);
597 }
598 return NoChange();
599 }
600
ReduceNumberBinop(Node * node)601 Reduction JSTypedLowering::ReduceNumberBinop(Node* node) {
602 JSBinopReduction r(this, node);
603 if (r.BothInputsAre(Type::PlainPrimitive()) ||
604 !(flags() & kDeoptimizationEnabled)) {
605 r.ConvertInputsToNumber();
606 return r.ChangeToPureOperator(r.NumberOp(), Type::Number());
607 }
608 return NoChange();
609 }
610
ReduceSpeculativeNumberBinop(Node * node)611 Reduction JSTypedLowering::ReduceSpeculativeNumberBinop(Node* node) {
612 JSBinopReduction r(this, node);
613 NumberOperationHint hint = NumberOperationHintOf(node->op());
614 if (hint == NumberOperationHint::kNumberOrOddball &&
615 r.BothInputsAre(Type::NumberOrOddball())) {
616 r.ConvertInputsToNumber();
617 return r.ChangeToPureOperator(r.NumberOpFromSpeculativeNumberOp(),
618 Type::Number());
619 }
620 return NoChange();
621 }
622
ReduceInt32Binop(Node * node)623 Reduction JSTypedLowering::ReduceInt32Binop(Node* node) {
624 JSBinopReduction r(this, node);
625 if (r.BothInputsAre(Type::PlainPrimitive()) ||
626 !(flags() & kDeoptimizationEnabled)) {
627 r.ConvertInputsToNumber();
628 r.ConvertInputsToUI32(kSigned, kSigned);
629 return r.ChangeToPureOperator(r.NumberOp(), Type::Signed32());
630 }
631 return NoChange();
632 }
633
ReduceUI32Shift(Node * node,Signedness signedness)634 Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Signedness signedness) {
635 JSBinopReduction r(this, node);
636 if (r.BothInputsAre(Type::PlainPrimitive()) ||
637 !(flags() & kDeoptimizationEnabled)) {
638 r.ConvertInputsToNumber();
639 r.ConvertInputsToUI32(signedness, kUnsigned);
640 return r.ChangeToPureOperator(r.NumberOp(), signedness == kUnsigned
641 ? Type::Unsigned32()
642 : Type::Signed32());
643 }
644 return NoChange();
645 }
646
ReduceCreateConsString(Node * node)647 Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
648 Node* first = NodeProperties::GetValueInput(node, 0);
649 Node* second = NodeProperties::GetValueInput(node, 1);
650 Node* context = NodeProperties::GetContextInput(node);
651 Node* frame_state = NodeProperties::GetFrameStateInput(node);
652 Node* effect = NodeProperties::GetEffectInput(node);
653 Node* control = NodeProperties::GetControlInput(node);
654
655 // Make sure {first} is actually a String.
656 Type* first_type = NodeProperties::GetType(first);
657 if (!first_type->Is(Type::String())) {
658 first = effect =
659 graph()->NewNode(simplified()->CheckString(), first, effect, control);
660 first_type = NodeProperties::GetType(first);
661 }
662
663 // Make sure {second} is actually a String.
664 Type* second_type = NodeProperties::GetType(second);
665 if (!second_type->Is(Type::String())) {
666 second = effect =
667 graph()->NewNode(simplified()->CheckString(), second, effect, control);
668 second_type = NodeProperties::GetType(second);
669 }
670
671 // Determine the {first} length.
672 HeapObjectBinopMatcher m(node);
673 Node* first_length =
674 (m.left().HasValue() && m.left().Value()->IsString())
675 ? jsgraph()->Constant(
676 Handle<String>::cast(m.left().Value())->length())
677 : effect = graph()->NewNode(
678 simplified()->LoadField(AccessBuilder::ForStringLength()),
679 first, effect, control);
680
681 // Determine the {second} length.
682 Node* second_length =
683 (m.right().HasValue() && m.right().Value()->IsString())
684 ? jsgraph()->Constant(
685 Handle<String>::cast(m.right().Value())->length())
686 : effect = graph()->NewNode(
687 simplified()->LoadField(AccessBuilder::ForStringLength()),
688 second, effect, control);
689
690 // Compute the resulting length.
691 Node* length =
692 graph()->NewNode(simplified()->NumberAdd(), first_length, second_length);
693
694 // Check if we would overflow the allowed maximum string length.
695 Node* check = graph()->NewNode(simplified()->NumberLessThanOrEqual(), length,
696 jsgraph()->Constant(String::kMaxLength));
697 if (isolate()->IsStringLengthOverflowIntact()) {
698 // Add a code dependency on the string length overflow protector.
699 dependencies()->AssumePropertyCell(factory()->string_length_protector());
700
701 // We can just deoptimize if the {check} fails. Besides generating a
702 // shorter code sequence than the version below, this has the additional
703 // benefit of not holding on to the lazy {frame_state} and thus potentially
704 // reduces the number of live ranges and allows for more truncations.
705 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
706 } else {
707 Node* branch =
708 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
709 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
710 Node* efalse = effect;
711 {
712 // Throw a RangeError in case of overflow.
713 Node* vfalse = efalse = graph()->NewNode(
714 javascript()->CallRuntime(Runtime::kThrowInvalidStringLength),
715 context, frame_state, efalse, if_false);
716 if_false = graph()->NewNode(common()->IfSuccess(), vfalse);
717 if_false = graph()->NewNode(common()->Throw(), vfalse, efalse, if_false);
718 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
719 NodeProperties::MergeControlToEnd(graph(), common(), if_false);
720 Revisit(graph()->end());
721
722 // Update potential {IfException} uses of {node} to point to the
723 // %ThrowInvalidStringLength runtime call node instead.
724 for (Edge edge : node->use_edges()) {
725 if (edge.from()->opcode() == IrOpcode::kIfException) {
726 DCHECK(NodeProperties::IsControlEdge(edge) ||
727 NodeProperties::IsEffectEdge(edge));
728 edge.UpdateTo(vfalse);
729 Revisit(edge.from());
730 }
731 }
732 }
733 control = graph()->NewNode(common()->IfTrue(), branch);
734 }
735
736 // Figure out the map for the resulting ConsString.
737 // TODO(turbofan): We currently just use the cons_string_map here for
738 // the sake of simplicity; we could also try to be smarter here and
739 // use the one_byte_cons_string_map instead when the resulting ConsString
740 // contains only one byte characters.
741 Node* value_map = jsgraph()->HeapConstant(factory()->cons_string_map());
742
743 // Allocate the resulting ConsString.
744 effect = graph()->NewNode(
745 common()->BeginRegion(RegionObservability::kNotObservable), effect);
746 Node* value = effect =
747 graph()->NewNode(simplified()->Allocate(NOT_TENURED),
748 jsgraph()->Constant(ConsString::kSize), effect, control);
749 NodeProperties::SetType(value, Type::OtherString());
750 effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
751 value, value_map, effect, control);
752 effect = graph()->NewNode(
753 simplified()->StoreField(AccessBuilder::ForNameHashField()), value,
754 jsgraph()->Constant(Name::kEmptyHashField), effect, control);
755 effect = graph()->NewNode(
756 simplified()->StoreField(AccessBuilder::ForStringLength()), value, length,
757 effect, control);
758 effect = graph()->NewNode(
759 simplified()->StoreField(AccessBuilder::ForConsStringFirst()), value,
760 first, effect, control);
761 effect = graph()->NewNode(
762 simplified()->StoreField(AccessBuilder::ForConsStringSecond()), value,
763 second, effect, control);
764
765 // Morph the {node} into a {FinishRegion}.
766 ReplaceWithValue(node, node, node, control);
767 node->ReplaceInput(0, value);
768 node->ReplaceInput(1, effect);
769 node->TrimInputCount(2);
770 NodeProperties::ChangeOp(node, common()->FinishRegion());
771 return Changed(node);
772 }
773
ReduceJSComparison(Node * node)774 Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
775 JSBinopReduction r(this, node);
776 if (r.BothInputsAre(Type::String())) {
777 // If both inputs are definitely strings, perform a string comparison.
778 const Operator* stringOp;
779 switch (node->opcode()) {
780 case IrOpcode::kJSLessThan:
781 stringOp = simplified()->StringLessThan();
782 break;
783 case IrOpcode::kJSGreaterThan:
784 stringOp = simplified()->StringLessThan();
785 r.SwapInputs(); // a > b => b < a
786 break;
787 case IrOpcode::kJSLessThanOrEqual:
788 stringOp = simplified()->StringLessThanOrEqual();
789 break;
790 case IrOpcode::kJSGreaterThanOrEqual:
791 stringOp = simplified()->StringLessThanOrEqual();
792 r.SwapInputs(); // a >= b => b <= a
793 break;
794 default:
795 return NoChange();
796 }
797 r.ChangeToPureOperator(stringOp);
798 return Changed(node);
799 }
800
801 NumberOperationHint hint;
802 const Operator* less_than;
803 const Operator* less_than_or_equal;
804 if (r.BothInputsAre(Type::Signed32()) ||
805 r.BothInputsAre(Type::Unsigned32())) {
806 less_than = simplified()->NumberLessThan();
807 less_than_or_equal = simplified()->NumberLessThanOrEqual();
808 } else if (r.GetCompareNumberOperationHint(&hint)) {
809 less_than = simplified()->SpeculativeNumberLessThan(hint);
810 less_than_or_equal = simplified()->SpeculativeNumberLessThanOrEqual(hint);
811 } else if (r.OneInputCannotBe(Type::StringOrReceiver()) &&
812 (r.BothInputsAre(Type::PlainPrimitive()) ||
813 !(flags() & kDeoptimizationEnabled))) {
814 r.ConvertInputsToNumber();
815 less_than = simplified()->NumberLessThan();
816 less_than_or_equal = simplified()->NumberLessThanOrEqual();
817 } else if (r.IsStringCompareOperation()) {
818 r.CheckInputsToString();
819 less_than = simplified()->StringLessThan();
820 less_than_or_equal = simplified()->StringLessThanOrEqual();
821 } else {
822 return NoChange();
823 }
824 const Operator* comparison;
825 switch (node->opcode()) {
826 case IrOpcode::kJSLessThan:
827 comparison = less_than;
828 break;
829 case IrOpcode::kJSGreaterThan:
830 comparison = less_than;
831 r.SwapInputs(); // a > b => b < a
832 break;
833 case IrOpcode::kJSLessThanOrEqual:
834 comparison = less_than_or_equal;
835 break;
836 case IrOpcode::kJSGreaterThanOrEqual:
837 comparison = less_than_or_equal;
838 r.SwapInputs(); // a >= b => b <= a
839 break;
840 default:
841 return NoChange();
842 }
843 if (comparison->EffectInputCount() > 0) {
844 return r.ChangeToSpeculativeOperator(comparison, Type::Boolean());
845 } else {
846 return r.ChangeToPureOperator(comparison);
847 }
848 }
849
ReduceJSTypeOf(Node * node)850 Reduction JSTypedLowering::ReduceJSTypeOf(Node* node) {
851 Node* const input = node->InputAt(0);
852 Type* type = NodeProperties::GetType(input);
853 Factory* const f = factory();
854 if (type->Is(Type::Boolean())) {
855 return Replace(jsgraph()->Constant(f->boolean_string()));
856 } else if (type->Is(Type::Number())) {
857 return Replace(jsgraph()->Constant(f->number_string()));
858 } else if (type->Is(Type::String())) {
859 return Replace(jsgraph()->Constant(f->string_string()));
860 } else if (type->Is(Type::Symbol())) {
861 return Replace(jsgraph()->Constant(f->symbol_string()));
862 } else if (type->Is(Type::OtherUndetectableOrUndefined())) {
863 return Replace(jsgraph()->Constant(f->undefined_string()));
864 } else if (type->Is(Type::NonCallableOrNull())) {
865 return Replace(jsgraph()->Constant(f->object_string()));
866 } else if (type->Is(Type::Function())) {
867 return Replace(jsgraph()->Constant(f->function_string()));
868 } else if (type->IsHeapConstant()) {
869 return Replace(jsgraph()->Constant(
870 Object::TypeOf(isolate(), type->AsHeapConstant()->Value())));
871 }
872
873 return NoChange();
874 }
875
ReduceJSEqualTypeOf(Node * node,bool invert)876 Reduction JSTypedLowering::ReduceJSEqualTypeOf(Node* node, bool invert) {
877 Node* input;
878 Handle<String> type;
879 HeapObjectBinopMatcher m(node);
880 if (m.left().IsJSTypeOf() && m.right().HasValue() &&
881 m.right().Value()->IsString()) {
882 input = m.left().InputAt(0);
883 type = Handle<String>::cast(m.right().Value());
884 } else if (m.right().IsJSTypeOf() && m.left().HasValue() &&
885 m.left().Value()->IsString()) {
886 input = m.right().InputAt(0);
887 type = Handle<String>::cast(m.left().Value());
888 } else {
889 return NoChange();
890 }
891 Node* value;
892 if (String::Equals(type, factory()->boolean_string())) {
893 value =
894 graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
895 graph()->NewNode(simplified()->ReferenceEqual(), input,
896 jsgraph()->TrueConstant()),
897 jsgraph()->TrueConstant(),
898 graph()->NewNode(simplified()->ReferenceEqual(), input,
899 jsgraph()->FalseConstant()));
900 } else if (String::Equals(type, factory()->function_string())) {
901 value = graph()->NewNode(simplified()->ObjectIsDetectableCallable(), input);
902 } else if (String::Equals(type, factory()->number_string())) {
903 value = graph()->NewNode(simplified()->ObjectIsNumber(), input);
904 } else if (String::Equals(type, factory()->object_string())) {
905 value = graph()->NewNode(
906 common()->Select(MachineRepresentation::kTagged),
907 graph()->NewNode(simplified()->ObjectIsNonCallable(), input),
908 jsgraph()->TrueConstant(),
909 graph()->NewNode(simplified()->ReferenceEqual(), input,
910 jsgraph()->NullConstant()));
911 } else if (String::Equals(type, factory()->string_string())) {
912 value = graph()->NewNode(simplified()->ObjectIsString(), input);
913 } else if (String::Equals(type, factory()->undefined_string())) {
914 value = graph()->NewNode(
915 common()->Select(MachineRepresentation::kTagged),
916 graph()->NewNode(simplified()->ReferenceEqual(), input,
917 jsgraph()->NullConstant()),
918 jsgraph()->FalseConstant(),
919 graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
920 } else {
921 return NoChange();
922 }
923 if (invert) {
924 value = graph()->NewNode(simplified()->BooleanNot(), value);
925 }
926 ReplaceWithValue(node, value);
927 return Replace(value);
928 }
929
ReduceJSEqual(Node * node,bool invert)930 Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
931 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
932 if (reduction.Changed()) return reduction;
933
934 JSBinopReduction r(this, node);
935
936 if (r.BothInputsAre(Type::UniqueName())) {
937 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
938 }
939 if (r.IsInternalizedStringCompareOperation()) {
940 r.CheckInputsToInternalizedString();
941 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
942 }
943 if (r.BothInputsAre(Type::String())) {
944 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
945 }
946 if (r.BothInputsAre(Type::Boolean())) {
947 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
948 }
949 if (r.BothInputsAre(Type::Receiver())) {
950 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
951 }
952 if (r.OneInputIs(Type::Undetectable())) {
953 RelaxEffectsAndControls(node);
954 node->RemoveInput(r.LeftInputIs(Type::Undetectable()) ? 0 : 1);
955 node->TrimInputCount(1);
956 NodeProperties::ChangeOp(node, simplified()->ObjectIsUndetectable());
957 if (invert) {
958 // Insert an boolean not to invert the value.
959 Node* value = graph()->NewNode(simplified()->BooleanNot(), node);
960 node->ReplaceUses(value);
961 // Note: ReplaceUses() smashes all uses, so smash it back here.
962 value->ReplaceInput(0, node);
963 return Replace(value);
964 }
965 return Changed(node);
966 }
967
968 NumberOperationHint hint;
969 if (r.BothInputsAre(Type::Signed32()) ||
970 r.BothInputsAre(Type::Unsigned32())) {
971 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
972 } else if (r.GetCompareNumberOperationHint(&hint)) {
973 return r.ChangeToSpeculativeOperator(
974 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean());
975 } else if (r.BothInputsAre(Type::Number())) {
976 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
977 } else if (r.IsReceiverCompareOperation()) {
978 r.CheckInputsToReceiver();
979 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
980 } else if (r.IsStringCompareOperation()) {
981 r.CheckInputsToString();
982 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
983 }
984 return NoChange();
985 }
986
ReduceJSStrictEqual(Node * node,bool invert)987 Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
988 JSBinopReduction r(this, node);
989 if (r.left() == r.right()) {
990 // x === x is always true if x != NaN
991 if (!r.left_type()->Maybe(Type::NaN())) {
992 Node* replacement = jsgraph()->BooleanConstant(!invert);
993 ReplaceWithValue(node, replacement);
994 return Replace(replacement);
995 }
996 }
997 if (r.OneInputCannotBe(Type::NumberOrString())) {
998 // For values with canonical representation (i.e. neither String, nor
999 // Number) an empty type intersection means the values cannot be strictly
1000 // equal.
1001 if (!r.left_type()->Maybe(r.right_type())) {
1002 Node* replacement = jsgraph()->BooleanConstant(invert);
1003 ReplaceWithValue(node, replacement);
1004 return Replace(replacement);
1005 }
1006 }
1007
1008 Reduction const reduction = ReduceJSEqualTypeOf(node, invert);
1009 if (reduction.Changed()) return reduction;
1010
1011 if (r.BothInputsAre(Type::Unique())) {
1012 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1013 }
1014 if (r.OneInputIs(pointer_comparable_type_)) {
1015 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1016 }
1017 if (r.IsInternalizedStringCompareOperation()) {
1018 r.CheckInputsToInternalizedString();
1019 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1020 }
1021 if (r.BothInputsAre(Type::String())) {
1022 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
1023 }
1024
1025 NumberOperationHint hint;
1026 if (r.BothInputsAre(Type::Signed32()) ||
1027 r.BothInputsAre(Type::Unsigned32())) {
1028 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
1029 } else if (r.GetCompareNumberOperationHint(&hint)) {
1030 return r.ChangeToSpeculativeOperator(
1031 simplified()->SpeculativeNumberEqual(hint), invert, Type::Boolean());
1032 } else if (r.BothInputsAre(Type::Number())) {
1033 return r.ChangeToPureOperator(simplified()->NumberEqual(), invert);
1034 } else if (r.IsReceiverCompareOperation()) {
1035 // For strict equality, it's enough to know that one input is a Receiver,
1036 // as a strict equality comparison with a Receiver can only yield true if
1037 // both sides refer to the same Receiver than.
1038 r.CheckLeftInputToReceiver();
1039 return r.ChangeToPureOperator(simplified()->ReferenceEqual(), invert);
1040 } else if (r.IsStringCompareOperation()) {
1041 r.CheckInputsToString();
1042 return r.ChangeToPureOperator(simplified()->StringEqual(), invert);
1043 }
1044 return NoChange();
1045 }
1046
ReduceJSToBoolean(Node * node)1047 Reduction JSTypedLowering::ReduceJSToBoolean(Node* node) {
1048 Node* const input = node->InputAt(0);
1049 Type* const input_type = NodeProperties::GetType(input);
1050 if (input_type->Is(Type::Boolean())) {
1051 // JSToBoolean(x:boolean) => x
1052 return Replace(input);
1053 } else if (input_type->Is(Type::OrderedNumber())) {
1054 // JSToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x,#0))
1055 node->ReplaceInput(0, graph()->NewNode(simplified()->NumberEqual(), input,
1056 jsgraph()->ZeroConstant()));
1057 node->TrimInputCount(1);
1058 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1059 return Changed(node);
1060 } else if (input_type->Is(Type::Number())) {
1061 // JSToBoolean(x:number) => NumberToBoolean(x)
1062 node->TrimInputCount(1);
1063 NodeProperties::ChangeOp(node, simplified()->NumberToBoolean());
1064 return Changed(node);
1065 } else if (input_type->Is(Type::DetectableReceiverOrNull())) {
1066 // JSToBoolean(x:detectable receiver \/ null)
1067 // => BooleanNot(ReferenceEqual(x,#null))
1068 node->ReplaceInput(0, graph()->NewNode(simplified()->ReferenceEqual(),
1069 input, jsgraph()->NullConstant()));
1070 node->TrimInputCount(1);
1071 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1072 return Changed(node);
1073 } else if (input_type->Is(Type::ReceiverOrNullOrUndefined())) {
1074 // JSToBoolean(x:receiver \/ null \/ undefined)
1075 // => BooleanNot(ObjectIsUndetectable(x))
1076 node->ReplaceInput(
1077 0, graph()->NewNode(simplified()->ObjectIsUndetectable(), input));
1078 node->TrimInputCount(1);
1079 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1080 return Changed(node);
1081 } else if (input_type->Is(Type::String())) {
1082 // JSToBoolean(x:string) => BooleanNot(ReferenceEqual(x,""))
1083 node->ReplaceInput(0,
1084 graph()->NewNode(simplified()->ReferenceEqual(), input,
1085 jsgraph()->EmptyStringConstant()));
1086 node->TrimInputCount(1);
1087 NodeProperties::ChangeOp(node, simplified()->BooleanNot());
1088 return Changed(node);
1089 }
1090 return NoChange();
1091 }
1092
ReduceJSToInteger(Node * node)1093 Reduction JSTypedLowering::ReduceJSToInteger(Node* node) {
1094 Node* const input = NodeProperties::GetValueInput(node, 0);
1095 Type* const input_type = NodeProperties::GetType(input);
1096 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
1097 // JSToInteger(x:integer) => x
1098 ReplaceWithValue(node, input);
1099 return Replace(input);
1100 }
1101 return NoChange();
1102 }
1103
ReduceJSToName(Node * node)1104 Reduction JSTypedLowering::ReduceJSToName(Node* node) {
1105 Node* const input = NodeProperties::GetValueInput(node, 0);
1106 Type* const input_type = NodeProperties::GetType(input);
1107 if (input_type->Is(Type::Name())) {
1108 // JSToName(x:name) => x
1109 ReplaceWithValue(node, input);
1110 return Replace(input);
1111 }
1112 return NoChange();
1113 }
1114
ReduceJSToLength(Node * node)1115 Reduction JSTypedLowering::ReduceJSToLength(Node* node) {
1116 Node* input = NodeProperties::GetValueInput(node, 0);
1117 Type* input_type = NodeProperties::GetType(input);
1118 if (input_type->Is(type_cache_.kIntegerOrMinusZero)) {
1119 if (input_type->Max() <= 0.0) {
1120 input = jsgraph()->ZeroConstant();
1121 } else if (input_type->Min() >= kMaxSafeInteger) {
1122 input = jsgraph()->Constant(kMaxSafeInteger);
1123 } else {
1124 if (input_type->Min() <= 0.0) {
1125 input = graph()->NewNode(simplified()->NumberMax(),
1126 jsgraph()->ZeroConstant(), input);
1127 }
1128 if (input_type->Max() > kMaxSafeInteger) {
1129 input = graph()->NewNode(simplified()->NumberMin(),
1130 jsgraph()->Constant(kMaxSafeInteger), input);
1131 }
1132 }
1133 ReplaceWithValue(node, input);
1134 return Replace(input);
1135 }
1136 return NoChange();
1137 }
1138
ReduceJSToNumberInput(Node * input)1139 Reduction JSTypedLowering::ReduceJSToNumberInput(Node* input) {
1140 // Try constant-folding of JSToNumber with constant inputs.
1141 Type* input_type = NodeProperties::GetType(input);
1142 if (input_type->Is(Type::String())) {
1143 HeapObjectMatcher m(input);
1144 if (m.HasValue() && m.Value()->IsString()) {
1145 Handle<Object> input_value = m.Value();
1146 return Replace(jsgraph()->Constant(
1147 String::ToNumber(Handle<String>::cast(input_value))));
1148 }
1149 }
1150 if (input_type->IsHeapConstant()) {
1151 Handle<Object> input_value = input_type->AsHeapConstant()->Value();
1152 if (input_value->IsOddball()) {
1153 return Replace(jsgraph()->Constant(
1154 Oddball::ToNumber(Handle<Oddball>::cast(input_value))));
1155 }
1156 }
1157 if (input_type->Is(Type::Number())) {
1158 // JSToNumber(x:number) => x
1159 return Changed(input);
1160 }
1161 if (input_type->Is(Type::Undefined())) {
1162 // JSToNumber(undefined) => #NaN
1163 return Replace(jsgraph()->NaNConstant());
1164 }
1165 if (input_type->Is(Type::Null())) {
1166 // JSToNumber(null) => #0
1167 return Replace(jsgraph()->ZeroConstant());
1168 }
1169 return NoChange();
1170 }
1171
ReduceJSToNumber(Node * node)1172 Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
1173 // Try to reduce the input first.
1174 Node* const input = node->InputAt(0);
1175 Reduction reduction = ReduceJSToNumberInput(input);
1176 if (reduction.Changed()) {
1177 ReplaceWithValue(node, reduction.replacement());
1178 return reduction;
1179 }
1180 Type* const input_type = NodeProperties::GetType(input);
1181 if (input_type->Is(Type::PlainPrimitive())) {
1182 RelaxEffectsAndControls(node);
1183 node->TrimInputCount(1);
1184 NodeProperties::ChangeOp(node, simplified()->PlainPrimitiveToNumber());
1185 return Changed(node);
1186 }
1187 return NoChange();
1188 }
1189
ReduceJSToStringInput(Node * input)1190 Reduction JSTypedLowering::ReduceJSToStringInput(Node* input) {
1191 if (input->opcode() == IrOpcode::kJSToString) {
1192 // Recursively try to reduce the input first.
1193 Reduction result = ReduceJSToString(input);
1194 if (result.Changed()) return result;
1195 return Changed(input); // JSToString(JSToString(x)) => JSToString(x)
1196 }
1197 Type* input_type = NodeProperties::GetType(input);
1198 if (input_type->Is(Type::String())) {
1199 return Changed(input); // JSToString(x:string) => x
1200 }
1201 if (input_type->Is(Type::Boolean())) {
1202 return Replace(graph()->NewNode(
1203 common()->Select(MachineRepresentation::kTagged), input,
1204 jsgraph()->HeapConstant(factory()->true_string()),
1205 jsgraph()->HeapConstant(factory()->false_string())));
1206 }
1207 if (input_type->Is(Type::Undefined())) {
1208 return Replace(jsgraph()->HeapConstant(factory()->undefined_string()));
1209 }
1210 if (input_type->Is(Type::Null())) {
1211 return Replace(jsgraph()->HeapConstant(factory()->null_string()));
1212 }
1213 // TODO(turbofan): js-typed-lowering of ToString(x:number)
1214 return NoChange();
1215 }
1216
ReduceJSToString(Node * node)1217 Reduction JSTypedLowering::ReduceJSToString(Node* node) {
1218 // Try to reduce the input first.
1219 Node* const input = node->InputAt(0);
1220 Reduction reduction = ReduceJSToStringInput(input);
1221 if (reduction.Changed()) {
1222 ReplaceWithValue(node, reduction.replacement());
1223 return reduction;
1224 }
1225 return NoChange();
1226 }
1227
ReduceJSToObject(Node * node)1228 Reduction JSTypedLowering::ReduceJSToObject(Node* node) {
1229 DCHECK_EQ(IrOpcode::kJSToObject, node->opcode());
1230 Node* receiver = NodeProperties::GetValueInput(node, 0);
1231 Type* receiver_type = NodeProperties::GetType(receiver);
1232 Node* context = NodeProperties::GetContextInput(node);
1233 Node* frame_state = NodeProperties::GetFrameStateInput(node);
1234 Node* effect = NodeProperties::GetEffectInput(node);
1235 Node* control = NodeProperties::GetControlInput(node);
1236 if (receiver_type->Is(Type::Receiver())) {
1237 ReplaceWithValue(node, receiver, effect, control);
1238 return Replace(receiver);
1239 }
1240
1241 // TODO(bmeurer/mstarzinger): Add support for lowering inside try blocks.
1242 if (receiver_type->Maybe(Type::NullOrUndefined()) &&
1243 NodeProperties::IsExceptionalCall(node)) {
1244 // ToObject throws for null or undefined inputs.
1245 return NoChange();
1246 }
1247
1248 // Check whether {receiver} is a spec object.
1249 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1250 Node* branch =
1251 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1252
1253 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1254 Node* etrue = effect;
1255 Node* rtrue = receiver;
1256
1257 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1258 Node* efalse = effect;
1259 Node* rfalse;
1260 {
1261 // Convert {receiver} using the ToObjectStub.
1262 Callable callable = CodeFactory::ToObject(isolate());
1263 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1264 isolate(), graph()->zone(), callable.descriptor(), 0,
1265 CallDescriptor::kNeedsFrameState, node->op()->properties());
1266 rfalse = efalse = graph()->NewNode(
1267 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1268 receiver, context, frame_state, efalse, if_false);
1269 if_false = graph()->NewNode(common()->IfSuccess(), rfalse);
1270 }
1271
1272 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1273 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1274
1275 // Morph the {node} into an appropriate Phi.
1276 ReplaceWithValue(node, node, effect, control);
1277 node->ReplaceInput(0, rtrue);
1278 node->ReplaceInput(1, rfalse);
1279 node->ReplaceInput(2, control);
1280 node->TrimInputCount(3);
1281 NodeProperties::ChangeOp(node,
1282 common()->Phi(MachineRepresentation::kTagged, 2));
1283 return Changed(node);
1284 }
1285
ReduceJSLoadNamed(Node * node)1286 Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
1287 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
1288 Node* receiver = NodeProperties::GetValueInput(node, 0);
1289 Type* receiver_type = NodeProperties::GetType(receiver);
1290 Node* effect = NodeProperties::GetEffectInput(node);
1291 Node* control = NodeProperties::GetControlInput(node);
1292 Handle<Name> name = NamedAccessOf(node->op()).name();
1293 // Optimize "length" property of strings.
1294 if (name.is_identical_to(factory()->length_string()) &&
1295 receiver_type->Is(Type::String())) {
1296 Node* value = effect = graph()->NewNode(
1297 simplified()->LoadField(AccessBuilder::ForStringLength()), receiver,
1298 effect, control);
1299 ReplaceWithValue(node, value, effect);
1300 return Replace(value);
1301 }
1302 return NoChange();
1303 }
1304
ReduceJSLoadProperty(Node * node)1305 Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
1306 Node* key = NodeProperties::GetValueInput(node, 1);
1307 Node* base = NodeProperties::GetValueInput(node, 0);
1308 Type* key_type = NodeProperties::GetType(key);
1309 HeapObjectMatcher mbase(base);
1310 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1311 Handle<JSTypedArray> const array =
1312 Handle<JSTypedArray>::cast(mbase.Value());
1313 if (!array->GetBuffer()->was_neutered()) {
1314 array->GetBuffer()->set_is_neuterable(false);
1315 BufferAccess const access(array->type());
1316 size_t const k =
1317 ElementSizeLog2Of(access.machine_type().representation());
1318 double const byte_length = array->byte_length()->Number();
1319 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1320 if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1321 // JSLoadProperty(typed-array, int32)
1322 Handle<FixedTypedArrayBase> elements =
1323 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1324 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1325 Node* length = jsgraph()->Constant(byte_length);
1326 Node* effect = NodeProperties::GetEffectInput(node);
1327 Node* control = NodeProperties::GetControlInput(node);
1328 // Check if we can avoid the bounds check.
1329 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1330 Node* load = graph()->NewNode(
1331 simplified()->LoadElement(
1332 AccessBuilder::ForTypedArrayElement(array->type(), true)),
1333 buffer, key, effect, control);
1334 ReplaceWithValue(node, load, load);
1335 return Replace(load);
1336 }
1337 // Compute byte offset.
1338 Node* offset =
1339 (k == 0) ? key : graph()->NewNode(
1340 simplified()->NumberShiftLeft(), key,
1341 jsgraph()->Constant(static_cast<double>(k)));
1342 Node* load = graph()->NewNode(simplified()->LoadBuffer(access), buffer,
1343 offset, length, effect, control);
1344 ReplaceWithValue(node, load, load);
1345 return Replace(load);
1346 }
1347 }
1348 }
1349 return NoChange();
1350 }
1351
ReduceJSStoreProperty(Node * node)1352 Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
1353 Node* key = NodeProperties::GetValueInput(node, 1);
1354 Node* base = NodeProperties::GetValueInput(node, 0);
1355 Node* value = NodeProperties::GetValueInput(node, 2);
1356 Type* key_type = NodeProperties::GetType(key);
1357 Type* value_type = NodeProperties::GetType(value);
1358
1359 if (!value_type->Is(Type::PlainPrimitive())) return NoChange();
1360
1361 HeapObjectMatcher mbase(base);
1362 if (mbase.HasValue() && mbase.Value()->IsJSTypedArray()) {
1363 Handle<JSTypedArray> const array =
1364 Handle<JSTypedArray>::cast(mbase.Value());
1365 if (!array->GetBuffer()->was_neutered()) {
1366 array->GetBuffer()->set_is_neuterable(false);
1367 BufferAccess const access(array->type());
1368 size_t const k =
1369 ElementSizeLog2Of(access.machine_type().representation());
1370 double const byte_length = array->byte_length()->Number();
1371 CHECK_LT(k, arraysize(shifted_int32_ranges_));
1372 if (access.external_array_type() != kExternalUint8ClampedArray &&
1373 key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) {
1374 // JSLoadProperty(typed-array, int32)
1375 Handle<FixedTypedArrayBase> elements =
1376 Handle<FixedTypedArrayBase>::cast(handle(array->elements()));
1377 Node* buffer = jsgraph()->PointerConstant(elements->external_pointer());
1378 Node* length = jsgraph()->Constant(byte_length);
1379 Node* effect = NodeProperties::GetEffectInput(node);
1380 Node* control = NodeProperties::GetControlInput(node);
1381 // Convert to a number first.
1382 if (!value_type->Is(Type::Number())) {
1383 Reduction number_reduction = ReduceJSToNumberInput(value);
1384 if (number_reduction.Changed()) {
1385 value = number_reduction.replacement();
1386 } else {
1387 value =
1388 graph()->NewNode(simplified()->PlainPrimitiveToNumber(), value);
1389 }
1390 }
1391 // Check if we can avoid the bounds check.
1392 if (key_type->Min() >= 0 && key_type->Max() < array->length_value()) {
1393 RelaxControls(node);
1394 node->ReplaceInput(0, buffer);
1395 DCHECK_EQ(key, node->InputAt(1));
1396 node->ReplaceInput(2, value);
1397 node->ReplaceInput(3, effect);
1398 node->ReplaceInput(4, control);
1399 node->TrimInputCount(5);
1400 NodeProperties::ChangeOp(
1401 node,
1402 simplified()->StoreElement(
1403 AccessBuilder::ForTypedArrayElement(array->type(), true)));
1404 return Changed(node);
1405 }
1406 // Compute byte offset.
1407 Node* offset =
1408 (k == 0) ? key : graph()->NewNode(
1409 simplified()->NumberShiftLeft(), key,
1410 jsgraph()->Constant(static_cast<double>(k)));
1411 // Turn into a StoreBuffer operation.
1412 RelaxControls(node);
1413 node->ReplaceInput(0, buffer);
1414 node->ReplaceInput(1, offset);
1415 node->ReplaceInput(2, length);
1416 node->ReplaceInput(3, value);
1417 node->ReplaceInput(4, effect);
1418 node->ReplaceInput(5, control);
1419 node->TrimInputCount(6);
1420 NodeProperties::ChangeOp(node, simplified()->StoreBuffer(access));
1421 return Changed(node);
1422 }
1423 }
1424 }
1425 return NoChange();
1426 }
1427
ReduceJSOrdinaryHasInstance(Node * node)1428 Reduction JSTypedLowering::ReduceJSOrdinaryHasInstance(Node* node) {
1429 DCHECK_EQ(IrOpcode::kJSOrdinaryHasInstance, node->opcode());
1430 Node* constructor = NodeProperties::GetValueInput(node, 0);
1431 Type* constructor_type = NodeProperties::GetType(constructor);
1432 Node* object = NodeProperties::GetValueInput(node, 1);
1433 Type* object_type = NodeProperties::GetType(object);
1434 Node* context = NodeProperties::GetContextInput(node);
1435 Node* frame_state = NodeProperties::GetFrameStateInput(node);
1436 Node* effect = NodeProperties::GetEffectInput(node);
1437 Node* control = NodeProperties::GetControlInput(node);
1438
1439 // Check if the {constructor} cannot be callable.
1440 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 1.
1441 if (!constructor_type->Maybe(Type::Callable())) {
1442 Node* value = jsgraph()->FalseConstant();
1443 ReplaceWithValue(node, value, effect, control);
1444 return Replace(value);
1445 }
1446
1447 // If the {constructor} cannot be a JSBoundFunction and then {object}
1448 // cannot be a JSReceiver, then this can be constant-folded to false.
1449 // See ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) step 2 and 3.
1450 if (!object_type->Maybe(Type::Receiver()) &&
1451 !constructor_type->Maybe(Type::BoundFunction())) {
1452 Node* value = jsgraph()->FalseConstant();
1453 ReplaceWithValue(node, value, effect, control);
1454 return Replace(value);
1455 }
1456
1457 // Check if the {constructor} is a (known) JSFunction.
1458 if (!constructor_type->IsHeapConstant() ||
1459 !constructor_type->AsHeapConstant()->Value()->IsJSFunction()) {
1460 return NoChange();
1461 }
1462 Handle<JSFunction> function =
1463 Handle<JSFunction>::cast(constructor_type->AsHeapConstant()->Value());
1464
1465 // Check if the {function} already has an initial map (i.e. the
1466 // {function} has been used as a constructor at least once).
1467 if (!function->has_initial_map()) return NoChange();
1468
1469 // Check if the {function}s "prototype" is a JSReceiver.
1470 if (!function->prototype()->IsJSReceiver()) return NoChange();
1471
1472 // Install a code dependency on the {function}s initial map.
1473 Handle<Map> initial_map(function->initial_map(), isolate());
1474 dependencies()->AssumeInitialMapCantChange(initial_map);
1475
1476 Node* prototype =
1477 jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
1478
1479 Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), object);
1480 Node* branch0 =
1481 graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
1482
1483 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1484 Node* etrue0 = effect;
1485 Node* vtrue0 = jsgraph()->FalseConstant();
1486
1487 control = graph()->NewNode(common()->IfFalse(), branch0);
1488
1489 // Loop through the {object}s prototype chain looking for the {prototype}.
1490 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control);
1491 Node* eloop = effect =
1492 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop);
1493 Node* vloop = object = graph()->NewNode(
1494 common()->Phi(MachineRepresentation::kTagged, 2), object, object, loop);
1495 // TODO(jarin): This is a very ugly hack to work-around the super-smart
1496 // implicit typing of the Phi, which goes completely nuts if the {object}
1497 // is for example a HeapConstant.
1498 NodeProperties::SetType(vloop, Type::NonInternal());
1499
1500 // Load the {object} map and instance type.
1501 Node* object_map = effect =
1502 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object,
1503 effect, control);
1504 Node* object_instance_type = effect = graph()->NewNode(
1505 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), object_map,
1506 effect, control);
1507
1508 // Check if the {object} is a special receiver, because for special
1509 // receivers, i.e. proxies or API objects that need access checks,
1510 // we have to use the %HasInPrototypeChain runtime function instead.
1511 Node* check1 = graph()->NewNode(
1512 simplified()->NumberLessThanOrEqual(), object_instance_type,
1513 jsgraph()->Constant(LAST_SPECIAL_RECEIVER_TYPE));
1514 Node* branch1 =
1515 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);
1516
1517 control = graph()->NewNode(common()->IfFalse(), branch1);
1518
1519 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1520 Node* etrue1 = effect;
1521 Node* vtrue1;
1522
1523 // Check if the {object} is not a receiver at all.
1524 Node* check10 =
1525 graph()->NewNode(simplified()->NumberLessThan(), object_instance_type,
1526 jsgraph()->Constant(FIRST_JS_RECEIVER_TYPE));
1527 Node* branch10 =
1528 graph()->NewNode(common()->Branch(BranchHint::kTrue), check10, if_true1);
1529
1530 // A primitive value cannot match the {prototype} we're looking for.
1531 if_true1 = graph()->NewNode(common()->IfTrue(), branch10);
1532 vtrue1 = jsgraph()->FalseConstant();
1533
1534 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch10);
1535 Node* efalse1 = etrue1;
1536 Node* vfalse1;
1537 {
1538 // Slow path, need to call the %HasInPrototypeChain runtime function.
1539 vfalse1 = efalse1 = graph()->NewNode(
1540 javascript()->CallRuntime(Runtime::kHasInPrototypeChain), object,
1541 prototype, context, frame_state, efalse1, if_false1);
1542 if_false1 = graph()->NewNode(common()->IfSuccess(), vfalse1);
1543
1544 // Replace any potential IfException on {node} to catch exceptions
1545 // from this %HasInPrototypeChain runtime call instead.
1546 for (Edge edge : node->use_edges()) {
1547 if (edge.from()->opcode() == IrOpcode::kIfException) {
1548 edge.UpdateTo(vfalse1);
1549 Revisit(edge.from());
1550 }
1551 }
1552 }
1553
1554 // Load the {object} prototype.
1555 Node* object_prototype = effect = graph()->NewNode(
1556 simplified()->LoadField(AccessBuilder::ForMapPrototype()), object_map,
1557 effect, control);
1558
1559 // Check if we reached the end of {object}s prototype chain.
1560 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(),
1561 object_prototype, jsgraph()->NullConstant());
1562 Node* branch2 = graph()->NewNode(common()->Branch(), check2, control);
1563
1564 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1565 Node* etrue2 = effect;
1566 Node* vtrue2 = jsgraph()->FalseConstant();
1567
1568 control = graph()->NewNode(common()->IfFalse(), branch2);
1569
1570 // Check if we reached the {prototype}.
1571 Node* check3 = graph()->NewNode(simplified()->ReferenceEqual(),
1572 object_prototype, prototype);
1573 Node* branch3 = graph()->NewNode(common()->Branch(), check3, control);
1574
1575 Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
1576 Node* etrue3 = effect;
1577 Node* vtrue3 = jsgraph()->TrueConstant();
1578
1579 control = graph()->NewNode(common()->IfFalse(), branch3);
1580
1581 // Close the loop.
1582 vloop->ReplaceInput(1, object_prototype);
1583 eloop->ReplaceInput(1, effect);
1584 loop->ReplaceInput(1, control);
1585
1586 control = graph()->NewNode(common()->Merge(5), if_true0, if_true1, if_true2,
1587 if_true3, if_false1);
1588 effect = graph()->NewNode(common()->EffectPhi(5), etrue0, etrue1, etrue2,
1589 etrue3, efalse1, control);
1590
1591 // Morph the {node} into an appropriate Phi.
1592 ReplaceWithValue(node, node, effect, control);
1593 node->ReplaceInput(0, vtrue0);
1594 node->ReplaceInput(1, vtrue1);
1595 node->ReplaceInput(2, vtrue2);
1596 node->ReplaceInput(3, vtrue3);
1597 node->ReplaceInput(4, vfalse1);
1598 node->ReplaceInput(5, control);
1599 node->TrimInputCount(6);
1600 NodeProperties::ChangeOp(node,
1601 common()->Phi(MachineRepresentation::kTagged, 5));
1602 return Changed(node);
1603 }
1604
ReduceJSLoadContext(Node * node)1605 Reduction JSTypedLowering::ReduceJSLoadContext(Node* node) {
1606 DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
1607 ContextAccess const& access = ContextAccessOf(node->op());
1608 Node* effect = NodeProperties::GetEffectInput(node);
1609 Node* context = NodeProperties::GetContextInput(node);
1610 Node* control = graph()->start();
1611 for (size_t i = 0; i < access.depth(); ++i) {
1612 context = effect = graph()->NewNode(
1613 simplified()->LoadField(
1614 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1615 context, effect, control);
1616 }
1617 node->ReplaceInput(0, context);
1618 node->ReplaceInput(1, effect);
1619 node->AppendInput(jsgraph()->zone(), control);
1620 NodeProperties::ChangeOp(
1621 node,
1622 simplified()->LoadField(AccessBuilder::ForContextSlot(access.index())));
1623 return Changed(node);
1624 }
1625
ReduceJSStoreContext(Node * node)1626 Reduction JSTypedLowering::ReduceJSStoreContext(Node* node) {
1627 DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
1628 ContextAccess const& access = ContextAccessOf(node->op());
1629 Node* effect = NodeProperties::GetEffectInput(node);
1630 Node* context = NodeProperties::GetContextInput(node);
1631 Node* control = graph()->start();
1632 Node* value = NodeProperties::GetValueInput(node, 0);
1633 for (size_t i = 0; i < access.depth(); ++i) {
1634 context = effect = graph()->NewNode(
1635 simplified()->LoadField(
1636 AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX)),
1637 context, effect, control);
1638 }
1639 node->ReplaceInput(0, context);
1640 node->ReplaceInput(1, value);
1641 node->ReplaceInput(2, effect);
1642 NodeProperties::ChangeOp(
1643 node,
1644 simplified()->StoreField(AccessBuilder::ForContextSlot(access.index())));
1645 return Changed(node);
1646 }
1647
ReduceJSLoadModule(Node * node)1648 Reduction JSTypedLowering::ReduceJSLoadModule(Node* node) {
1649 DCHECK_EQ(IrOpcode::kJSLoadModule, node->opcode());
1650 Node* effect = NodeProperties::GetEffectInput(node);
1651 Node* control = NodeProperties::GetControlInput(node);
1652
1653 int32_t cell_index = OpParameter<int32_t>(node);
1654 Node* module = NodeProperties::GetValueInput(node, 0);
1655
1656 Node* array;
1657 int index;
1658 if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1659 ModuleDescriptor::kExport) {
1660 array = effect = graph()->NewNode(
1661 simplified()->LoadField(AccessBuilder::ForModuleRegularExports()),
1662 module, effect, control);
1663 index = cell_index - 1;
1664 } else {
1665 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1666 ModuleDescriptor::kImport);
1667 array = effect = graph()->NewNode(
1668 simplified()->LoadField(AccessBuilder::ForModuleRegularImports()),
1669 module, effect, control);
1670 index = -cell_index - 1;
1671 }
1672
1673 Node* cell = effect = graph()->NewNode(
1674 simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1675 effect, control);
1676
1677 Node* value = effect =
1678 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForCellValue()),
1679 cell, effect, control);
1680
1681 ReplaceWithValue(node, value, effect, control);
1682 return Changed(value);
1683 }
1684
ReduceJSStoreModule(Node * node)1685 Reduction JSTypedLowering::ReduceJSStoreModule(Node* node) {
1686 DCHECK_EQ(IrOpcode::kJSStoreModule, node->opcode());
1687 Node* effect = NodeProperties::GetEffectInput(node);
1688 Node* control = NodeProperties::GetControlInput(node);
1689
1690 int32_t cell_index = OpParameter<int32_t>(node);
1691 Node* module = NodeProperties::GetValueInput(node, 0);
1692 Node* value = NodeProperties::GetValueInput(node, 1);
1693
1694 Node* array;
1695 int index;
1696 if (ModuleDescriptor::GetCellIndexKind(cell_index) ==
1697 ModuleDescriptor::kExport) {
1698 array = effect = graph()->NewNode(
1699 simplified()->LoadField(AccessBuilder::ForModuleRegularExports()),
1700 module, effect, control);
1701 index = cell_index - 1;
1702 } else {
1703 DCHECK_EQ(ModuleDescriptor::GetCellIndexKind(cell_index),
1704 ModuleDescriptor::kImport);
1705 array = effect = graph()->NewNode(
1706 simplified()->LoadField(AccessBuilder::ForModuleRegularImports()),
1707 module, effect, control);
1708 index = -cell_index - 1;
1709 }
1710
1711 Node* cell = effect = graph()->NewNode(
1712 simplified()->LoadField(AccessBuilder::ForFixedArraySlot(index)), array,
1713 effect, control);
1714
1715 effect =
1716 graph()->NewNode(simplified()->StoreField(AccessBuilder::ForCellValue()),
1717 cell, value, effect, control);
1718
1719 ReplaceWithValue(node, effect, effect, control);
1720 return Changed(value);
1721 }
1722
ReduceJSConvertReceiver(Node * node)1723 Reduction JSTypedLowering::ReduceJSConvertReceiver(Node* node) {
1724 DCHECK_EQ(IrOpcode::kJSConvertReceiver, node->opcode());
1725 ConvertReceiverMode mode = ConvertReceiverModeOf(node->op());
1726 Node* receiver = NodeProperties::GetValueInput(node, 0);
1727 Type* receiver_type = NodeProperties::GetType(receiver);
1728 Node* context = NodeProperties::GetContextInput(node);
1729 Type* context_type = NodeProperties::GetType(context);
1730 Node* effect = NodeProperties::GetEffectInput(node);
1731 Node* control = NodeProperties::GetControlInput(node);
1732
1733 // Check if {receiver} is known to be a receiver.
1734 if (receiver_type->Is(Type::Receiver())) {
1735 ReplaceWithValue(node, receiver, effect, control);
1736 return Replace(receiver);
1737 }
1738
1739 // If the {receiver} is known to be null or undefined, we can just replace it
1740 // with the global proxy unconditionally.
1741 if (receiver_type->Is(Type::NullOrUndefined()) ||
1742 mode == ConvertReceiverMode::kNullOrUndefined) {
1743 if (context_type->IsHeapConstant()) {
1744 Handle<JSObject> global_proxy(
1745 Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1746 ->global_proxy(),
1747 isolate());
1748 receiver = jsgraph()->Constant(global_proxy);
1749 } else {
1750 Node* native_context = effect = graph()->NewNode(
1751 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1752 context, effect);
1753 receiver = effect = graph()->NewNode(
1754 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1755 native_context, effect);
1756 }
1757 ReplaceWithValue(node, receiver, effect, control);
1758 return Replace(receiver);
1759 }
1760
1761 // If {receiver} cannot be null or undefined we can skip a few checks.
1762 if (!receiver_type->Maybe(Type::NullOrUndefined()) ||
1763 mode == ConvertReceiverMode::kNotNullOrUndefined) {
1764 Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1765 Node* branch =
1766 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
1767
1768 Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
1769 Node* etrue = effect;
1770 Node* rtrue = receiver;
1771
1772 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
1773 Node* efalse = effect;
1774 Node* rfalse;
1775 {
1776 // Convert {receiver} using the ToObjectStub. The call does not require a
1777 // frame-state in this case, because neither null nor undefined is passed.
1778 Callable callable = CodeFactory::ToObject(isolate());
1779 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1780 isolate(), graph()->zone(), callable.descriptor(), 0,
1781 CallDescriptor::kNoFlags, node->op()->properties());
1782 rfalse = efalse = graph()->NewNode(
1783 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1784 receiver, context, efalse);
1785 }
1786
1787 control = graph()->NewNode(common()->Merge(2), if_true, if_false);
1788 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
1789
1790 // Morph the {node} into an appropriate Phi.
1791 ReplaceWithValue(node, node, effect, control);
1792 node->ReplaceInput(0, rtrue);
1793 node->ReplaceInput(1, rfalse);
1794 node->ReplaceInput(2, control);
1795 node->TrimInputCount(3);
1796 NodeProperties::ChangeOp(node,
1797 common()->Phi(MachineRepresentation::kTagged, 2));
1798 return Changed(node);
1799 }
1800
1801 // Check if {receiver} is already a JSReceiver.
1802 Node* check0 = graph()->NewNode(simplified()->ObjectIsReceiver(), receiver);
1803 Node* branch0 =
1804 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
1805 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
1806 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
1807
1808 // Check {receiver} for undefined.
1809 Node* check1 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1810 jsgraph()->UndefinedConstant());
1811 Node* branch1 =
1812 graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_false0);
1813 Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
1814 Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
1815
1816 // Check {receiver} for null.
1817 Node* check2 = graph()->NewNode(simplified()->ReferenceEqual(), receiver,
1818 jsgraph()->NullConstant());
1819 Node* branch2 =
1820 graph()->NewNode(common()->Branch(BranchHint::kFalse), check2, if_false1);
1821 Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
1822 Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
1823
1824 // We just use {receiver} directly.
1825 Node* if_noop = if_true0;
1826 Node* enoop = effect;
1827 Node* rnoop = receiver;
1828
1829 // Convert {receiver} using ToObject.
1830 Node* if_convert = if_false2;
1831 Node* econvert = effect;
1832 Node* rconvert;
1833 {
1834 // Convert {receiver} using the ToObjectStub. The call does not require a
1835 // frame-state in this case, because neither null nor undefined is passed.
1836 Callable callable = CodeFactory::ToObject(isolate());
1837 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
1838 isolate(), graph()->zone(), callable.descriptor(), 0,
1839 CallDescriptor::kNoFlags, node->op()->properties());
1840 rconvert = econvert = graph()->NewNode(
1841 common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
1842 receiver, context, econvert);
1843 }
1844
1845 // Replace {receiver} with global proxy of {context}.
1846 Node* if_global = graph()->NewNode(common()->Merge(2), if_true1, if_true2);
1847 Node* eglobal = effect;
1848 Node* rglobal;
1849 {
1850 if (context_type->IsHeapConstant()) {
1851 Handle<JSObject> global_proxy(
1852 Handle<Context>::cast(context_type->AsHeapConstant()->Value())
1853 ->global_proxy(),
1854 isolate());
1855 rglobal = jsgraph()->Constant(global_proxy);
1856 } else {
1857 Node* native_context = eglobal = graph()->NewNode(
1858 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1859 context, eglobal);
1860 rglobal = eglobal = graph()->NewNode(
1861 javascript()->LoadContext(0, Context::GLOBAL_PROXY_INDEX, true),
1862 native_context, eglobal);
1863 }
1864 }
1865
1866 control =
1867 graph()->NewNode(common()->Merge(3), if_noop, if_convert, if_global);
1868 effect = graph()->NewNode(common()->EffectPhi(3), enoop, econvert, eglobal,
1869 control);
1870 // Morph the {node} into an appropriate Phi.
1871 ReplaceWithValue(node, node, effect, control);
1872 node->ReplaceInput(0, rnoop);
1873 node->ReplaceInput(1, rconvert);
1874 node->ReplaceInput(2, rglobal);
1875 node->ReplaceInput(3, control);
1876 node->TrimInputCount(4);
1877 NodeProperties::ChangeOp(node,
1878 common()->Phi(MachineRepresentation::kTagged, 3));
1879 return Changed(node);
1880 }
1881
1882 namespace {
1883
ReduceBuiltin(Isolate * isolate,JSGraph * jsgraph,Node * node,int builtin_index,int arity,CallDescriptor::Flags flags)1884 void ReduceBuiltin(Isolate* isolate, JSGraph* jsgraph, Node* node,
1885 int builtin_index, int arity, CallDescriptor::Flags flags) {
1886 // Patch {node} to a direct CEntryStub call.
1887 //
1888 // ----------- A r g u m e n t s -----------
1889 // -- 0: CEntryStub
1890 // --- Stack args ---
1891 // -- 1: receiver
1892 // -- [2, 2 + n[: the n actual arguments passed to the builtin
1893 // -- 2 + n: argc, including the receiver and implicit args (Smi)
1894 // -- 2 + n + 1: target
1895 // -- 2 + n + 2: new_target
1896 // --- Register args ---
1897 // -- 2 + n + 3: the C entry point
1898 // -- 2 + n + 4: argc (Int32)
1899 // -----------------------------------
1900
1901 // The logic contained here is mirrored in Builtins::Generate_Adaptor.
1902 // Keep these in sync.
1903
1904 const bool is_construct = (node->opcode() == IrOpcode::kJSConstruct);
1905
1906 DCHECK(Builtins::HasCppImplementation(builtin_index));
1907 DCHECK_EQ(0, flags & CallDescriptor::kSupportsTailCalls);
1908
1909 Node* target = NodeProperties::GetValueInput(node, 0);
1910 Node* new_target = is_construct
1911 ? NodeProperties::GetValueInput(node, arity + 1)
1912 : jsgraph->UndefinedConstant();
1913
1914 // API and CPP builtins are implemented in C++, and we can inline both.
1915 // CPP builtins create a builtin exit frame, API builtins don't.
1916 const bool has_builtin_exit_frame = Builtins::IsCpp(builtin_index);
1917
1918 Node* stub = jsgraph->CEntryStubConstant(1, kDontSaveFPRegs, kArgvOnStack,
1919 has_builtin_exit_frame);
1920 node->ReplaceInput(0, stub);
1921
1922 Zone* zone = jsgraph->zone();
1923 if (is_construct) {
1924 // Unify representations between construct and call nodes.
1925 // Remove new target and add receiver as a stack parameter.
1926 Node* receiver = jsgraph->UndefinedConstant();
1927 node->RemoveInput(arity + 1);
1928 node->InsertInput(zone, 1, receiver);
1929 }
1930
1931 const int argc = arity + BuiltinArguments::kNumExtraArgsWithReceiver;
1932 Node* argc_node = jsgraph->Constant(argc);
1933
1934 static const int kStubAndReceiver = 2;
1935 int cursor = arity + kStubAndReceiver;
1936 node->InsertInput(zone, cursor++, argc_node);
1937 node->InsertInput(zone, cursor++, target);
1938 node->InsertInput(zone, cursor++, new_target);
1939
1940 Address entry = Builtins::CppEntryOf(builtin_index);
1941 ExternalReference entry_ref(ExternalReference(entry, isolate));
1942 Node* entry_node = jsgraph->ExternalConstant(entry_ref);
1943
1944 node->InsertInput(zone, cursor++, entry_node);
1945 node->InsertInput(zone, cursor++, argc_node);
1946
1947 static const int kReturnCount = 1;
1948 const char* debug_name = Builtins::name(builtin_index);
1949 Operator::Properties properties = node->op()->properties();
1950 CallDescriptor* desc = Linkage::GetCEntryStubCallDescriptor(
1951 zone, kReturnCount, argc, debug_name, properties, flags);
1952
1953 NodeProperties::ChangeOp(node, jsgraph->common()->Call(desc));
1954 }
1955
NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared,int arity)1956 bool NeedsArgumentAdaptorFrame(Handle<SharedFunctionInfo> shared, int arity) {
1957 static const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1958 const int num_decl_parms = shared->internal_formal_parameter_count();
1959 return (num_decl_parms != arity && num_decl_parms != sentinel);
1960 }
1961
1962 } // namespace
1963
ReduceJSConstruct(Node * node)1964 Reduction JSTypedLowering::ReduceJSConstruct(Node* node) {
1965 DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode());
1966 ConstructParameters const& p = ConstructParametersOf(node->op());
1967 DCHECK_LE(2u, p.arity());
1968 int const arity = static_cast<int>(p.arity() - 2);
1969 Node* target = NodeProperties::GetValueInput(node, 0);
1970 Type* target_type = NodeProperties::GetType(target);
1971 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1972 Node* effect = NodeProperties::GetEffectInput(node);
1973 Node* control = NodeProperties::GetControlInput(node);
1974
1975 // Check if {target} is a known JSFunction.
1976 if (target_type->IsHeapConstant() &&
1977 target_type->AsHeapConstant()->Value()->IsJSFunction()) {
1978 Handle<JSFunction> function =
1979 Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
1980 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
1981 const int builtin_index = shared->construct_stub()->builtin_index();
1982 const bool is_builtin = (builtin_index != -1);
1983
1984 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
1985
1986 if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
1987 !NeedsArgumentAdaptorFrame(shared, arity)) {
1988 // Patch {node} to a direct CEntryStub call.
1989
1990 // Load the context from the {target}.
1991 Node* context = effect = graph()->NewNode(
1992 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()),
1993 target, effect, control);
1994 NodeProperties::ReplaceContextInput(node, context);
1995
1996 // Update the effect dependency for the {node}.
1997 NodeProperties::ReplaceEffectInput(node, effect);
1998
1999 ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
2000 } else {
2001 // Patch {node} to an indirect call via the {function}s construct stub.
2002 Callable callable(handle(shared->construct_stub(), isolate()),
2003 ConstructStubDescriptor(isolate()));
2004 node->RemoveInput(arity + 1);
2005 node->InsertInput(graph()->zone(), 0,
2006 jsgraph()->HeapConstant(callable.code()));
2007 node->InsertInput(graph()->zone(), 2, new_target);
2008 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
2009 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
2010 node->InsertInput(graph()->zone(), 5, jsgraph()->UndefinedConstant());
2011 NodeProperties::ChangeOp(
2012 node, common()->Call(Linkage::GetStubCallDescriptor(
2013 isolate(), graph()->zone(), callable.descriptor(),
2014 1 + arity, flags)));
2015 }
2016 return Changed(node);
2017 }
2018
2019 // Check if {target} is a JSFunction.
2020 if (target_type->Is(Type::Function())) {
2021 // Patch {node} to an indirect call via the ConstructFunction builtin.
2022 Callable callable = CodeFactory::ConstructFunction(isolate());
2023 node->RemoveInput(arity + 1);
2024 node->InsertInput(graph()->zone(), 0,
2025 jsgraph()->HeapConstant(callable.code()));
2026 node->InsertInput(graph()->zone(), 2, new_target);
2027 node->InsertInput(graph()->zone(), 3, jsgraph()->Constant(arity));
2028 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant());
2029 NodeProperties::ChangeOp(
2030 node, common()->Call(Linkage::GetStubCallDescriptor(
2031 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
2032 CallDescriptor::kNeedsFrameState)));
2033 return Changed(node);
2034 }
2035
2036 return NoChange();
2037 }
2038
ReduceJSCallForwardVarargs(Node * node)2039 Reduction JSTypedLowering::ReduceJSCallForwardVarargs(Node* node) {
2040 DCHECK_EQ(IrOpcode::kJSCallForwardVarargs, node->opcode());
2041 CallForwardVarargsParameters p = CallForwardVarargsParametersOf(node->op());
2042 Node* target = NodeProperties::GetValueInput(node, 0);
2043 Type* target_type = NodeProperties::GetType(target);
2044
2045 // Check if {target} is a JSFunction.
2046 if (target_type->Is(Type::Function())) {
2047 // Compute flags for the call.
2048 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2049 if (p.tail_call_mode() == TailCallMode::kAllow) {
2050 flags |= CallDescriptor::kSupportsTailCalls;
2051 }
2052
2053 // Patch {node} to an indirect call via CallFunctionForwardVarargs.
2054 Callable callable = CodeFactory::CallFunctionForwardVarargs(isolate());
2055 node->InsertInput(graph()->zone(), 0,
2056 jsgraph()->HeapConstant(callable.code()));
2057 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(p.start_index()));
2058 NodeProperties::ChangeOp(
2059 node,
2060 common()->Call(Linkage::GetStubCallDescriptor(
2061 isolate(), graph()->zone(), callable.descriptor(), 1, flags)));
2062 return Changed(node);
2063 }
2064
2065 return NoChange();
2066 }
2067
ReduceJSCall(Node * node)2068 Reduction JSTypedLowering::ReduceJSCall(Node* node) {
2069 DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
2070 CallParameters const& p = CallParametersOf(node->op());
2071 int const arity = static_cast<int>(p.arity() - 2);
2072 ConvertReceiverMode convert_mode = p.convert_mode();
2073 Node* target = NodeProperties::GetValueInput(node, 0);
2074 Type* target_type = NodeProperties::GetType(target);
2075 Node* receiver = NodeProperties::GetValueInput(node, 1);
2076 Type* receiver_type = NodeProperties::GetType(receiver);
2077 Node* effect = NodeProperties::GetEffectInput(node);
2078 Node* control = NodeProperties::GetControlInput(node);
2079
2080 // Try to infer receiver {convert_mode} from {receiver} type.
2081 if (receiver_type->Is(Type::NullOrUndefined())) {
2082 convert_mode = ConvertReceiverMode::kNullOrUndefined;
2083 } else if (!receiver_type->Maybe(Type::NullOrUndefined())) {
2084 convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2085 }
2086
2087 // Check if {target} is a known JSFunction.
2088 if (target_type->IsHeapConstant() &&
2089 target_type->AsHeapConstant()->Value()->IsJSFunction()) {
2090 Handle<JSFunction> function =
2091 Handle<JSFunction>::cast(target_type->AsHeapConstant()->Value());
2092 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
2093 const int builtin_index = shared->code()->builtin_index();
2094 const bool is_builtin = (builtin_index != -1);
2095
2096 // Class constructors are callable, but [[Call]] will raise an exception.
2097 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
2098 if (IsClassConstructor(shared->kind())) return NoChange();
2099
2100 // Load the context from the {target}.
2101 Node* context = effect = graph()->NewNode(
2102 simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target,
2103 effect, control);
2104 NodeProperties::ReplaceContextInput(node, context);
2105
2106 // Check if we need to convert the {receiver}.
2107 if (is_sloppy(shared->language_mode()) && !shared->native() &&
2108 !receiver_type->Is(Type::Receiver())) {
2109 receiver = effect =
2110 graph()->NewNode(javascript()->ConvertReceiver(convert_mode),
2111 receiver, context, effect, control);
2112 NodeProperties::ReplaceValueInput(node, receiver, 1);
2113 }
2114
2115 // Update the effect dependency for the {node}.
2116 NodeProperties::ReplaceEffectInput(node, effect);
2117
2118 // Compute flags for the call.
2119 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2120 if (p.tail_call_mode() == TailCallMode::kAllow) {
2121 flags |= CallDescriptor::kSupportsTailCalls;
2122 }
2123
2124 Node* new_target = jsgraph()->UndefinedConstant();
2125 Node* argument_count = jsgraph()->Constant(arity);
2126 if (NeedsArgumentAdaptorFrame(shared, arity)) {
2127 // Patch {node} to an indirect call via the ArgumentsAdaptorTrampoline.
2128 Callable callable = CodeFactory::ArgumentAdaptor(isolate());
2129 node->InsertInput(graph()->zone(), 0,
2130 jsgraph()->HeapConstant(callable.code()));
2131 node->InsertInput(graph()->zone(), 2, new_target);
2132 node->InsertInput(graph()->zone(), 3, argument_count);
2133 node->InsertInput(
2134 graph()->zone(), 4,
2135 jsgraph()->Constant(shared->internal_formal_parameter_count()));
2136 NodeProperties::ChangeOp(
2137 node, common()->Call(Linkage::GetStubCallDescriptor(
2138 isolate(), graph()->zone(), callable.descriptor(),
2139 1 + arity, flags)));
2140 } else if (is_builtin && Builtins::HasCppImplementation(builtin_index) &&
2141 ((flags & CallDescriptor::kSupportsTailCalls) == 0)) {
2142 // Patch {node} to a direct CEntryStub call.
2143 ReduceBuiltin(isolate(), jsgraph(), node, builtin_index, arity, flags);
2144 } else {
2145 // Patch {node} to a direct call.
2146 node->InsertInput(graph()->zone(), arity + 2, new_target);
2147 node->InsertInput(graph()->zone(), arity + 3, argument_count);
2148 NodeProperties::ChangeOp(node,
2149 common()->Call(Linkage::GetJSCallDescriptor(
2150 graph()->zone(), false, 1 + arity, flags)));
2151 }
2152 return Changed(node);
2153 }
2154
2155 // Check if {target} is a JSFunction.
2156 if (target_type->Is(Type::Function())) {
2157 // Compute flags for the call.
2158 CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
2159 if (p.tail_call_mode() == TailCallMode::kAllow) {
2160 flags |= CallDescriptor::kSupportsTailCalls;
2161 }
2162
2163 // Patch {node} to an indirect call via the CallFunction builtin.
2164 Callable callable = CodeFactory::CallFunction(isolate(), convert_mode);
2165 node->InsertInput(graph()->zone(), 0,
2166 jsgraph()->HeapConstant(callable.code()));
2167 node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(arity));
2168 NodeProperties::ChangeOp(
2169 node, common()->Call(Linkage::GetStubCallDescriptor(
2170 isolate(), graph()->zone(), callable.descriptor(), 1 + arity,
2171 flags)));
2172 return Changed(node);
2173 }
2174
2175 // Maybe we did at least learn something about the {receiver}.
2176 if (p.convert_mode() != convert_mode) {
2177 NodeProperties::ChangeOp(
2178 node,
2179 javascript()->Call(p.arity(), p.frequency(), p.feedback(), convert_mode,
2180 p.tail_call_mode()));
2181 return Changed(node);
2182 }
2183
2184 return NoChange();
2185 }
2186
2187
ReduceJSForInNext(Node * node)2188 Reduction JSTypedLowering::ReduceJSForInNext(Node* node) {
2189 DCHECK_EQ(IrOpcode::kJSForInNext, node->opcode());
2190 Node* receiver = NodeProperties::GetValueInput(node, 0);
2191 Node* cache_array = NodeProperties::GetValueInput(node, 1);
2192 Node* cache_type = NodeProperties::GetValueInput(node, 2);
2193 Node* index = NodeProperties::GetValueInput(node, 3);
2194 Node* context = NodeProperties::GetContextInput(node);
2195 Node* frame_state = NodeProperties::GetFrameStateInput(node);
2196 Node* effect = NodeProperties::GetEffectInput(node);
2197 Node* control = NodeProperties::GetControlInput(node);
2198
2199 // We don't support lowering JSForInNext inside try blocks.
2200 if (NodeProperties::IsExceptionalCall(node)) return NoChange();
2201
2202 // We know that the {index} is in Unsigned32 range here, otherwise executing
2203 // the JSForInNext wouldn't be valid. Unfortunately due to OSR and generators
2204 // this is not always reflected in the types, hence we might need to rename
2205 // the {index} here.
2206 if (!NodeProperties::GetType(index)->Is(Type::Unsigned32())) {
2207 index = graph()->NewNode(common()->TypeGuard(Type::Unsigned32()), index,
2208 control);
2209 }
2210
2211 // Load the next {key} from the {cache_array}.
2212 Node* key = effect = graph()->NewNode(
2213 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
2214 cache_array, index, effect, control);
2215
2216 // Load the map of the {receiver}.
2217 Node* receiver_map = effect =
2218 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
2219 receiver, effect, control);
2220
2221 // Check if the expected map still matches that of the {receiver}.
2222 Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), receiver_map,
2223 cache_type);
2224 Node* branch0 =
2225 graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
2226
2227 Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
2228 Node* etrue0;
2229 Node* vtrue0;
2230 {
2231 // Don't need filtering since expected map still matches that of the
2232 // {receiver}.
2233 etrue0 = effect;
2234 vtrue0 = key;
2235 }
2236
2237 Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
2238 Node* efalse0;
2239 Node* vfalse0;
2240 {
2241 // Filter the {key} to check if it's still a valid property of the
2242 // {receiver} (does the ToName conversion implicitly).
2243 Callable const callable = CodeFactory::ForInFilter(isolate());
2244 CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
2245 isolate(), graph()->zone(), callable.descriptor(), 0,
2246 CallDescriptor::kNeedsFrameState);
2247 vfalse0 = efalse0 = graph()->NewNode(
2248 common()->Call(desc), jsgraph()->HeapConstant(callable.code()), key,
2249 receiver, context, frame_state, effect, if_false0);
2250 if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
2251 }
2252
2253 control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
2254 effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
2255 ReplaceWithValue(node, node, effect, control);
2256 node->ReplaceInput(0, vtrue0);
2257 node->ReplaceInput(1, vfalse0);
2258 node->ReplaceInput(2, control);
2259 node->TrimInputCount(3);
2260 NodeProperties::ChangeOp(node,
2261 common()->Phi(MachineRepresentation::kTagged, 2));
2262 return Changed(node);
2263 }
2264
ReduceJSLoadMessage(Node * node)2265 Reduction JSTypedLowering::ReduceJSLoadMessage(Node* node) {
2266 DCHECK_EQ(IrOpcode::kJSLoadMessage, node->opcode());
2267 ExternalReference const ref =
2268 ExternalReference::address_of_pending_message_obj(isolate());
2269 node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2270 NodeProperties::ChangeOp(
2271 node, simplified()->LoadField(AccessBuilder::ForExternalTaggedValue()));
2272 return Changed(node);
2273 }
2274
ReduceJSStoreMessage(Node * node)2275 Reduction JSTypedLowering::ReduceJSStoreMessage(Node* node) {
2276 DCHECK_EQ(IrOpcode::kJSStoreMessage, node->opcode());
2277 ExternalReference const ref =
2278 ExternalReference::address_of_pending_message_obj(isolate());
2279 Node* value = NodeProperties::GetValueInput(node, 0);
2280 node->ReplaceInput(0, jsgraph()->ExternalConstant(ref));
2281 node->ReplaceInput(1, value);
2282 NodeProperties::ChangeOp(
2283 node, simplified()->StoreField(AccessBuilder::ForExternalTaggedValue()));
2284 return Changed(node);
2285 }
2286
ReduceJSGeneratorStore(Node * node)2287 Reduction JSTypedLowering::ReduceJSGeneratorStore(Node* node) {
2288 DCHECK_EQ(IrOpcode::kJSGeneratorStore, node->opcode());
2289 Node* generator = NodeProperties::GetValueInput(node, 0);
2290 Node* continuation = NodeProperties::GetValueInput(node, 1);
2291 Node* offset = NodeProperties::GetValueInput(node, 2);
2292 Node* context = NodeProperties::GetContextInput(node);
2293 Node* effect = NodeProperties::GetEffectInput(node);
2294 Node* control = NodeProperties::GetControlInput(node);
2295 int register_count = OpParameter<int>(node);
2296
2297 FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2298 FieldAccess context_field = AccessBuilder::ForJSGeneratorObjectContext();
2299 FieldAccess continuation_field =
2300 AccessBuilder::ForJSGeneratorObjectContinuation();
2301 FieldAccess input_or_debug_pos_field =
2302 AccessBuilder::ForJSGeneratorObjectInputOrDebugPos();
2303
2304 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2305 generator, effect, control);
2306
2307 for (int i = 0; i < register_count; ++i) {
2308 Node* value = NodeProperties::GetValueInput(node, 3 + i);
2309 effect = graph()->NewNode(
2310 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), array,
2311 value, effect, control);
2312 }
2313
2314 effect = graph()->NewNode(simplified()->StoreField(context_field), generator,
2315 context, effect, control);
2316 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2317 generator, continuation, effect, control);
2318 effect = graph()->NewNode(simplified()->StoreField(input_or_debug_pos_field),
2319 generator, offset, effect, control);
2320
2321 ReplaceWithValue(node, effect, effect, control);
2322 return Changed(effect);
2323 }
2324
ReduceJSGeneratorRestoreContinuation(Node * node)2325 Reduction JSTypedLowering::ReduceJSGeneratorRestoreContinuation(Node* node) {
2326 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreContinuation, node->opcode());
2327 Node* generator = NodeProperties::GetValueInput(node, 0);
2328 Node* effect = NodeProperties::GetEffectInput(node);
2329 Node* control = NodeProperties::GetControlInput(node);
2330
2331 FieldAccess continuation_field =
2332 AccessBuilder::ForJSGeneratorObjectContinuation();
2333
2334 Node* continuation = effect = graph()->NewNode(
2335 simplified()->LoadField(continuation_field), generator, effect, control);
2336 Node* executing = jsgraph()->Constant(JSGeneratorObject::kGeneratorExecuting);
2337 effect = graph()->NewNode(simplified()->StoreField(continuation_field),
2338 generator, executing, effect, control);
2339
2340 ReplaceWithValue(node, continuation, effect, control);
2341 return Changed(continuation);
2342 }
2343
ReduceJSGeneratorRestoreRegister(Node * node)2344 Reduction JSTypedLowering::ReduceJSGeneratorRestoreRegister(Node* node) {
2345 DCHECK_EQ(IrOpcode::kJSGeneratorRestoreRegister, node->opcode());
2346 Node* generator = NodeProperties::GetValueInput(node, 0);
2347 Node* effect = NodeProperties::GetEffectInput(node);
2348 Node* control = NodeProperties::GetControlInput(node);
2349 int index = OpParameter<int>(node);
2350
2351 FieldAccess array_field = AccessBuilder::ForJSGeneratorObjectRegisterFile();
2352 FieldAccess element_field = AccessBuilder::ForFixedArraySlot(index);
2353
2354 Node* array = effect = graph()->NewNode(simplified()->LoadField(array_field),
2355 generator, effect, control);
2356 Node* element = effect = graph()->NewNode(
2357 simplified()->LoadField(element_field), array, effect, control);
2358 Node* stale = jsgraph()->StaleRegisterConstant();
2359 effect = graph()->NewNode(simplified()->StoreField(element_field), array,
2360 stale, effect, control);
2361
2362 ReplaceWithValue(node, element, effect, control);
2363 return Changed(element);
2364 }
2365
Reduce(Node * node)2366 Reduction JSTypedLowering::Reduce(Node* node) {
2367 switch (node->opcode()) {
2368 case IrOpcode::kJSEqual:
2369 return ReduceJSEqual(node, false);
2370 case IrOpcode::kJSNotEqual:
2371 return ReduceJSEqual(node, true);
2372 case IrOpcode::kJSStrictEqual:
2373 return ReduceJSStrictEqual(node, false);
2374 case IrOpcode::kJSStrictNotEqual:
2375 return ReduceJSStrictEqual(node, true);
2376 case IrOpcode::kJSLessThan: // fall through
2377 case IrOpcode::kJSGreaterThan: // fall through
2378 case IrOpcode::kJSLessThanOrEqual: // fall through
2379 case IrOpcode::kJSGreaterThanOrEqual:
2380 return ReduceJSComparison(node);
2381 case IrOpcode::kJSBitwiseOr:
2382 case IrOpcode::kJSBitwiseXor:
2383 case IrOpcode::kJSBitwiseAnd:
2384 return ReduceInt32Binop(node);
2385 case IrOpcode::kJSShiftLeft:
2386 case IrOpcode::kJSShiftRight:
2387 return ReduceUI32Shift(node, kSigned);
2388 case IrOpcode::kJSShiftRightLogical:
2389 return ReduceUI32Shift(node, kUnsigned);
2390 case IrOpcode::kJSAdd:
2391 return ReduceJSAdd(node);
2392 case IrOpcode::kJSSubtract:
2393 case IrOpcode::kJSMultiply:
2394 case IrOpcode::kJSDivide:
2395 case IrOpcode::kJSModulus:
2396 return ReduceNumberBinop(node);
2397 case IrOpcode::kJSOrdinaryHasInstance:
2398 return ReduceJSOrdinaryHasInstance(node);
2399 case IrOpcode::kJSToBoolean:
2400 return ReduceJSToBoolean(node);
2401 case IrOpcode::kJSToInteger:
2402 return ReduceJSToInteger(node);
2403 case IrOpcode::kJSToLength:
2404 return ReduceJSToLength(node);
2405 case IrOpcode::kJSToName:
2406 return ReduceJSToName(node);
2407 case IrOpcode::kJSToNumber:
2408 return ReduceJSToNumber(node);
2409 case IrOpcode::kJSToString:
2410 return ReduceJSToString(node);
2411 case IrOpcode::kJSToObject:
2412 return ReduceJSToObject(node);
2413 case IrOpcode::kJSTypeOf:
2414 return ReduceJSTypeOf(node);
2415 case IrOpcode::kJSLoadNamed:
2416 return ReduceJSLoadNamed(node);
2417 case IrOpcode::kJSLoadProperty:
2418 return ReduceJSLoadProperty(node);
2419 case IrOpcode::kJSStoreProperty:
2420 return ReduceJSStoreProperty(node);
2421 case IrOpcode::kJSLoadContext:
2422 return ReduceJSLoadContext(node);
2423 case IrOpcode::kJSStoreContext:
2424 return ReduceJSStoreContext(node);
2425 case IrOpcode::kJSLoadModule:
2426 return ReduceJSLoadModule(node);
2427 case IrOpcode::kJSStoreModule:
2428 return ReduceJSStoreModule(node);
2429 case IrOpcode::kJSConvertReceiver:
2430 return ReduceJSConvertReceiver(node);
2431 case IrOpcode::kJSConstruct:
2432 return ReduceJSConstruct(node);
2433 case IrOpcode::kJSCallForwardVarargs:
2434 return ReduceJSCallForwardVarargs(node);
2435 case IrOpcode::kJSCall:
2436 return ReduceJSCall(node);
2437 case IrOpcode::kJSForInNext:
2438 return ReduceJSForInNext(node);
2439 case IrOpcode::kJSLoadMessage:
2440 return ReduceJSLoadMessage(node);
2441 case IrOpcode::kJSStoreMessage:
2442 return ReduceJSStoreMessage(node);
2443 case IrOpcode::kJSGeneratorStore:
2444 return ReduceJSGeneratorStore(node);
2445 case IrOpcode::kJSGeneratorRestoreContinuation:
2446 return ReduceJSGeneratorRestoreContinuation(node);
2447 case IrOpcode::kJSGeneratorRestoreRegister:
2448 return ReduceJSGeneratorRestoreRegister(node);
2449 // TODO(mstarzinger): Simplified operations hiding in JS-level reducer not
2450 // fooling anyone. Consider moving this into a separate reducer.
2451 case IrOpcode::kSpeculativeNumberAdd:
2452 return ReduceSpeculativeNumberAdd(node);
2453 case IrOpcode::kSpeculativeNumberSubtract:
2454 case IrOpcode::kSpeculativeNumberMultiply:
2455 case IrOpcode::kSpeculativeNumberDivide:
2456 case IrOpcode::kSpeculativeNumberModulus:
2457 return ReduceSpeculativeNumberBinop(node);
2458 default:
2459 break;
2460 }
2461 return NoChange();
2462 }
2463
2464
factory() const2465 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2466
2467
graph() const2468 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2469
2470
isolate() const2471 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2472
2473
javascript() const2474 JSOperatorBuilder* JSTypedLowering::javascript() const {
2475 return jsgraph()->javascript();
2476 }
2477
2478
common() const2479 CommonOperatorBuilder* JSTypedLowering::common() const {
2480 return jsgraph()->common();
2481 }
2482
simplified() const2483 SimplifiedOperatorBuilder* JSTypedLowering::simplified() const {
2484 return jsgraph()->simplified();
2485 }
2486
2487
dependencies() const2488 CompilationDependencies* JSTypedLowering::dependencies() const {
2489 return dependencies_;
2490 }
2491
2492 } // namespace compiler
2493 } // namespace internal
2494 } // namespace v8
2495