Line data Source code
1 : // Copyright 2017 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-type-hint-lowering.h"
6 :
7 : #include "src/compiler/js-graph.h"
8 : #include "src/compiler/operator-properties.h"
9 : #include "src/compiler/simplified-operator.h"
10 : #include "src/feedback-vector.h"
11 : #include "src/type-hints.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 : namespace compiler {
16 :
17 : namespace {
18 :
19 : bool BinaryOperationHintToNumberOperationHint(
20 : BinaryOperationHint binop_hint, NumberOperationHint* number_hint) {
21 490418 : switch (binop_hint) {
22 : case BinaryOperationHint::kSignedSmall:
23 157528 : *number_hint = NumberOperationHint::kSignedSmall;
24 : return true;
25 : case BinaryOperationHint::kSigned32:
26 0 : *number_hint = NumberOperationHint::kSigned32;
27 : return true;
28 : case BinaryOperationHint::kNumberOrOddball:
29 98802 : *number_hint = NumberOperationHint::kNumberOrOddball;
30 : return true;
31 : case BinaryOperationHint::kAny:
32 : case BinaryOperationHint::kNone:
33 : case BinaryOperationHint::kString:
34 : break;
35 : }
36 : return false;
37 : }
38 :
39 : } // namespace
40 :
41 : class JSSpeculativeBinopBuilder final {
42 : public:
43 : JSSpeculativeBinopBuilder(const JSTypeHintLowering* lowering,
44 : const Operator* op, Node* left, Node* right,
45 : Node* effect, Node* control, FeedbackSlot slot)
46 : : lowering_(lowering),
47 : op_(op),
48 : left_(left),
49 : right_(right),
50 : effect_(effect),
51 : control_(control),
52 586189 : slot_(slot) {}
53 :
54 485425 : BinaryOperationHint GetBinaryOperationHint() {
55 : DCHECK_EQ(FeedbackSlotKind::kBinaryOp, feedback_vector()->GetKind(slot_));
56 : BinaryOpICNexus nexus(feedback_vector(), slot_);
57 485425 : return nexus.GetBinaryOperationFeedback();
58 : }
59 :
60 100764 : CompareOperationHint GetCompareOperationHint() {
61 : DCHECK_EQ(FeedbackSlotKind::kCompareOp, feedback_vector()->GetKind(slot_));
62 : CompareICNexus nexus(feedback_vector(), slot_);
63 100764 : return nexus.GetCompareOperationFeedback();
64 : }
65 :
66 485425 : bool GetBinaryNumberOperationHint(NumberOperationHint* hint) {
67 : return BinaryOperationHintToNumberOperationHint(GetBinaryOperationHint(),
68 970850 : hint);
69 : }
70 :
71 100764 : bool GetCompareNumberOperationHint(NumberOperationHint* hint) {
72 100764 : switch (GetCompareOperationHint()) {
73 : case CompareOperationHint::kSignedSmall:
74 52937 : *hint = NumberOperationHint::kSignedSmall;
75 52937 : return true;
76 : case CompareOperationHint::kNumber:
77 1686 : *hint = NumberOperationHint::kNumber;
78 1686 : return true;
79 : case CompareOperationHint::kNumberOrOddball:
80 61 : *hint = NumberOperationHint::kNumberOrOddball;
81 61 : return true;
82 : case CompareOperationHint::kAny:
83 : case CompareOperationHint::kNone:
84 : case CompareOperationHint::kString:
85 : case CompareOperationHint::kReceiver:
86 : case CompareOperationHint::kInternalizedString:
87 : break;
88 : }
89 : return false;
90 : }
91 :
92 256330 : const Operator* SpeculativeNumberOp(NumberOperationHint hint) {
93 256330 : switch (op_->opcode()) {
94 : case IrOpcode::kJSAdd:
95 150566 : return simplified()->SpeculativeNumberAdd(hint);
96 : case IrOpcode::kJSSubtract:
97 25027 : return simplified()->SpeculativeNumberSubtract(hint);
98 : case IrOpcode::kJSMultiply:
99 27320 : return simplified()->SpeculativeNumberMultiply(hint);
100 : case IrOpcode::kJSDivide:
101 16757 : return simplified()->SpeculativeNumberDivide(hint);
102 : case IrOpcode::kJSModulus:
103 3812 : return simplified()->SpeculativeNumberModulus(hint);
104 : case IrOpcode::kJSBitwiseAnd:
105 5038 : return simplified()->SpeculativeNumberBitwiseAnd(hint);
106 : case IrOpcode::kJSBitwiseOr:
107 17150 : return simplified()->SpeculativeNumberBitwiseOr(hint);
108 : case IrOpcode::kJSBitwiseXor:
109 1435 : return simplified()->SpeculativeNumberBitwiseXor(hint);
110 : case IrOpcode::kJSShiftLeft:
111 2296 : return simplified()->SpeculativeNumberShiftLeft(hint);
112 : case IrOpcode::kJSShiftRight:
113 5022 : return simplified()->SpeculativeNumberShiftRight(hint);
114 : case IrOpcode::kJSShiftRightLogical:
115 1907 : return simplified()->SpeculativeNumberShiftRightLogical(hint);
116 : default:
117 : break;
118 : }
119 0 : UNREACHABLE();
120 : return nullptr;
121 : }
122 :
123 54684 : const Operator* SpeculativeCompareOp(NumberOperationHint hint) {
124 54684 : switch (op_->opcode()) {
125 : case IrOpcode::kJSEqual:
126 6543 : return simplified()->SpeculativeNumberEqual(hint);
127 : case IrOpcode::kJSLessThan:
128 14604 : return simplified()->SpeculativeNumberLessThan(hint);
129 : case IrOpcode::kJSGreaterThan:
130 : std::swap(left_, right_); // a > b => b < a
131 31975 : return simplified()->SpeculativeNumberLessThan(hint);
132 : case IrOpcode::kJSLessThanOrEqual:
133 709 : return simplified()->SpeculativeNumberLessThanOrEqual(hint);
134 : case IrOpcode::kJSGreaterThanOrEqual:
135 : std::swap(left_, right_); // a >= b => b <= a
136 853 : return simplified()->SpeculativeNumberLessThanOrEqual(hint);
137 : default:
138 : break;
139 : }
140 0 : UNREACHABLE();
141 : return nullptr;
142 : }
143 :
144 311014 : Node* BuildSpeculativeOperation(const Operator* op) {
145 : DCHECK_EQ(2, op->ValueInputCount());
146 : DCHECK_EQ(1, op->EffectInputCount());
147 : DCHECK_EQ(1, op->ControlInputCount());
148 : DCHECK_EQ(false, OperatorProperties::HasFrameStateInput(op));
149 : DCHECK_EQ(false, OperatorProperties::HasContextInput(op));
150 : DCHECK_EQ(1, op->EffectOutputCount());
151 : DCHECK_EQ(0, op->ControlOutputCount());
152 622028 : return graph()->NewNode(op, left_, right_, effect_, control_);
153 : }
154 :
155 485425 : Node* TryBuildNumberBinop() {
156 : NumberOperationHint hint;
157 485425 : if (GetBinaryNumberOperationHint(&hint)) {
158 256330 : const Operator* op = SpeculativeNumberOp(hint);
159 256330 : Node* node = BuildSpeculativeOperation(op);
160 256330 : return node;
161 : }
162 : return nullptr;
163 : }
164 :
165 100764 : Node* TryBuildNumberCompare() {
166 : NumberOperationHint hint;
167 100764 : if (GetCompareNumberOperationHint(&hint)) {
168 54684 : const Operator* op = SpeculativeCompareOp(hint);
169 54684 : Node* node = BuildSpeculativeOperation(op);
170 54684 : return node;
171 : }
172 : return nullptr;
173 : }
174 :
175 622028 : JSGraph* jsgraph() const { return lowering_->jsgraph(); }
176 622028 : Graph* graph() const { return jsgraph()->graph(); }
177 : JSOperatorBuilder* javascript() { return jsgraph()->javascript(); }
178 622028 : SimplifiedOperatorBuilder* simplified() { return jsgraph()->simplified(); }
179 : CommonOperatorBuilder* common() { return jsgraph()->common(); }
180 : const Handle<FeedbackVector>& feedback_vector() const {
181 : return lowering_->feedback_vector();
182 : }
183 :
184 : private:
185 : const JSTypeHintLowering* lowering_;
186 : const Operator* op_;
187 : Node* left_;
188 : Node* right_;
189 : Node* effect_;
190 : Node* control_;
191 : FeedbackSlot slot_;
192 : };
193 :
194 430866 : JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
195 : Handle<FeedbackVector> feedback_vector,
196 : Flags flags)
197 430866 : : jsgraph_(jsgraph), flags_(flags), feedback_vector_(feedback_vector) {}
198 :
199 840415 : Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
200 : Node* left, Node* right,
201 : Node* effect, Node* control,
202 : FeedbackSlot slot) const {
203 : switch (op->opcode()) {
204 : case IrOpcode::kJSStrictEqual:
205 : break;
206 : case IrOpcode::kJSEqual:
207 : case IrOpcode::kJSLessThan:
208 : case IrOpcode::kJSGreaterThan:
209 : case IrOpcode::kJSLessThanOrEqual:
210 : case IrOpcode::kJSGreaterThanOrEqual: {
211 : JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
212 100764 : if (Node* node = b.TryBuildNumberCompare()) {
213 54684 : return Reduction(node);
214 : }
215 46080 : break;
216 : }
217 : case IrOpcode::kJSBitwiseOr:
218 : case IrOpcode::kJSBitwiseXor:
219 : case IrOpcode::kJSBitwiseAnd:
220 : case IrOpcode::kJSShiftLeft:
221 : case IrOpcode::kJSShiftRight:
222 : case IrOpcode::kJSShiftRightLogical:
223 : case IrOpcode::kJSAdd:
224 : case IrOpcode::kJSSubtract:
225 : case IrOpcode::kJSMultiply:
226 : case IrOpcode::kJSDivide:
227 : case IrOpcode::kJSModulus: {
228 : JSSpeculativeBinopBuilder b(this, op, left, right, effect, control, slot);
229 485425 : if (Node* node = b.TryBuildNumberBinop()) {
230 256330 : return Reduction(node);
231 : }
232 229095 : break;
233 : }
234 : default:
235 0 : UNREACHABLE();
236 : break;
237 : }
238 529401 : return Reduction();
239 : }
240 :
241 4993 : Reduction JSTypeHintLowering::ReduceToNumberOperation(Node* input, Node* effect,
242 : Node* control,
243 4438 : FeedbackSlot slot) const {
244 : DCHECK(!slot.IsInvalid());
245 : BinaryOpICNexus nexus(feedback_vector(), slot);
246 : NumberOperationHint hint;
247 4993 : if (BinaryOperationHintToNumberOperationHint(
248 4993 : nexus.GetBinaryOperationFeedback(), &hint)) {
249 : Node* node = jsgraph()->graph()->NewNode(
250 : jsgraph()->simplified()->SpeculativeToNumber(hint), input, effect,
251 4438 : control);
252 2219 : return Reduction(node);
253 : }
254 2774 : return Reduction();
255 : }
256 :
257 455619 : Reduction JSTypeHintLowering::ReduceLoadNamedOperation(
258 : const Operator* op, Node* obj, Node* effect, Node* control,
259 : FeedbackSlot slot) const {
260 : DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
261 : DCHECK(!slot.IsInvalid());
262 : LoadICNexus nexus(feedback_vector(), slot);
263 455619 : if (Node* node = TryBuildSoftDeopt(
264 : nexus, effect, control,
265 455619 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
266 22623 : return Reduction(node);
267 : }
268 432996 : return Reduction();
269 : }
270 :
271 67876 : Reduction JSTypeHintLowering::ReduceLoadKeyedOperation(
272 : const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
273 : FeedbackSlot slot) const {
274 : DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
275 : DCHECK(!slot.IsInvalid());
276 : KeyedLoadICNexus nexus(feedback_vector(), slot);
277 67876 : if (Node* node = TryBuildSoftDeopt(
278 : nexus, effect, control,
279 67876 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
280 348 : return Reduction(node);
281 : }
282 67528 : return Reduction();
283 : }
284 :
285 98217 : Reduction JSTypeHintLowering::ReduceStoreNamedOperation(
286 : const Operator* op, Node* obj, Node* val, Node* effect, Node* control,
287 : FeedbackSlot slot) const {
288 : DCHECK(op->opcode() == IrOpcode::kJSStoreNamed ||
289 : op->opcode() == IrOpcode::kJSStoreNamedOwn);
290 : DCHECK(!slot.IsInvalid());
291 : StoreICNexus nexus(feedback_vector(), slot);
292 98217 : if (Node* node = TryBuildSoftDeopt(
293 : nexus, effect, control,
294 98217 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
295 375 : return Reduction(node);
296 : }
297 97842 : return Reduction();
298 : }
299 :
300 39360 : Reduction JSTypeHintLowering::ReduceStoreKeyedOperation(
301 : const Operator* op, Node* obj, Node* key, Node* val, Node* effect,
302 : Node* control, FeedbackSlot slot) const {
303 : DCHECK_EQ(IrOpcode::kJSStoreProperty, op->opcode());
304 : DCHECK(!slot.IsInvalid());
305 : KeyedStoreICNexus nexus(feedback_vector(), slot);
306 39360 : if (Node* node = TryBuildSoftDeopt(
307 : nexus, effect, control,
308 39360 : DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
309 69 : return Reduction(node);
310 : }
311 39291 : return Reduction();
312 : }
313 :
314 661072 : Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
315 : Node* control,
316 70245 : DeoptimizeReason reason) const {
317 789090 : if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
318 : Node* deoptimize = jsgraph()->graph()->NewNode(
319 : jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason),
320 70245 : jsgraph()->Dead(), effect, control);
321 23415 : Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
322 23415 : deoptimize->ReplaceInput(0, frame_state);
323 23415 : return deoptimize;
324 : }
325 : return nullptr;
326 : }
327 :
328 : } // namespace compiler
329 : } // namespace internal
330 : } // namespace v8
|