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