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