blob: 904d5f7406d028dac6e9a186c17c0b98b0061656 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/code-factory.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006#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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/compiler/node-properties.h"
12#include "src/compiler/operator-properties.h"
13#include "src/isolate-inl.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014#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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019using testing::_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020using testing::BitEq;
21using testing::IsNaN;
22
23
24namespace v8 {
25namespace internal {
26namespace compiler {
27
28namespace {
29
30const ExternalArrayType kExternalArrayTypes[] = {
31 kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
32 kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
33 kExternalFloat32Array, kExternalFloat64Array};
34
35
36const 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
57const size_t kIndices[] = {0, 1, 42, 100, 1024};
58
59
60const 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
65Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
66 Type::Number(), Type::String(), Type::Object()};
67
68
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069STATIC_ASSERT(LANGUAGE_END == 3);
Ben Murdochda12d292016-06-02 14:46:10 +010070const LanguageMode kLanguageModes[] = {SLOPPY, STRICT};
Emily Bernierd0a1eb72015-03-24 16:35:39 -040071
72} // namespace
73
74
75class JSTypedLoweringTest : public TypedGraphTest {
76 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 JSTypedLoweringTest()
78 : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {}
79 ~JSTypedLoweringTest() override {}
Emily Bernierd0a1eb72015-03-24 16:35:39 -040080
81 protected:
82 Reduction Reduce(Node* node) {
83 MachineOperatorBuilder machine(zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084 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());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040092 return reducer.Reduce(node);
93 }
94
95 Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
96 Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000097 JSArrayBuffer::Setup(buffer, isolate(), true, bytes, byte_length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098 return buffer;
99 }
100
101 Matcher<Node*> IsIntPtrConstant(intptr_t value) {
102 return sizeof(value) == 4 ? IsInt32Constant(static_cast<int32_t>(value))
103 : IsInt64Constant(static_cast<int64_t>(value));
104 }
105
106 JSOperatorBuilder* javascript() { return &javascript_; }
107
108 private:
109 JSOperatorBuilder javascript_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 CompilationDependencies deps_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400111};
112
113
114// -----------------------------------------------------------------------------
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400115// Constant propagation
116
117
118TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
119 {
120 Reduction r = Reduce(
121 Parameter(Type::Constant(factory()->minus_zero_value(), zone())));
122 ASSERT_TRUE(r.Changed());
123 EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
124 }
125 {
126 Reduction r = Reduce(Parameter(Type::MinusZero()));
127 ASSERT_TRUE(r.Changed());
128 EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
129 }
130 {
131 Reduction r = Reduce(Parameter(
132 Type::Union(Type::MinusZero(),
133 Type::Constant(factory()->NewNumber(0), zone()), zone())));
134 EXPECT_FALSE(r.Changed());
135 }
136}
137
138
139TEST_F(JSTypedLoweringTest, ParameterWithNull) {
140 Handle<HeapObject> null = factory()->null_value();
141 {
142 Reduction r = Reduce(Parameter(Type::Constant(null, zone())));
143 ASSERT_TRUE(r.Changed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144 EXPECT_THAT(r.replacement(), IsHeapConstant(null));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400145 }
146 {
147 Reduction r = Reduce(Parameter(Type::Null()));
148 ASSERT_TRUE(r.Changed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000149 EXPECT_THAT(r.replacement(), IsHeapConstant(null));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150 }
151}
152
153
154TEST_F(JSTypedLoweringTest, ParameterWithNaN) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400156 std::numeric_limits<double>::quiet_NaN(),
157 std::numeric_limits<double>::signaling_NaN()};
158 TRACED_FOREACH(double, nan, kNaNs) {
159 Handle<Object> constant = factory()->NewNumber(nan);
160 Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
161 ASSERT_TRUE(r.Changed());
162 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
163 }
164 {
165 Reduction r =
166 Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
167 ASSERT_TRUE(r.Changed());
168 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
169 }
170 {
171 Reduction r = Reduce(Parameter(Type::NaN()));
172 ASSERT_TRUE(r.Changed());
173 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
174 }
175}
176
177
178TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
179 TRACED_FOREACH(double, value, kFloat64Values) {
180 Handle<Object> constant = factory()->NewNumber(value);
181 Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
182 ASSERT_TRUE(r.Changed());
183 EXPECT_THAT(r.replacement(), IsNumberConstant(value));
184 }
185 TRACED_FOREACH(double, value, kIntegerValues) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 Reduction r = Reduce(Parameter(Type::Range(value, value, zone())));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400187 ASSERT_TRUE(r.Changed());
188 EXPECT_THAT(r.replacement(), IsNumberConstant(value));
189 }
190}
191
192
193TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
194 Handle<HeapObject> undefined = factory()->undefined_value();
195 {
196 Reduction r = Reduce(Parameter(Type::Undefined()));
197 ASSERT_TRUE(r.Changed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 EXPECT_THAT(r.replacement(), IsHeapConstant(undefined));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400199 }
200 {
201 Reduction r = Reduce(Parameter(Type::Constant(undefined, zone())));
202 ASSERT_TRUE(r.Changed());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203 EXPECT_THAT(r.replacement(), IsHeapConstant(undefined));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400204 }
205}
206
207
208// -----------------------------------------------------------------------------
209// JSToBoolean
210
211
212TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
213 Node* input = Parameter(Type::Boolean(), 0);
214 Node* context = Parameter(Type::Any(), 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100215 Reduction r = Reduce(graph()->NewNode(
216 javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400217 ASSERT_TRUE(r.Changed());
218 EXPECT_EQ(input, r.replacement());
219}
220
221
222TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223 Node* input = Parameter(
224 Type::Union(
225 Type::MinusZero(),
226 Type::Union(
227 Type::NaN(),
228 Type::Union(
229 Type::Null(),
230 Type::Union(
231 Type::Undefined(),
232 Type::Union(
233 Type::Undetectable(),
234 Type::Union(
235 Type::Constant(factory()->false_value(), zone()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 Type::Range(0.0, 0.0, zone()), zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400237 zone()),
238 zone()),
239 zone()),
240 zone()),
241 zone()),
242 0);
243 Node* context = Parameter(Type::Any(), 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100244 Reduction r = Reduce(graph()->NewNode(
245 javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246 ASSERT_TRUE(r.Changed());
247 EXPECT_THAT(r.replacement(), IsFalseConstant());
248}
249
250
251TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
252 Node* input = Parameter(
253 Type::Union(
254 Type::Constant(factory()->true_value(), zone()),
255 Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
256 zone()),
257 0);
258 Node* context = Parameter(Type::Any(), 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100259 Reduction r = Reduce(graph()->NewNode(
260 javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400261 ASSERT_TRUE(r.Changed());
262 EXPECT_THAT(r.replacement(), IsTrueConstant());
263}
264
265
266TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400268 Node* context = Parameter(Type::Any(), 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100269 Reduction r = Reduce(graph()->NewNode(
270 javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400271 ASSERT_TRUE(r.Changed());
272 EXPECT_THAT(r.replacement(), IsTrueConstant());
273}
274
275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) {
277 Node* input = Parameter(Type::OrderedNumber(), 0);
278 Node* context = Parameter(Type::Any(), 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100279 Reduction r = Reduce(graph()->NewNode(
280 javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281 ASSERT_TRUE(r.Changed());
282 EXPECT_THAT(r.replacement(),
283 IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0))));
284}
285
286
287TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
288 Node* input = Parameter(Type::String(), 0);
289 Node* context = Parameter(Type::Any(), 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100290 Reduction r = Reduce(graph()->NewNode(
291 javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 ASSERT_TRUE(r.Changed());
293 EXPECT_THAT(
294 r.replacement(),
295 IsNumberLessThan(IsNumberConstant(0.0),
296 IsLoadField(AccessBuilder::ForStringLength(), input,
297 graph()->start(), graph()->start())));
298}
299
300
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400301TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
302 Node* input = Parameter(Type::Any(), 0);
303 Node* context = Parameter(Type::Any(), 1);
Ben Murdochc5610432016-08-08 18:44:38 +0100304 Reduction r = Reduce(graph()->NewNode(
305 javascript()->ToBoolean(ToBooleanHint::kAny), input, context));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306 ASSERT_FALSE(r.Changed());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307}
308
309
310// -----------------------------------------------------------------------------
311// JSToNumber
312
313
314TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
315 Node* const input = Parameter(Type::PlainPrimitive(), 0);
316 Node* const context = Parameter(Type::Any(), 1);
317 Node* const effect = graph()->start();
318 Node* const control = graph()->start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 Reduction r =
320 Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
321 EmptyFrameState(), effect, control));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400322 ASSERT_TRUE(r.Changed());
323 EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
324 graph()->start(), control));
325}
326
327
328// -----------------------------------------------------------------------------
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000329// JSToObject
330
331
332TEST_F(JSTypedLoweringTest, JSToObjectWithAny) {
333 Node* const input = Parameter(Type::Any(), 0);
334 Node* const context = Parameter(Type::Any(), 1);
335 Node* const frame_state = EmptyFrameState();
336 Node* const effect = graph()->start();
337 Node* const control = graph()->start();
338 Reduction r = Reduce(graph()->NewNode(javascript()->ToObject(), input,
339 context, frame_state, effect, control));
340 ASSERT_TRUE(r.Changed());
341 EXPECT_THAT(r.replacement(), IsPhi(MachineRepresentation::kTagged, _, _, _));
342}
343
344
345TEST_F(JSTypedLoweringTest, JSToObjectWithReceiver) {
346 Node* const input = Parameter(Type::Receiver(), 0);
347 Node* const context = Parameter(Type::Any(), 1);
348 Node* const frame_state = EmptyFrameState();
349 Node* const effect = graph()->start();
350 Node* const control = graph()->start();
351 Reduction r = Reduce(graph()->NewNode(javascript()->ToObject(), input,
352 context, frame_state, effect, control));
353 ASSERT_TRUE(r.Changed());
354 EXPECT_EQ(input, r.replacement());
355}
356
357
358// -----------------------------------------------------------------------------
359// JSToString
360
361
362TEST_F(JSTypedLoweringTest, JSToStringWithBoolean) {
363 Node* const input = Parameter(Type::Boolean(), 0);
364 Node* const context = Parameter(Type::Any(), 1);
365 Node* const frame_state = EmptyFrameState();
366 Node* const effect = graph()->start();
367 Node* const control = graph()->start();
368 Reduction r = Reduce(graph()->NewNode(javascript()->ToString(), input,
369 context, frame_state, effect, control));
370 ASSERT_TRUE(r.Changed());
371 EXPECT_THAT(r.replacement(),
372 IsSelect(MachineRepresentation::kTagged, input,
373 IsHeapConstant(factory()->true_string()),
374 IsHeapConstant(factory()->false_string())));
375}
376
377
378// -----------------------------------------------------------------------------
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400379// JSStrictEqual
380
381
382TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
383 Node* const the_hole = HeapConstant(factory()->the_hole_value());
384 Node* const context = UndefinedConstant();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400385 TRACED_FOREACH(Type*, type, kJSTypes) {
386 Node* const lhs = Parameter(type);
Ben Murdochc5610432016-08-08 18:44:38 +0100387 Reduction r = Reduce(
388 graph()->NewNode(javascript()->StrictEqual(), lhs, the_hole, context));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400389 ASSERT_TRUE(r.Changed());
390 EXPECT_THAT(r.replacement(), IsFalseConstant());
391 }
392}
393
394
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395TEST_F(JSTypedLoweringTest, JSStrictEqualWithUnique) {
396 Node* const lhs = Parameter(Type::Unique(), 0);
397 Node* const rhs = Parameter(Type::Unique(), 1);
398 Node* const context = Parameter(Type::Any(), 2);
399 Reduction r =
Ben Murdochc5610432016-08-08 18:44:38 +0100400 Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs, rhs, context));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401 ASSERT_TRUE(r.Changed());
402 EXPECT_THAT(r.replacement(), IsReferenceEqual(Type::Unique(), lhs, rhs));
403}
404
405
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400406// -----------------------------------------------------------------------------
407// JSShiftLeft
408
409
410TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411 BinaryOperationHints const hints = BinaryOperationHints::Any();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400412 Node* const lhs = Parameter(Type::Signed32());
413 Node* const context = UndefinedConstant();
414 Node* const effect = graph()->start();
415 Node* const control = graph()->start();
416 TRACED_FORRANGE(double, rhs, 0, 31) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100417 Reduction r = Reduce(graph()->NewNode(
418 javascript()->ShiftLeft(hints), lhs, NumberConstant(rhs), context,
419 EmptyFrameState(), EmptyFrameState(), effect, control));
420 ASSERT_TRUE(r.Changed());
421 EXPECT_THAT(r.replacement(),
422 IsNumberShiftLeft(lhs, IsNumberConstant(BitEq(rhs))));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400423 }
424}
425
426
427TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 BinaryOperationHints const hints = BinaryOperationHints::Any();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400429 Node* const lhs = Parameter(Type::Signed32());
430 Node* const rhs = Parameter(Type::Unsigned32());
431 Node* const context = UndefinedConstant();
432 Node* const effect = graph()->start();
433 Node* const control = graph()->start();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100434 Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(hints), lhs,
435 rhs, context, EmptyFrameState(),
436 EmptyFrameState(), effect, control));
437 ASSERT_TRUE(r.Changed());
438 EXPECT_THAT(r.replacement(), IsNumberShiftLeft(lhs, rhs));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400439}
440
441
442// -----------------------------------------------------------------------------
443// JSShiftRight
444
445
446TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 BinaryOperationHints const hints = BinaryOperationHints::Any();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400448 Node* const lhs = Parameter(Type::Signed32());
449 Node* const context = UndefinedConstant();
450 Node* const effect = graph()->start();
451 Node* const control = graph()->start();
452 TRACED_FORRANGE(double, rhs, 0, 31) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100453 Reduction r = Reduce(graph()->NewNode(
454 javascript()->ShiftRight(hints), lhs, NumberConstant(rhs), context,
455 EmptyFrameState(), EmptyFrameState(), effect, control));
456 ASSERT_TRUE(r.Changed());
457 EXPECT_THAT(r.replacement(),
458 IsNumberShiftRight(lhs, IsNumberConstant(BitEq(rhs))));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400459 }
460}
461
462
463TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000464 BinaryOperationHints const hints = BinaryOperationHints::Any();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400465 Node* const lhs = Parameter(Type::Signed32());
466 Node* const rhs = Parameter(Type::Unsigned32());
467 Node* const context = UndefinedConstant();
468 Node* const effect = graph()->start();
469 Node* const control = graph()->start();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100470 Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(hints), lhs,
471 rhs, context, EmptyFrameState(),
472 EmptyFrameState(), effect, control));
473 ASSERT_TRUE(r.Changed());
474 EXPECT_THAT(r.replacement(), IsNumberShiftRight(lhs, rhs));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400475}
476
477
478// -----------------------------------------------------------------------------
479// JSShiftRightLogical
480
481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482TEST_F(JSTypedLoweringTest,
483 JSShiftRightLogicalWithUnsigned32AndConstant) {
484 BinaryOperationHints const hints = BinaryOperationHints::Any();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400485 Node* const lhs = Parameter(Type::Unsigned32());
486 Node* const context = UndefinedConstant();
487 Node* const effect = graph()->start();
488 Node* const control = graph()->start();
489 TRACED_FORRANGE(double, rhs, 0, 31) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100490 Reduction r = Reduce(graph()->NewNode(
491 javascript()->ShiftRightLogical(hints), lhs, NumberConstant(rhs),
492 context, EmptyFrameState(), EmptyFrameState(), effect, control));
493 ASSERT_TRUE(r.Changed());
494 EXPECT_THAT(r.replacement(),
495 IsNumberShiftRightLogical(lhs, IsNumberConstant(BitEq(rhs))));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400496 }
497}
498
499
500TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 BinaryOperationHints const hints = BinaryOperationHints::Any();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400502 Node* const lhs = Parameter(Type::Unsigned32());
503 Node* const rhs = Parameter(Type::Unsigned32());
504 Node* const context = UndefinedConstant();
505 Node* const effect = graph()->start();
506 Node* const control = graph()->start();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100507 Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(hints),
508 lhs, rhs, context, EmptyFrameState(),
509 EmptyFrameState(), effect, control));
510 ASSERT_TRUE(r.Changed());
511 EXPECT_THAT(r.replacement(), IsNumberShiftRightLogical(lhs, rhs));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400512}
513
514
515// -----------------------------------------------------------------------------
516// JSLoadContext
517
518
519TEST_F(JSTypedLoweringTest, JSLoadContext) {
520 Node* const context = Parameter(Type::Any());
521 Node* const effect = graph()->start();
522 static bool kBooleans[] = {false, true};
523 TRACED_FOREACH(size_t, index, kIndices) {
524 TRACED_FOREACH(bool, immutable, kBooleans) {
525 Reduction const r1 = Reduce(
526 graph()->NewNode(javascript()->LoadContext(0, index, immutable),
527 context, context, effect));
528 ASSERT_TRUE(r1.Changed());
529 EXPECT_THAT(r1.replacement(),
530 IsLoadField(AccessBuilder::ForContextSlot(index), context,
531 effect, graph()->start()));
532
533 Reduction const r2 = Reduce(
534 graph()->NewNode(javascript()->LoadContext(1, index, immutable),
535 context, context, effect));
536 ASSERT_TRUE(r2.Changed());
537 EXPECT_THAT(r2.replacement(),
538 IsLoadField(AccessBuilder::ForContextSlot(index),
539 IsLoadField(AccessBuilder::ForContextSlot(
540 Context::PREVIOUS_INDEX),
541 context, effect, graph()->start()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 _, graph()->start()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400543 }
544 }
545}
546
547
548// -----------------------------------------------------------------------------
549// JSStoreContext
550
551
552TEST_F(JSTypedLoweringTest, JSStoreContext) {
553 Node* const context = Parameter(Type::Any());
554 Node* const effect = graph()->start();
555 Node* const control = graph()->start();
556 TRACED_FOREACH(size_t, index, kIndices) {
557 TRACED_FOREACH(Type*, type, kJSTypes) {
558 Node* const value = Parameter(type);
559
560 Reduction const r1 =
561 Reduce(graph()->NewNode(javascript()->StoreContext(0, index), context,
562 value, context, effect, control));
563 ASSERT_TRUE(r1.Changed());
564 EXPECT_THAT(r1.replacement(),
565 IsStoreField(AccessBuilder::ForContextSlot(index), context,
566 value, effect, control));
567
568 Reduction const r2 =
569 Reduce(graph()->NewNode(javascript()->StoreContext(1, index), context,
570 value, context, effect, control));
571 ASSERT_TRUE(r2.Changed());
572 EXPECT_THAT(r2.replacement(),
573 IsStoreField(AccessBuilder::ForContextSlot(index),
574 IsLoadField(AccessBuilder::ForContextSlot(
575 Context::PREVIOUS_INDEX),
576 context, effect, graph()->start()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 value, _, control));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400578 }
579 }
580}
581
582
583// -----------------------------------------------------------------------------
584// JSLoadProperty
585
586
587TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
588 const size_t kLength = 17;
589 double backing_store[kLength];
590 Handle<JSArrayBuffer> buffer =
591 NewArrayBuffer(backing_store, sizeof(backing_store));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 VectorSlotPair feedback;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400593 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100594 Handle<JSTypedArray> array =
595 factory()->NewJSTypedArray(type, buffer, 0, kLength);
596 int const element_size = static_cast<int>(array->element_size());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400597
Ben Murdoch097c5b22016-05-18 11:27:45 +0100598 Node* key = Parameter(
599 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
600 Node* base = HeapConstant(array);
601 Node* vector = UndefinedConstant();
602 Node* context = UndefinedConstant();
603 Node* effect = graph()->start();
604 Node* control = graph()->start();
605 Reduction r = Reduce(graph()->NewNode(
606 javascript()->LoadProperty(feedback), base, key, vector, context,
607 EmptyFrameState(), EmptyFrameState(), effect, control));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608
Ben Murdoch097c5b22016-05-18 11:27:45 +0100609 Matcher<Node*> offset_matcher =
610 element_size == 1
611 ? key
612 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000613
Ben Murdoch097c5b22016-05-18 11:27:45 +0100614 ASSERT_TRUE(r.Changed());
615 EXPECT_THAT(
616 r.replacement(),
617 IsLoadBuffer(BufferAccess(type),
618 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
619 offset_matcher,
620 IsNumberConstant(array->byte_length()->Number()), effect,
621 control));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400622 }
623}
624
625
626TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
627 const size_t kLength = 17;
628 double backing_store[kLength];
629 Handle<JSArrayBuffer> buffer =
630 NewArrayBuffer(backing_store, sizeof(backing_store));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 VectorSlotPair feedback;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400632 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100633 Handle<JSTypedArray> array =
634 factory()->NewJSTypedArray(type, buffer, 0, kLength);
635 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400636
Ben Murdoch097c5b22016-05-18 11:27:45 +0100637 int min = random_number_generator()->NextInt(static_cast<int>(kLength));
638 int max = random_number_generator()->NextInt(static_cast<int>(kLength));
639 if (min > max) std::swap(min, max);
640 Node* key = Parameter(Type::Range(min, max, zone()));
641 Node* base = HeapConstant(array);
642 Node* vector = UndefinedConstant();
643 Node* context = UndefinedConstant();
644 Node* effect = graph()->start();
645 Node* control = graph()->start();
646 Reduction r = Reduce(graph()->NewNode(
647 javascript()->LoadProperty(feedback), base, key, vector, context,
648 EmptyFrameState(), EmptyFrameState(), effect, control));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000649
Ben Murdoch097c5b22016-05-18 11:27:45 +0100650 ASSERT_TRUE(r.Changed());
651 EXPECT_THAT(
652 r.replacement(),
653 IsLoadElement(access,
654 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
655 key, effect, control));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400656 }
657}
658
659
660// -----------------------------------------------------------------------------
661// JSStoreProperty
662
663
664TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
665 const size_t kLength = 17;
666 double backing_store[kLength];
667 Handle<JSArrayBuffer> buffer =
668 NewArrayBuffer(backing_store, sizeof(backing_store));
669 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000670 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400671 Handle<JSTypedArray> array =
672 factory()->NewJSTypedArray(type, buffer, 0, kLength);
673 int const element_size = static_cast<int>(array->element_size());
674
675 Node* key = Parameter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400677 Node* base = HeapConstant(array);
678 Node* value =
679 Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 Node* vector = UndefinedConstant();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400681 Node* context = UndefinedConstant();
682 Node* effect = graph()->start();
683 Node* control = graph()->start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000684 VectorSlotPair feedback;
685 const Operator* op = javascript()->StoreProperty(language_mode, feedback);
686 Node* node = graph()->NewNode(op, base, key, value, vector, context,
687 EmptyFrameState(), EmptyFrameState(),
688 effect, control);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400689 Reduction r = Reduce(node);
690
691 Matcher<Node*> offset_matcher =
692 element_size == 1
693 ? key
694 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
695
696 ASSERT_TRUE(r.Changed());
697 EXPECT_THAT(
698 r.replacement(),
699 IsStoreBuffer(BufferAccess(type),
700 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
701 offset_matcher,
702 IsNumberConstant(array->byte_length()->Number()), value,
703 effect, control));
704 }
705 }
706}
707
708
709TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
710 const size_t kLength = 17;
711 double backing_store[kLength];
712 Handle<JSArrayBuffer> buffer =
713 NewArrayBuffer(backing_store, sizeof(backing_store));
714 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400716 Handle<JSTypedArray> array =
717 factory()->NewJSTypedArray(type, buffer, 0, kLength);
718 int const element_size = static_cast<int>(array->element_size());
719
720 Node* key = Parameter(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000721 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400722 Node* base = HeapConstant(array);
723 Node* value = Parameter(Type::Any());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 Node* vector = UndefinedConstant();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400725 Node* context = UndefinedConstant();
726 Node* effect = graph()->start();
727 Node* control = graph()->start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000728 VectorSlotPair feedback;
729 const Operator* op = javascript()->StoreProperty(language_mode, feedback);
730 Node* node = graph()->NewNode(op, base, key, value, vector, context,
731 EmptyFrameState(), EmptyFrameState(),
732 effect, control);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400733 Reduction r = Reduce(node);
734
735 Matcher<Node*> offset_matcher =
736 element_size == 1
737 ? key
738 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
739
740 Matcher<Node*> value_matcher =
741 IsToNumber(value, context, effect, control);
742 Matcher<Node*> effect_matcher = value_matcher;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400743
744 ASSERT_TRUE(r.Changed());
745 EXPECT_THAT(
746 r.replacement(),
747 IsStoreBuffer(BufferAccess(type),
748 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
749 offset_matcher,
750 IsNumberConstant(array->byte_length()->Number()),
751 value_matcher, effect_matcher, control));
752 }
753 }
754}
755
756
757TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
758 const size_t kLength = 17;
759 double backing_store[kLength];
760 Handle<JSArrayBuffer> buffer =
761 NewArrayBuffer(backing_store, sizeof(backing_store));
762 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000763 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400764 Handle<JSTypedArray> array =
765 factory()->NewJSTypedArray(type, buffer, 0, kLength);
766 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
767
768 int min = random_number_generator()->NextInt(static_cast<int>(kLength));
769 int max = random_number_generator()->NextInt(static_cast<int>(kLength));
770 if (min > max) std::swap(min, max);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000771 Node* key = Parameter(Type::Range(min, max, zone()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400772 Node* base = HeapConstant(array);
773 Node* value = Parameter(access.type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000774 Node* vector = UndefinedConstant();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400775 Node* context = UndefinedConstant();
776 Node* effect = graph()->start();
777 Node* control = graph()->start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000778 VectorSlotPair feedback;
779 const Operator* op = javascript()->StoreProperty(language_mode, feedback);
780 Node* node = graph()->NewNode(op, base, key, value, vector, context,
781 EmptyFrameState(), EmptyFrameState(),
782 effect, control);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400783 Reduction r = Reduce(node);
784
785 ASSERT_TRUE(r.Changed());
786 EXPECT_THAT(
787 r.replacement(),
788 IsStoreElement(
789 access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
790 key, value, effect, control));
791 }
792 }
793}
794
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000795
796// -----------------------------------------------------------------------------
797// JSLoadNamed
798
799
800TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) {
801 VectorSlotPair feedback;
802 Handle<Name> name = factory()->length_string();
803 Node* const receiver = Parameter(Type::String(), 0);
804 Node* const vector = Parameter(Type::Internal(), 1);
805 Node* const context = UndefinedConstant();
806 Node* const effect = graph()->start();
807 Node* const control = graph()->start();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100808 Reduction const r = Reduce(graph()->NewNode(
809 javascript()->LoadNamed(name, feedback), receiver, vector, context,
810 EmptyFrameState(), EmptyFrameState(), effect, control));
811 ASSERT_TRUE(r.Changed());
812 EXPECT_THAT(r.replacement(), IsLoadField(AccessBuilder::ForStringLength(),
813 receiver, effect, control));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000814}
815
816
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817// -----------------------------------------------------------------------------
818// JSAdd
819
820
821TEST_F(JSTypedLoweringTest, JSAddWithString) {
822 BinaryOperationHints const hints = BinaryOperationHints::Any();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823 Node* lhs = Parameter(Type::String(), 0);
824 Node* rhs = Parameter(Type::String(), 1);
825 Node* context = Parameter(Type::Any(), 2);
826 Node* frame_state0 = EmptyFrameState();
827 Node* frame_state1 = EmptyFrameState();
828 Node* effect = graph()->start();
829 Node* control = graph()->start();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100830 Reduction r =
831 Reduce(graph()->NewNode(javascript()->Add(hints), lhs, rhs, context,
832 frame_state0, frame_state1, effect, control));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000833 ASSERT_TRUE(r.Changed());
834 EXPECT_THAT(r.replacement(),
835 IsCall(_, IsHeapConstant(CodeFactory::StringAdd(
836 isolate(), STRING_ADD_CHECK_NONE,
837 NOT_TENURED).code()),
838 lhs, rhs, context, frame_state0, effect, control));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000839}
840
841
842// -----------------------------------------------------------------------------
843// JSInstanceOf
844// Test that instanceOf is reduced if and only if the right-hand side is a
845// function constant. Functional correctness is ensured elsewhere.
846
847
848TEST_F(JSTypedLoweringTest, JSInstanceOfSpecializationWithoutSmiCheck) {
849 Node* const context = Parameter(Type::Any());
850 Node* const frame_state = EmptyFrameState();
851 Node* const effect = graph()->start();
852 Node* const control = graph()->start();
853
854 // Reduce if left-hand side is known to be an object.
855 Node* instanceOf =
856 graph()->NewNode(javascript()->InstanceOf(), Parameter(Type::Object(), 0),
857 HeapConstant(isolate()->object_function()), context,
858 frame_state, effect, control);
859 Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context,
860 frame_state, effect, control);
861 Reduction r = Reduce(instanceOf);
862 ASSERT_TRUE(r.Changed());
863 ASSERT_EQ(r.replacement(), dummy->InputAt(0));
864 ASSERT_NE(instanceOf, dummy->InputAt(0));
865}
866
867
868TEST_F(JSTypedLoweringTest, JSInstanceOfSpecializationWithSmiCheck) {
869 Node* const context = Parameter(Type::Any());
870 Node* const frame_state = EmptyFrameState();
871 Node* const effect = graph()->start();
872 Node* const control = graph()->start();
873
874 // Reduce if left-hand side could be a Smi.
875 Node* instanceOf =
876 graph()->NewNode(javascript()->InstanceOf(), Parameter(Type::Any(), 0),
877 HeapConstant(isolate()->object_function()), context,
878 frame_state, effect, control);
879 Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context,
880 frame_state, effect, control);
881 Reduction r = Reduce(instanceOf);
882 ASSERT_TRUE(r.Changed());
883 ASSERT_EQ(r.replacement(), dummy->InputAt(0));
884 ASSERT_NE(instanceOf, dummy->InputAt(0));
885}
886
887
888TEST_F(JSTypedLoweringTest, JSInstanceOfNoSpecialization) {
889 Node* const context = Parameter(Type::Any());
890 Node* const frame_state = EmptyFrameState();
891 Node* const effect = graph()->start();
892 Node* const control = graph()->start();
893
894 // Do not reduce if right-hand side is not a function constant.
895 Node* instanceOf = graph()->NewNode(
896 javascript()->InstanceOf(), Parameter(Type::Any(), 0),
897 Parameter(Type::Any()), context, frame_state, effect, control);
898 Node* dummy = graph()->NewNode(javascript()->ToObject(), instanceOf, context,
899 frame_state, effect, control);
900 Reduction r = Reduce(instanceOf);
901 ASSERT_FALSE(r.Changed());
902 ASSERT_EQ(instanceOf, dummy->InputAt(0));
903}
904
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400905} // namespace compiler
906} // namespace internal
907} // namespace v8