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/code-factory.h"
6 #include "src/compiler/access-builder.h"
7 #include "src/compiler/js-graph.h"
8 #include "src/compiler/js-operator.h"
9 #include "src/compiler/js-typed-lowering.h"
10 #include "src/compiler/machine-operator.h"
11 #include "src/compiler/node-properties.h"
12 #include "src/compiler/operator-properties.h"
13 #include "src/isolate-inl.h"
14 #include "test/unittests/compiler/compiler-test-utils.h"
15 #include "test/unittests/compiler/graph-unittest.h"
16 #include "test/unittests/compiler/node-test-utils.h"
17 #include "testing/gmock-support.h"
18
19 using testing::_;
20 using testing::BitEq;
21 using testing::IsNaN;
22
23
24 namespace v8 {
25 namespace internal {
26 namespace compiler {
27
28 namespace {
29
30 const ExternalArrayType kExternalArrayTypes[] = {
31 kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
32 kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
33 kExternalFloat32Array, kExternalFloat64Array};
34
35
36 const double kFloat64Values[] = {
37 -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
38 -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
39 -1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09,
40 -7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984,
41 -107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10,
42 -9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79,
43 -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
44 -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282,
45 -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308,
46 1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228,
47 2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90,
48 2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05,
49 2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08,
50 4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54,
51 2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166,
52 4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243,
53 1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294,
54 1.79769e+308, V8_INFINITY};
55
56
57 const size_t kIndices[] = {0, 1, 42, 100, 1024};
58
59
60 const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0,
61 -1.0, 0.0, 1.0, 42.0,
62 1000.0, INT_MAX, UINT_MAX, V8_INFINITY};
63
64
65 Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
66 Type::Number(), Type::String(), Type::Object()};
67
68
69 STATIC_ASSERT(LANGUAGE_END == 3);
70 const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG};
71
72 } // namespace
73
74
75 class JSTypedLoweringTest : public TypedGraphTest {
76 public:
JSTypedLoweringTest()77 JSTypedLoweringTest()
78 : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {}
~JSTypedLoweringTest()79 ~JSTypedLoweringTest() override {}
80
81 protected:
Reduce(Node * node)82 Reduction Reduce(Node* node) {
83 MachineOperatorBuilder machine(zone());
84 SimplifiedOperatorBuilder simplified(zone());
85 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
86 &machine);
87 // TODO(titzer): mock the GraphReducer here for better unit testing.
88 GraphReducer graph_reducer(zone(), graph());
89 JSTypedLowering reducer(&graph_reducer, &deps_,
90 JSTypedLowering::kDeoptimizationEnabled, &jsgraph,
91 zone());
92 return reducer.Reduce(node);
93 }
94
FrameState(Handle<SharedFunctionInfo> shared,Node * outer_frame_state)95 Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) {
96 Node* state_values = graph()->NewNode(common()->StateValues(0));
97 return graph()->NewNode(
98 common()->FrameState(BailoutId::None(),
99 OutputFrameStateCombine::Ignore(),
100 common()->CreateFrameStateFunctionInfo(
101 FrameStateType::kJavaScriptFunction, 1, 0,
102 shared, CALL_MAINTAINS_NATIVE_CONTEXT)),
103 state_values, state_values, state_values, NumberConstant(0),
104 UndefinedConstant(), outer_frame_state);
105 }
106
NewArrayBuffer(void * bytes,size_t byte_length)107 Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
108 Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
109 JSArrayBuffer::Setup(buffer, isolate(), true, bytes, byte_length);
110 return buffer;
111 }
112
IsIntPtrConstant(intptr_t value)113 Matcher<Node*> IsIntPtrConstant(intptr_t value) {
114 return sizeof(value) == 4 ? IsInt32Constant(static_cast<int32_t>(value))
115 : IsInt64Constant(static_cast<int64_t>(value));
116 }
117
javascript()118 JSOperatorBuilder* javascript() { return &javascript_; }
119
120 private:
121 JSOperatorBuilder javascript_;
122 CompilationDependencies deps_;
123 };
124
125
126 // -----------------------------------------------------------------------------
127 // Constant propagation
128
129
TEST_F(JSTypedLoweringTest,ParameterWithMinusZero)130 TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
131 {
132 Reduction r = Reduce(
133 Parameter(Type::Constant(factory()->minus_zero_value(), zone())));
134 ASSERT_TRUE(r.Changed());
135 EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
136 }
137 {
138 Reduction r = Reduce(Parameter(Type::MinusZero()));
139 ASSERT_TRUE(r.Changed());
140 EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
141 }
142 {
143 Reduction r = Reduce(Parameter(
144 Type::Union(Type::MinusZero(),
145 Type::Constant(factory()->NewNumber(0), zone()), zone())));
146 EXPECT_FALSE(r.Changed());
147 }
148 }
149
150
TEST_F(JSTypedLoweringTest,ParameterWithNull)151 TEST_F(JSTypedLoweringTest, ParameterWithNull) {
152 Handle<HeapObject> null = factory()->null_value();
153 {
154 Reduction r = Reduce(Parameter(Type::Constant(null, zone())));
155 ASSERT_TRUE(r.Changed());
156 EXPECT_THAT(r.replacement(), IsHeapConstant(null));
157 }
158 {
159 Reduction r = Reduce(Parameter(Type::Null()));
160 ASSERT_TRUE(r.Changed());
161 EXPECT_THAT(r.replacement(), IsHeapConstant(null));
162 }
163 }
164
165
TEST_F(JSTypedLoweringTest,ParameterWithNaN)166 TEST_F(JSTypedLoweringTest, ParameterWithNaN) {
167 const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(),
168 std::numeric_limits<double>::quiet_NaN(),
169 std::numeric_limits<double>::signaling_NaN()};
170 TRACED_FOREACH(double, nan, kNaNs) {
171 Handle<Object> constant = factory()->NewNumber(nan);
172 Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
173 ASSERT_TRUE(r.Changed());
174 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
175 }
176 {
177 Reduction r =
178 Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
179 ASSERT_TRUE(r.Changed());
180 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
181 }
182 {
183 Reduction r = Reduce(Parameter(Type::NaN()));
184 ASSERT_TRUE(r.Changed());
185 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
186 }
187 }
188
189
TEST_F(JSTypedLoweringTest,ParameterWithPlainNumber)190 TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
191 TRACED_FOREACH(double, value, kFloat64Values) {
192 Handle<Object> constant = factory()->NewNumber(value);
193 Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
194 ASSERT_TRUE(r.Changed());
195 EXPECT_THAT(r.replacement(), IsNumberConstant(value));
196 }
197 TRACED_FOREACH(double, value, kIntegerValues) {
198 Reduction r = Reduce(Parameter(Type::Range(value, value, zone())));
199 ASSERT_TRUE(r.Changed());
200 EXPECT_THAT(r.replacement(), IsNumberConstant(value));
201 }
202 }
203
204
TEST_F(JSTypedLoweringTest,ParameterWithUndefined)205 TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
206 Handle<HeapObject> undefined = factory()->undefined_value();
207 {
208 Reduction r = Reduce(Parameter(Type::Undefined()));
209 ASSERT_TRUE(r.Changed());
210 EXPECT_THAT(r.replacement(), IsHeapConstant(undefined));
211 }
212 {
213 Reduction r = Reduce(Parameter(Type::Constant(undefined, zone())));
214 ASSERT_TRUE(r.Changed());
215 EXPECT_THAT(r.replacement(), IsHeapConstant(undefined));
216 }
217 }
218
219
220 // -----------------------------------------------------------------------------
221 // JSToBoolean
222
223
TEST_F(JSTypedLoweringTest,JSToBooleanWithBoolean)224 TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
225 Node* input = Parameter(Type::Boolean(), 0);
226 Node* context = Parameter(Type::Any(), 1);
227 Reduction r =
228 Reduce(graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
229 input, context, graph()->start()));
230 ASSERT_TRUE(r.Changed());
231 EXPECT_EQ(input, r.replacement());
232 }
233
234
TEST_F(JSTypedLoweringTest,JSToBooleanWithFalsish)235 TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
236 Node* input = Parameter(
237 Type::Union(
238 Type::MinusZero(),
239 Type::Union(
240 Type::NaN(),
241 Type::Union(
242 Type::Null(),
243 Type::Union(
244 Type::Undefined(),
245 Type::Union(
246 Type::Undetectable(),
247 Type::Union(
248 Type::Constant(factory()->false_value(), zone()),
249 Type::Range(0.0, 0.0, zone()), zone()),
250 zone()),
251 zone()),
252 zone()),
253 zone()),
254 zone()),
255 0);
256 Node* context = Parameter(Type::Any(), 1);
257 Reduction r =
258 Reduce(graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
259 input, context, graph()->start()));
260 ASSERT_TRUE(r.Changed());
261 EXPECT_THAT(r.replacement(), IsFalseConstant());
262 }
263
264
TEST_F(JSTypedLoweringTest,JSToBooleanWithTruish)265 TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
266 Node* input = Parameter(
267 Type::Union(
268 Type::Constant(factory()->true_value(), zone()),
269 Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
270 zone()),
271 0);
272 Node* context = Parameter(Type::Any(), 1);
273 Reduction r =
274 Reduce(graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
275 input, context, graph()->start()));
276 ASSERT_TRUE(r.Changed());
277 EXPECT_THAT(r.replacement(), IsTrueConstant());
278 }
279
280
TEST_F(JSTypedLoweringTest,JSToBooleanWithNonZeroPlainNumber)281 TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
282 Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0);
283 Node* context = Parameter(Type::Any(), 1);
284 Reduction r =
285 Reduce(graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
286 input, context, graph()->start()));
287 ASSERT_TRUE(r.Changed());
288 EXPECT_THAT(r.replacement(), IsTrueConstant());
289 }
290
291
TEST_F(JSTypedLoweringTest,JSToBooleanWithOrderedNumber)292 TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) {
293 Node* input = Parameter(Type::OrderedNumber(), 0);
294 Node* context = Parameter(Type::Any(), 1);
295 Reduction r =
296 Reduce(graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
297 input, context, graph()->start()));
298 ASSERT_TRUE(r.Changed());
299 EXPECT_THAT(r.replacement(),
300 IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0))));
301 }
302
303
TEST_F(JSTypedLoweringTest,JSToBooleanWithString)304 TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
305 Node* input = Parameter(Type::String(), 0);
306 Node* context = Parameter(Type::Any(), 1);
307 Reduction r =
308 Reduce(graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
309 input, context, graph()->start()));
310 ASSERT_TRUE(r.Changed());
311 EXPECT_THAT(
312 r.replacement(),
313 IsNumberLessThan(IsNumberConstant(0.0),
314 IsLoadField(AccessBuilder::ForStringLength(), input,
315 graph()->start(), graph()->start())));
316 }
317
318
TEST_F(JSTypedLoweringTest,JSToBooleanWithAny)319 TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
320 Node* input = Parameter(Type::Any(), 0);
321 Node* context = Parameter(Type::Any(), 1);
322 Reduction r =
323 Reduce(graph()->NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
324 input, context, graph()->start()));
325 ASSERT_FALSE(r.Changed());
326 }
327
328
329 // -----------------------------------------------------------------------------
330 // JSToNumber
331
332
TEST_F(JSTypedLoweringTest,JSToNumberWithPlainPrimitive)333 TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
334 Node* const input = Parameter(Type::PlainPrimitive(), 0);
335 Node* const context = Parameter(Type::Any(), 1);
336 Node* const effect = graph()->start();
337 Node* const control = graph()->start();
338 Reduction r =
339 Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
340 EmptyFrameState(), effect, control));
341 ASSERT_TRUE(r.Changed());
342 EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
343 graph()->start(), control));
344 }
345
346
347 // -----------------------------------------------------------------------------
348 // JSToObject
349
350
TEST_F(JSTypedLoweringTest,JSToObjectWithAny)351 TEST_F(JSTypedLoweringTest, JSToObjectWithAny) {
352 Node* const input = Parameter(Type::Any(), 0);
353 Node* const context = Parameter(Type::Any(), 1);
354 Node* const frame_state = EmptyFrameState();
355 Node* const effect = graph()->start();
356 Node* const control = graph()->start();
357 Reduction r = Reduce(graph()->NewNode(javascript()->ToObject(), input,
358 context, frame_state, effect, control));
359 ASSERT_TRUE(r.Changed());
360 EXPECT_THAT(r.replacement(), IsPhi(MachineRepresentation::kTagged, _, _, _));
361 }
362
363
TEST_F(JSTypedLoweringTest,JSToObjectWithReceiver)364 TEST_F(JSTypedLoweringTest, JSToObjectWithReceiver) {
365 Node* const input = Parameter(Type::Receiver(), 0);
366 Node* const context = Parameter(Type::Any(), 1);
367 Node* const frame_state = EmptyFrameState();
368 Node* const effect = graph()->start();
369 Node* const control = graph()->start();
370 Reduction r = Reduce(graph()->NewNode(javascript()->ToObject(), input,
371 context, frame_state, effect, control));
372 ASSERT_TRUE(r.Changed());
373 EXPECT_EQ(input, r.replacement());
374 }
375
376
377 // -----------------------------------------------------------------------------
378 // JSToString
379
380
TEST_F(JSTypedLoweringTest,JSToStringWithBoolean)381 TEST_F(JSTypedLoweringTest, JSToStringWithBoolean) {
382 Node* const input = Parameter(Type::Boolean(), 0);
383 Node* const context = Parameter(Type::Any(), 1);
384 Node* const frame_state = EmptyFrameState();
385 Node* const effect = graph()->start();
386 Node* const control = graph()->start();
387 Reduction r = Reduce(graph()->NewNode(javascript()->ToString(), input,
388 context, frame_state, effect, control));
389 ASSERT_TRUE(r.Changed());
390 EXPECT_THAT(r.replacement(),
391 IsSelect(MachineRepresentation::kTagged, input,
392 IsHeapConstant(factory()->true_string()),
393 IsHeapConstant(factory()->false_string())));
394 }
395
396
397 // -----------------------------------------------------------------------------
398 // JSStrictEqual
399
400
TEST_F(JSTypedLoweringTest,JSStrictEqualWithTheHole)401 TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
402 Node* const the_hole = HeapConstant(factory()->the_hole_value());
403 Node* const context = UndefinedConstant();
404 TRACED_FOREACH(Type*, type, kJSTypes) {
405 Node* const lhs = Parameter(type);
406 Reduction r =
407 Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs, the_hole,
408 context, graph()->start(), graph()->start()));
409 ASSERT_TRUE(r.Changed());
410 EXPECT_THAT(r.replacement(), IsFalseConstant());
411 }
412 }
413
414
TEST_F(JSTypedLoweringTest,JSStrictEqualWithUnique)415 TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
416 Node* const lhs = Parameter(Type::Unique(), 0);
417 Node* const rhs = Parameter(Type::Unique(), 1);
418 Node* const context = Parameter(Type::Any(), 2);
419 Reduction r =
420 Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs, rhs, context,
421 graph()->start(), graph()->start()));
422 ASSERT_TRUE(r.Changed());
423 EXPECT_THAT(r.replacement(), IsReferenceEqual(Type::Unique(), lhs, rhs));
424 }
425
426
427 // -----------------------------------------------------------------------------
428 // JSShiftLeft
429
430
TEST_F(JSTypedLoweringTest,JSShiftLeftWithSigned32AndConstant)431 TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
432 BinaryOperationHints const hints = BinaryOperationHints::Any();
433 Node* const lhs = Parameter(Type::Signed32());
434 Node* const context = UndefinedConstant();
435 Node* const effect = graph()->start();
436 Node* const control = graph()->start();
437 TRACED_FORRANGE(double, rhs, 0, 31) {
438 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
439 Reduction r = Reduce(
440 graph()->NewNode(javascript()->ShiftLeft(language_mode, hints), lhs,
441 NumberConstant(rhs), context, EmptyFrameState(),
442 EmptyFrameState(), effect, control));
443 ASSERT_TRUE(r.Changed());
444 EXPECT_THAT(r.replacement(),
445 IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs))));
446 }
447 }
448 }
449
450
TEST_F(JSTypedLoweringTest,JSShiftLeftWithSigned32AndUnsigned32)451 TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
452 BinaryOperationHints const hints = BinaryOperationHints::Any();
453 Node* const lhs = Parameter(Type::Signed32());
454 Node* const rhs = Parameter(Type::Unsigned32());
455 Node* const context = UndefinedConstant();
456 Node* const effect = graph()->start();
457 Node* const control = graph()->start();
458 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
459 Reduction r = Reduce(graph()->NewNode(
460 javascript()->ShiftLeft(language_mode, hints), lhs, rhs, context,
461 EmptyFrameState(), EmptyFrameState(), effect, control));
462 ASSERT_TRUE(r.Changed());
463 EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs));
464 }
465 }
466
467
468 // -----------------------------------------------------------------------------
469 // JSShiftRight
470
471
TEST_F(JSTypedLoweringTest,JSShiftRightWithSigned32AndConstant)472 TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
473 BinaryOperationHints const hints = BinaryOperationHints::Any();
474 Node* const lhs = Parameter(Type::Signed32());
475 Node* const context = UndefinedConstant();
476 Node* const effect = graph()->start();
477 Node* const control = graph()->start();
478 TRACED_FORRANGE(double, rhs, 0, 31) {
479 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
480 Reduction r = Reduce(
481 graph()->NewNode(javascript()->ShiftRight(language_mode, hints), lhs,
482 NumberConstant(rhs), context, EmptyFrameState(),
483 EmptyFrameState(), effect, control));
484 ASSERT_TRUE(r.Changed());
485 EXPECT_THAT(r.replacement(),
486 IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs))));
487 }
488 }
489 }
490
491
TEST_F(JSTypedLoweringTest,JSShiftRightWithSigned32AndUnsigned32)492 TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
493 BinaryOperationHints const hints = BinaryOperationHints::Any();
494 Node* const lhs = Parameter(Type::Signed32());
495 Node* const rhs = Parameter(Type::Unsigned32());
496 Node* const context = UndefinedConstant();
497 Node* const effect = graph()->start();
498 Node* const control = graph()->start();
499 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
500 Reduction r = Reduce(graph()->NewNode(
501 javascript()->ShiftRight(language_mode, hints), lhs, rhs, context,
502 EmptyFrameState(), EmptyFrameState(), effect, control));
503 ASSERT_TRUE(r.Changed());
504 EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs));
505 }
506 }
507
508
509 // -----------------------------------------------------------------------------
510 // JSShiftRightLogical
511
512
TEST_F(JSTypedLoweringTest,JSShiftRightLogicalWithUnsigned32AndConstant)513 TEST_F(JSTypedLoweringTest,
514 JSShiftRightLogicalWithUnsigned32AndConstant) {
515 BinaryOperationHints const hints = BinaryOperationHints::Any();
516 Node* const lhs = Parameter(Type::Unsigned32());
517 Node* const context = UndefinedConstant();
518 Node* const effect = graph()->start();
519 Node* const control = graph()->start();
520 TRACED_FORRANGE(double, rhs, 0, 31) {
521 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
522 Reduction r = Reduce(graph()->NewNode(
523 javascript()->ShiftRightLogical(language_mode, hints), lhs,
524 NumberConstant(rhs), context, EmptyFrameState(), EmptyFrameState(),
525 effect, control));
526 ASSERT_TRUE(r.Changed());
527 EXPECT_THAT(r.replacement(),
528 IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs))));
529 }
530 }
531 }
532
533
TEST_F(JSTypedLoweringTest,JSShiftRightLogicalWithUnsigned32AndUnsigned32)534 TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
535 BinaryOperationHints const hints = BinaryOperationHints::Any();
536 Node* const lhs = Parameter(Type::Unsigned32());
537 Node* const rhs = Parameter(Type::Unsigned32());
538 Node* const context = UndefinedConstant();
539 Node* const effect = graph()->start();
540 Node* const control = graph()->start();
541 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
542 Reduction r = Reduce(graph()->NewNode(
543 javascript()->ShiftRightLogical(language_mode, hints), lhs, rhs,
544 context, EmptyFrameState(), EmptyFrameState(), effect, control));
545 ASSERT_TRUE(r.Changed());
546 EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs));
547 }
548 }
549
550
551 // -----------------------------------------------------------------------------
552 // JSLoadContext
553
554
TEST_F(JSTypedLoweringTest,JSLoadContext)555 TEST_F(JSTypedLoweringTest, JSLoadContext) {
556 Node* const context = Parameter(Type::Any());
557 Node* const effect = graph()->start();
558 static bool kBooleans[] = {false, true};
559 TRACED_FOREACH(size_t, index, kIndices) {
560 TRACED_FOREACH(bool, immutable, kBooleans) {
561 Reduction const r1 = Reduce(
562 graph()->NewNode(javascript()->LoadContext(0, index, immutable),
563 context, context, effect));
564 ASSERT_TRUE(r1.Changed());
565 EXPECT_THAT(r1.replacement(),
566 IsLoadField(AccessBuilder::ForContextSlot(index), context,
567 effect, graph()->start()));
568
569 Reduction const r2 = Reduce(
570 graph()->NewNode(javascript()->LoadContext(1, index, immutable),
571 context, context, effect));
572 ASSERT_TRUE(r2.Changed());
573 EXPECT_THAT(r2.replacement(),
574 IsLoadField(AccessBuilder::ForContextSlot(index),
575 IsLoadField(AccessBuilder::ForContextSlot(
576 Context::PREVIOUS_INDEX),
577 context, effect, graph()->start()),
578 _, graph()->start()));
579 }
580 }
581 }
582
583
584 // -----------------------------------------------------------------------------
585 // JSStoreContext
586
587
TEST_F(JSTypedLoweringTest,JSStoreContext)588 TEST_F(JSTypedLoweringTest, JSStoreContext) {
589 Node* const context = Parameter(Type::Any());
590 Node* const effect = graph()->start();
591 Node* const control = graph()->start();
592 TRACED_FOREACH(size_t, index, kIndices) {
593 TRACED_FOREACH(Type*, type, kJSTypes) {
594 Node* const value = Parameter(type);
595
596 Reduction const r1 =
597 Reduce(graph()->NewNode(javascript()->StoreContext(0, index), context,
598 value, context, effect, control));
599 ASSERT_TRUE(r1.Changed());
600 EXPECT_THAT(r1.replacement(),
601 IsStoreField(AccessBuilder::ForContextSlot(index), context,
602 value, effect, control));
603
604 Reduction const r2 =
605 Reduce(graph()->NewNode(javascript()->StoreContext(1, index), context,
606 value, context, effect, control));
607 ASSERT_TRUE(r2.Changed());
608 EXPECT_THAT(r2.replacement(),
609 IsStoreField(AccessBuilder::ForContextSlot(index),
610 IsLoadField(AccessBuilder::ForContextSlot(
611 Context::PREVIOUS_INDEX),
612 context, effect, graph()->start()),
613 value, _, control));
614 }
615 }
616 }
617
618
619 // -----------------------------------------------------------------------------
620 // JSLoadProperty
621
622
TEST_F(JSTypedLoweringTest,JSLoadPropertyFromExternalTypedArray)623 TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
624 const size_t kLength = 17;
625 double backing_store[kLength];
626 Handle<JSArrayBuffer> buffer =
627 NewArrayBuffer(backing_store, sizeof(backing_store));
628 VectorSlotPair feedback;
629 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
630 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
631 Handle<JSTypedArray> array =
632 factory()->NewJSTypedArray(type, buffer, 0, kLength);
633 int const element_size = static_cast<int>(array->element_size());
634
635 Node* key = Parameter(
636 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
637 Node* base = HeapConstant(array);
638 Node* vector = UndefinedConstant();
639 Node* context = UndefinedConstant();
640 Node* effect = graph()->start();
641 Node* control = graph()->start();
642 Reduction r = Reduce(
643 graph()->NewNode(javascript()->LoadProperty(language_mode, feedback),
644 base, key, vector, context, EmptyFrameState(),
645 EmptyFrameState(), effect, control));
646
647 Matcher<Node*> offset_matcher =
648 element_size == 1
649 ? key
650 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
651
652 ASSERT_TRUE(r.Changed());
653 EXPECT_THAT(
654 r.replacement(),
655 IsLoadBuffer(BufferAccess(type),
656 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
657 offset_matcher,
658 IsNumberConstant(array->byte_length()->Number()), effect,
659 control));
660 }
661 }
662 }
663
664
TEST_F(JSTypedLoweringTest,JSLoadPropertyFromExternalTypedArrayWithSafeKey)665 TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
666 const size_t kLength = 17;
667 double backing_store[kLength];
668 Handle<JSArrayBuffer> buffer =
669 NewArrayBuffer(backing_store, sizeof(backing_store));
670 VectorSlotPair feedback;
671 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
672 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
673 Handle<JSTypedArray> array =
674 factory()->NewJSTypedArray(type, buffer, 0, kLength);
675 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
676
677 int min = random_number_generator()->NextInt(static_cast<int>(kLength));
678 int max = random_number_generator()->NextInt(static_cast<int>(kLength));
679 if (min > max) std::swap(min, max);
680 Node* key = Parameter(Type::Range(min, max, zone()));
681 Node* base = HeapConstant(array);
682 Node* vector = UndefinedConstant();
683 Node* context = UndefinedConstant();
684 Node* effect = graph()->start();
685 Node* control = graph()->start();
686 Reduction r = Reduce(
687 graph()->NewNode(javascript()->LoadProperty(language_mode, feedback),
688 base, key, vector, context, EmptyFrameState(),
689 EmptyFrameState(), effect, control));
690
691 ASSERT_TRUE(r.Changed());
692 EXPECT_THAT(
693 r.replacement(),
694 IsLoadElement(access,
695 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
696 key, effect, control));
697 }
698 }
699 }
700
701
702 // -----------------------------------------------------------------------------
703 // JSStoreProperty
704
705
TEST_F(JSTypedLoweringTest,JSStorePropertyToExternalTypedArray)706 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
707 const size_t kLength = 17;
708 double backing_store[kLength];
709 Handle<JSArrayBuffer> buffer =
710 NewArrayBuffer(backing_store, sizeof(backing_store));
711 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
712 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
713 Handle<JSTypedArray> array =
714 factory()->NewJSTypedArray(type, buffer, 0, kLength);
715 int const element_size = static_cast<int>(array->element_size());
716
717 Node* key = Parameter(
718 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
719 Node* base = HeapConstant(array);
720 Node* value =
721 Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
722 Node* vector = UndefinedConstant();
723 Node* context = UndefinedConstant();
724 Node* effect = graph()->start();
725 Node* control = graph()->start();
726 VectorSlotPair feedback;
727 const Operator* op = javascript()->StoreProperty(language_mode, feedback);
728 Node* node = graph()->NewNode(op, base, key, value, vector, context,
729 EmptyFrameState(), EmptyFrameState(),
730 effect, control);
731 Reduction r = Reduce(node);
732
733 Matcher<Node*> offset_matcher =
734 element_size == 1
735 ? key
736 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
737
738 ASSERT_TRUE(r.Changed());
739 EXPECT_THAT(
740 r.replacement(),
741 IsStoreBuffer(BufferAccess(type),
742 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
743 offset_matcher,
744 IsNumberConstant(array->byte_length()->Number()), value,
745 effect, control));
746 }
747 }
748 }
749
750
TEST_F(JSTypedLoweringTest,JSStorePropertyToExternalTypedArrayWithConversion)751 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
752 const size_t kLength = 17;
753 double backing_store[kLength];
754 Handle<JSArrayBuffer> buffer =
755 NewArrayBuffer(backing_store, sizeof(backing_store));
756 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
757 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
758 Handle<JSTypedArray> array =
759 factory()->NewJSTypedArray(type, buffer, 0, kLength);
760 int const element_size = static_cast<int>(array->element_size());
761
762 Node* key = Parameter(
763 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
764 Node* base = HeapConstant(array);
765 Node* value = Parameter(Type::Any());
766 Node* vector = UndefinedConstant();
767 Node* context = UndefinedConstant();
768 Node* effect = graph()->start();
769 Node* control = graph()->start();
770 VectorSlotPair feedback;
771 const Operator* op = javascript()->StoreProperty(language_mode, feedback);
772 Node* node = graph()->NewNode(op, base, key, value, vector, context,
773 EmptyFrameState(), EmptyFrameState(),
774 effect, control);
775 Reduction r = Reduce(node);
776
777 Matcher<Node*> offset_matcher =
778 element_size == 1
779 ? key
780 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
781
782 Matcher<Node*> value_matcher =
783 IsToNumber(value, context, effect, control);
784 Matcher<Node*> effect_matcher = value_matcher;
785
786 ASSERT_TRUE(r.Changed());
787 EXPECT_THAT(
788 r.replacement(),
789 IsStoreBuffer(BufferAccess(type),
790 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
791 offset_matcher,
792 IsNumberConstant(array->byte_length()->Number()),
793 value_matcher, effect_matcher, control));
794 }
795 }
796 }
797
798
TEST_F(JSTypedLoweringTest,JSStorePropertyToExternalTypedArrayWithSafeKey)799 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
800 const size_t kLength = 17;
801 double backing_store[kLength];
802 Handle<JSArrayBuffer> buffer =
803 NewArrayBuffer(backing_store, sizeof(backing_store));
804 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
805 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
806 Handle<JSTypedArray> array =
807 factory()->NewJSTypedArray(type, buffer, 0, kLength);
808 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
809
810 int min = random_number_generator()->NextInt(static_cast<int>(kLength));
811 int max = random_number_generator()->NextInt(static_cast<int>(kLength));
812 if (min > max) std::swap(min, max);
813 Node* key = Parameter(Type::Range(min, max, zone()));
814 Node* base = HeapConstant(array);
815 Node* value = Parameter(access.type);
816 Node* vector = UndefinedConstant();
817 Node* context = UndefinedConstant();
818 Node* effect = graph()->start();
819 Node* control = graph()->start();
820 VectorSlotPair feedback;
821 const Operator* op = javascript()->StoreProperty(language_mode, feedback);
822 Node* node = graph()->NewNode(op, base, key, value, vector, context,
823 EmptyFrameState(), EmptyFrameState(),
824 effect, control);
825 Reduction r = Reduce(node);
826
827 ASSERT_TRUE(r.Changed());
828 EXPECT_THAT(
829 r.replacement(),
830 IsStoreElement(
831 access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
832 key, value, effect, control));
833 }
834 }
835 }
836
837
838 // -----------------------------------------------------------------------------
839 // JSLoadNamed
840
841
TEST_F(JSTypedLoweringTest,JSLoadNamedStringLength)842 TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) {
843 VectorSlotPair feedback;
844 Handle<Name> name = factory()->length_string();
845 Node* const receiver = Parameter(Type::String(), 0);
846 Node* const vector = Parameter(Type::Internal(), 1);
847 Node* const context = UndefinedConstant();
848 Node* const effect = graph()->start();
849 Node* const control = graph()->start();
850 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
851 Reduction const r = Reduce(
852 graph()->NewNode(javascript()->LoadNamed(language_mode, name, feedback),
853 receiver, vector, context, EmptyFrameState(),
854 EmptyFrameState(), effect, control));
855 ASSERT_TRUE(r.Changed());
856 EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(),
857 receiver, effect, control));
858 }
859 }
860
861
TEST_F(JSTypedLoweringTest,JSLoadNamedFunctionPrototype)862 TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) {
863 VectorSlotPair feedback;
864 Handle<Name> name = factory()->prototype_string();
865 Handle<JSFunction> function = isolate()->object_function();
866 Handle<JSObject> function_prototype(JSObject::cast(function->prototype()));
867 Node* const receiver = Parameter(Type::Constant(function, zone()), 0);
868 Node* const vector = Parameter(Type::Internal(), 1);
869 Node* const context = Parameter(Type::Internal(), 2);
870 Node* const effect = graph()->start();
871 Node* const control = graph()->start();
872 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
873 Reduction const r = Reduce(
874 graph()->NewNode(javascript()->LoadNamed(language_mode, name, feedback),
875 receiver, vector, context, EmptyFrameState(),
876 EmptyFrameState(), effect, control));
877 ASSERT_TRUE(r.Changed());
878 EXPECT_THAT(r.replacement(), IsHeapConstant(function_prototype));
879 }
880 }
881
882
883 // -----------------------------------------------------------------------------
884 // JSAdd
885
886
TEST_F(JSTypedLoweringTest,JSAddWithString)887 TEST_F(JSTypedLoweringTest, JSAddWithString) {
888 BinaryOperationHints const hints = BinaryOperationHints::Any();
889 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
890 Node* lhs = Parameter(Type::String(), 0);
891 Node* rhs = Parameter(Type::String(), 1);
892 Node* context = Parameter(Type::Any(), 2);
893 Node* frame_state0 = EmptyFrameState();
894 Node* frame_state1 = EmptyFrameState();
895 Node* effect = graph()->start();
896 Node* control = graph()->start();
897 Reduction r = Reduce(
898 graph()->NewNode(javascript()->Add(language_mode, hints), lhs, rhs,
899 context, frame_state0, frame_state1, effect, control));
900 ASSERT_TRUE(r.Changed());
901 EXPECT_THAT(r.replacement(),
902 IsCall(_, IsHeapConstant(CodeFactory::StringAdd(
903 isolate(), STRING_ADD_CHECK_NONE,
904 NOT_TENURED).code()),
905 lhs, rhs, context, frame_state0, effect, control));
906 }
907 }
908
909
910 // -----------------------------------------------------------------------------
911 // JSCreate
912
913
TEST_F(JSTypedLoweringTest,JSCreate)914 TEST_F(JSTypedLoweringTest, JSCreate) {
915 Handle<JSFunction> function = isolate()->object_function();
916 Node* const target = Parameter(Type::Constant(function, graph()->zone()));
917 Node* const context = Parameter(Type::Any());
918 Node* const effect = graph()->start();
919 Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target,
920 context, EmptyFrameState(), effect));
921 ASSERT_TRUE(r.Changed());
922 EXPECT_THAT(
923 r.replacement(),
924 IsFinishRegion(
925 IsAllocate(IsNumberConstant(function->initial_map()->instance_size()),
926 IsBeginRegion(effect), _),
927 _));
928 }
929
930
931 // -----------------------------------------------------------------------------
932 // JSCreateArguments
933
934
TEST_F(JSTypedLoweringTest,JSCreateArgumentsViaStub)935 TEST_F(JSTypedLoweringTest, JSCreateArgumentsViaStub) {
936 Node* const closure = Parameter(Type::Any());
937 Node* const context = UndefinedConstant();
938 Node* const effect = graph()->start();
939 Node* const control = graph()->start();
940 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
941 Node* const frame_state = FrameState(shared, graph()->start());
942 Reduction r = Reduce(
943 graph()->NewNode(javascript()->CreateArguments(
944 CreateArgumentsParameters::kMappedArguments, 0),
945 closure, context, frame_state, effect, control));
946 ASSERT_TRUE(r.Changed());
947 EXPECT_THAT(r.replacement(),
948 IsCall(_, IsHeapConstant(CodeFactory::ArgumentsAccess(
949 isolate(), false, false)
950 .code()),
951 closure, IsNumberConstant(0), _, effect, control));
952 }
953
954
TEST_F(JSTypedLoweringTest,JSCreateArgumentsRestArrayViaStub)955 TEST_F(JSTypedLoweringTest, JSCreateArgumentsRestArrayViaStub) {
956 Node* const closure = Parameter(Type::Any());
957 Node* const context = UndefinedConstant();
958 Node* const effect = graph()->start();
959 Node* const control = graph()->start();
960 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
961 Node* const frame_state = FrameState(shared, graph()->start());
962 Reduction r = Reduce(graph()->NewNode(
963 javascript()->CreateArguments(CreateArgumentsParameters::kRestArray, 0),
964 closure, context, frame_state, effect, control));
965 ASSERT_TRUE(r.Changed());
966 EXPECT_THAT(
967 r.replacement(),
968 IsCall(_,
969 IsHeapConstant(CodeFactory::RestArgumentsAccess(isolate()).code()),
970 IsNumberConstant(0), _, IsNumberConstant(0), _, effect, control));
971 }
972
973
TEST_F(JSTypedLoweringTest,JSCreateArgumentsInlinedMapped)974 TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedMapped) {
975 Node* const closure = Parameter(Type::Any());
976 Node* const context = UndefinedConstant();
977 Node* const effect = graph()->start();
978 Node* const control = graph()->start();
979 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
980 Node* const frame_state_outer = FrameState(shared, graph()->start());
981 Node* const frame_state_inner = FrameState(shared, frame_state_outer);
982 Reduction r = Reduce(
983 graph()->NewNode(javascript()->CreateArguments(
984 CreateArgumentsParameters::kMappedArguments, 0),
985 closure, context, frame_state_inner, effect, control));
986 ASSERT_TRUE(r.Changed());
987 EXPECT_THAT(r.replacement(),
988 IsFinishRegion(
989 IsAllocate(IsNumberConstant(Heap::kSloppyArgumentsObjectSize),
990 _, control),
991 _));
992 }
993
994
TEST_F(JSTypedLoweringTest,JSCreateArgumentsInlinedUnmapped)995 TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedUnmapped) {
996 Node* const closure = Parameter(Type::Any());
997 Node* const context = UndefinedConstant();
998 Node* const effect = graph()->start();
999 Node* const control = graph()->start();
1000 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
1001 Node* const frame_state_outer = FrameState(shared, graph()->start());
1002 Node* const frame_state_inner = FrameState(shared, frame_state_outer);
1003 Reduction r = Reduce(
1004 graph()->NewNode(javascript()->CreateArguments(
1005 CreateArgumentsParameters::kUnmappedArguments, 0),
1006 closure, context, frame_state_inner, effect, control));
1007 ASSERT_TRUE(r.Changed());
1008 EXPECT_THAT(r.replacement(),
1009 IsFinishRegion(
1010 IsAllocate(IsNumberConstant(Heap::kStrictArgumentsObjectSize),
1011 _, control),
1012 _));
1013 }
1014
1015
TEST_F(JSTypedLoweringTest,JSCreateArgumentsInlinedRestArray)1016 TEST_F(JSTypedLoweringTest, JSCreateArgumentsInlinedRestArray) {
1017 Node* const closure = Parameter(Type::Any());
1018 Node* const context = UndefinedConstant();
1019 Node* const effect = graph()->start();
1020 Node* const control = graph()->start();
1021 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
1022 Node* const frame_state_outer = FrameState(shared, graph()->start());
1023 Node* const frame_state_inner = FrameState(shared, frame_state_outer);
1024 Reduction r = Reduce(graph()->NewNode(
1025 javascript()->CreateArguments(CreateArgumentsParameters::kRestArray, 0),
1026 closure, context, frame_state_inner, effect, control));
1027 ASSERT_TRUE(r.Changed());
1028 EXPECT_THAT(r.replacement(),
1029 IsFinishRegion(
1030 IsAllocate(IsNumberConstant(JSArray::kSize), _, control), _));
1031 }
1032
1033
1034 // -----------------------------------------------------------------------------
1035 // JSCreateClosure
1036
1037
TEST_F(JSTypedLoweringTest,JSCreateClosure)1038 TEST_F(JSTypedLoweringTest, JSCreateClosure) {
1039 Node* const context = UndefinedConstant();
1040 Node* const effect = graph()->start();
1041 Node* const control = graph()->start();
1042 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
1043 Reduction r =
1044 Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED),
1045 context, effect, control));
1046 ASSERT_TRUE(r.Changed());
1047 EXPECT_THAT(r.replacement(),
1048 IsCall(_, IsHeapConstant(CodeFactory::FastNewClosure(
1049 isolate(), shared->language_mode(),
1050 shared->kind()).code()),
1051 IsHeapConstant(shared), effect, control));
1052 }
1053
1054
1055 // -----------------------------------------------------------------------------
1056 // JSCreateLiteralArray
1057
1058
TEST_F(JSTypedLoweringTest,JSCreateLiteralArray)1059 TEST_F(JSTypedLoweringTest, JSCreateLiteralArray) {
1060 Handle<FixedArray> const constant_elements = factory()->NewFixedArray(12);
1061 int const literal_flags = ArrayLiteral::kShallowElements;
1062 int const literal_index = 1;
1063 Node* const closure = Parameter(0);
1064 Node* const context = Parameter(1);
1065 Node* const frame_state = EmptyFrameState();
1066 Node* const effect = graph()->start();
1067 Node* const control = graph()->start();
1068 Reduction const r = Reduce(
1069 graph()->NewNode(javascript()->CreateLiteralArray(
1070 constant_elements, literal_flags, literal_index),
1071 closure, context, frame_state, effect, control));
1072 ASSERT_TRUE(r.Changed());
1073 EXPECT_THAT(
1074 r.replacement(),
1075 IsCall(_, IsHeapConstant(
1076 CodeFactory::FastCloneShallowArray(isolate()).code()),
1077 closure, IsNumberConstant(literal_index),
1078 IsHeapConstant(constant_elements), context, frame_state, effect,
1079 control));
1080 }
1081
1082
1083 // -----------------------------------------------------------------------------
1084 // JSCreateLiteralObject
1085
1086
TEST_F(JSTypedLoweringTest,JSCreateLiteralObject)1087 TEST_F(JSTypedLoweringTest, JSCreateLiteralObject) {
1088 Handle<FixedArray> const constant_properties =
1089 factory()->NewFixedArray(6 * 2);
1090 int const literal_flags = ObjectLiteral::kShallowProperties;
1091 int const literal_index = 1;
1092 Node* const closure = Parameter(0);
1093 Node* const context = Parameter(1);
1094 Node* const frame_state = EmptyFrameState();
1095 Node* const effect = graph()->start();
1096 Node* const control = graph()->start();
1097 Reduction const r = Reduce(
1098 graph()->NewNode(javascript()->CreateLiteralObject(
1099 constant_properties, literal_flags, literal_index),
1100 closure, context, frame_state, effect, control));
1101 ASSERT_TRUE(r.Changed());
1102 EXPECT_THAT(
1103 r.replacement(),
1104 IsCall(_, IsHeapConstant(
1105 CodeFactory::FastCloneShallowObject(isolate(), 6).code()),
1106 closure, IsNumberConstant(literal_index),
1107 IsHeapConstant(constant_properties), _, context, frame_state,
1108 effect, control));
1109 }
1110
1111
1112 // -----------------------------------------------------------------------------
1113 // JSCreateFunctionContext
1114
1115
TEST_F(JSTypedLoweringTest,JSCreateFunctionContextViaInlinedAllocation)1116 TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaInlinedAllocation) {
1117 Node* const closure = Parameter(Type::Any());
1118 Node* const context = Parameter(Type::Any());
1119 Node* const effect = graph()->start();
1120 Node* const control = graph()->start();
1121 Reduction const r =
1122 Reduce(graph()->NewNode(javascript()->CreateFunctionContext(8), closure,
1123 context, effect, control));
1124 ASSERT_TRUE(r.Changed());
1125 EXPECT_THAT(r.replacement(),
1126 IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
1127 8 + Context::MIN_CONTEXT_SLOTS)),
1128 IsBeginRegion(_), control),
1129 _));
1130 }
1131
1132
TEST_F(JSTypedLoweringTest,JSCreateFunctionContextViaStub)1133 TEST_F(JSTypedLoweringTest, JSCreateFunctionContextViaStub) {
1134 Node* const closure = Parameter(Type::Any());
1135 Node* const context = Parameter(Type::Any());
1136 Node* const effect = graph()->start();
1137 Node* const control = graph()->start();
1138 Reduction const r =
1139 Reduce(graph()->NewNode(javascript()->CreateFunctionContext(32), closure,
1140 context, effect, control));
1141 ASSERT_TRUE(r.Changed());
1142 EXPECT_THAT(r.replacement(),
1143 IsCall(_, IsHeapConstant(
1144 CodeFactory::FastNewContext(isolate(), 32).code()),
1145 closure, context, effect, control));
1146 }
1147
1148
1149 // -----------------------------------------------------------------------------
1150 // JSCreateWithContext
1151
1152
TEST_F(JSTypedLoweringTest,JSCreateWithContext)1153 TEST_F(JSTypedLoweringTest, JSCreateWithContext) {
1154 Node* const object = Parameter(Type::Receiver());
1155 Node* const closure = Parameter(Type::Function());
1156 Node* const context = Parameter(Type::Any());
1157 Node* const effect = graph()->start();
1158 Node* const control = graph()->start();
1159 Reduction r =
1160 Reduce(graph()->NewNode(javascript()->CreateWithContext(), object,
1161 closure, context, effect, control));
1162 ASSERT_TRUE(r.Changed());
1163 EXPECT_THAT(r.replacement(),
1164 IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
1165 Context::MIN_CONTEXT_SLOTS)),
1166 IsBeginRegion(_), control),
1167 _));
1168 }
1169
1170
1171 // -----------------------------------------------------------------------------
1172 // JSCreateCatchContext
1173
1174
TEST_F(JSTypedLoweringTest,JSCreateCatchContext)1175 TEST_F(JSTypedLoweringTest, JSCreateCatchContext) {
1176 Handle<String> name = factory()->length_string();
1177 Node* const exception = Parameter(Type::Receiver());
1178 Node* const closure = Parameter(Type::Function());
1179 Node* const context = Parameter(Type::Any());
1180 Node* const effect = graph()->start();
1181 Node* const control = graph()->start();
1182 Reduction r =
1183 Reduce(graph()->NewNode(javascript()->CreateCatchContext(name), exception,
1184 closure, context, effect, control));
1185 ASSERT_TRUE(r.Changed());
1186 EXPECT_THAT(r.replacement(),
1187 IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
1188 Context::MIN_CONTEXT_SLOTS + 1)),
1189 IsBeginRegion(_), control),
1190 _));
1191 }
1192
1193
1194 // -----------------------------------------------------------------------------
1195 // JSInstanceOf
1196 // Test that instanceOf is reduced if and only if the right-hand side is a
1197 // function constant. Functional correctness is ensured elsewhere.
1198
1199
TEST_F(JSTypedLoweringTest,JSInstanceOfSpecializationWithoutSmiCheck)1200 TEST_F(JSTypedLoweringTest, JSInstanceOfSpecializationWithoutSmiCheck) {
1201 Node* const context = Parameter(Type::Any());
1202 Node* const frame_state = EmptyFrameState();
1203 Node* const effect = graph()->start();
1204 Node* const control = graph()->start();
1205
1206 // Reduce if left-hand side is known to be an object.
1207 Node* instanceOf =
1208 graph()->NewNode(javascript()->InstanceOf(), Parameter(Type::Object(), 0),
1209 HeapConstant(isolate()->object_function()), context,
1210 frame_state, effect, control);
1211 Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context,
1212 frame_state, effect, control);
1213 Reduction r = Reduce(instanceOf);
1214 ASSERT_TRUE(r.Changed());
1215 ASSERT_EQ(r.replacement(), dummy->InputAt(0));
1216 ASSERT_NE(instanceOf, dummy->InputAt(0));
1217 }
1218
1219
TEST_F(JSTypedLoweringTest,JSInstanceOfSpecializationWithSmiCheck)1220 TEST_F(JSTypedLoweringTest, JSInstanceOfSpecializationWithSmiCheck) {
1221 Node* const context = Parameter(Type::Any());
1222 Node* const frame_state = EmptyFrameState();
1223 Node* const effect = graph()->start();
1224 Node* const control = graph()->start();
1225
1226 // Reduce if left-hand side could be a Smi.
1227 Node* instanceOf =
1228 graph()->NewNode(javascript()->InstanceOf(), Parameter(Type::Any(), 0),
1229 HeapConstant(isolate()->object_function()), context,
1230 frame_state, effect, control);
1231 Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context,
1232 frame_state, effect, control);
1233 Reduction r = Reduce(instanceOf);
1234 ASSERT_TRUE(r.Changed());
1235 ASSERT_EQ(r.replacement(), dummy->InputAt(0));
1236 ASSERT_NE(instanceOf, dummy->InputAt(0));
1237 }
1238
1239
TEST_F(JSTypedLoweringTest,JSInstanceOfNoSpecialization)1240 TEST_F(JSTypedLoweringTest, JSInstanceOfNoSpecialization) {
1241 Node* const context = Parameter(Type::Any());
1242 Node* const frame_state = EmptyFrameState();
1243 Node* const effect = graph()->start();
1244 Node* const control = graph()->start();
1245
1246 // Do not reduce if right-hand side is not a function constant.
1247 Node* instanceOf = graph()->NewNode(
1248 javascript()->InstanceOf(), Parameter(Type::Any(), 0),
1249 Parameter(Type::Any()), context, frame_state, effect, control);
1250 Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context,
1251 frame_state, effect, control);
1252 Reduction r = Reduce(instanceOf);
1253 ASSERT_FALSE(r.Changed());
1254 ASSERT_EQ(instanceOf, dummy->InputAt(0));
1255 }
1256
1257 } // namespace compiler
1258 } // namespace internal
1259 } // namespace v8
1260