OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/access-builder.h" | 5 #include "src/compiler/access-builder.h" |
6 #include "src/compiler/js-graph.h" | 6 #include "src/compiler/js-graph.h" |
7 #include "src/compiler/js-operator.h" | 7 #include "src/compiler/js-operator.h" |
8 #include "src/compiler/js-typed-lowering.h" | 8 #include "src/compiler/js-typed-lowering.h" |
9 #include "src/compiler/machine-operator.h" | 9 #include "src/compiler/machine-operator.h" |
10 #include "src/compiler/node-properties-inl.h" | 10 #include "src/compiler/node-properties-inl.h" |
11 #include "src/compiler/typer.h" | 11 #include "src/compiler/typer.h" |
12 #include "test/unittests/compiler/compiler-test-utils.h" | 12 #include "test/unittests/compiler/compiler-test-utils.h" |
13 #include "test/unittests/compiler/graph-unittest.h" | 13 #include "test/unittests/compiler/graph-unittest.h" |
14 #include "test/unittests/compiler/node-test-utils.h" | 14 #include "test/unittests/compiler/node-test-utils.h" |
15 | 15 |
16 namespace v8 { | 16 namespace v8 { |
17 namespace internal { | 17 namespace internal { |
18 namespace compiler { | 18 namespace compiler { |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 const ExternalArrayType kExternalArrayTypes[] = { | 22 const ExternalArrayType kExternalArrayTypes[] = { |
23 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) kExternal##Type##Array, | 23 kExternalUint8Array, kExternalInt8Array, kExternalUint16Array, |
24 TYPED_ARRAYS(TYPED_ARRAY_CASE) | 24 kExternalInt16Array, kExternalUint32Array, kExternalInt32Array, |
25 #undef TYPED_ARRAY_CASE | 25 kExternalFloat32Array, kExternalFloat64Array}; |
26 }; | |
27 | 26 |
28 | 27 |
29 Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(), | 28 Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(), |
30 Type::Number(), Type::String(), Type::Object()}; | 29 Type::Number(), Type::String(), Type::Object()}; |
31 | 30 |
32 | 31 |
33 const StrictMode kStrictModes[] = {SLOPPY, STRICT}; | 32 const StrictMode kStrictModes[] = {SLOPPY, STRICT}; |
34 | 33 |
35 } // namespace | 34 } // namespace |
36 | 35 |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) { | 236 TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) { |
238 const size_t kLength = 17; | 237 const size_t kLength = 17; |
239 double backing_store[kLength]; | 238 double backing_store[kLength]; |
240 Handle<JSArrayBuffer> buffer = | 239 Handle<JSArrayBuffer> buffer = |
241 NewArrayBuffer(backing_store, sizeof(backing_store)); | 240 NewArrayBuffer(backing_store, sizeof(backing_store)); |
242 VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), | 241 VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), |
243 FeedbackVectorICSlot::Invalid()); | 242 FeedbackVectorICSlot::Invalid()); |
244 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { | 243 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { |
245 Handle<JSTypedArray> array = | 244 Handle<JSTypedArray> array = |
246 factory()->NewJSTypedArray(type, buffer, 0, kLength); | 245 factory()->NewJSTypedArray(type, buffer, 0, kLength); |
| 246 int const element_size = static_cast<int>(array->element_size()); |
247 | 247 |
248 Node* key = Parameter(Type::Integral32()); | 248 Node* key = Parameter( |
| 249 Type::Range(factory()->NewNumber(kMinInt / element_size), |
| 250 factory()->NewNumber(kMaxInt / element_size), zone())); |
249 Node* base = HeapConstant(array); | 251 Node* base = HeapConstant(array); |
250 Node* context = UndefinedConstant(); | 252 Node* context = UndefinedConstant(); |
251 Node* effect = graph()->start(); | 253 Node* effect = graph()->start(); |
| 254 Node* control = graph()->start(); |
| 255 Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base, |
| 256 key, context); |
| 257 if (FLAG_turbo_deoptimization) { |
| 258 node->AppendInput(zone(), UndefinedConstant()); |
| 259 } |
| 260 node->AppendInput(zone(), effect); |
| 261 node->AppendInput(zone(), control); |
| 262 Reduction r = Reduce(node); |
| 263 |
| 264 Matcher<Node*> offset_matcher = |
| 265 element_size == 1 |
| 266 ? key |
| 267 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); |
| 268 |
| 269 ASSERT_TRUE(r.Changed()); |
| 270 EXPECT_THAT( |
| 271 r.replacement(), |
| 272 IsLoadBuffer(BufferAccess(type), |
| 273 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), |
| 274 offset_matcher, |
| 275 IsNumberConstant(array->byte_length()->Number()), effect, |
| 276 control)); |
| 277 } |
| 278 } |
| 279 |
| 280 |
| 281 TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) { |
| 282 const size_t kLength = 17; |
| 283 double backing_store[kLength]; |
| 284 Handle<JSArrayBuffer> buffer = |
| 285 NewArrayBuffer(backing_store, sizeof(backing_store)); |
| 286 VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), |
| 287 FeedbackVectorICSlot::Invalid()); |
| 288 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { |
| 289 Handle<JSTypedArray> array = |
| 290 factory()->NewJSTypedArray(type, buffer, 0, kLength); |
| 291 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); |
| 292 |
| 293 int min = random_number_generator()->NextInt(static_cast<int>(kLength)); |
| 294 int max = random_number_generator()->NextInt(static_cast<int>(kLength)); |
| 295 if (min > max) std::swap(min, max); |
| 296 Node* key = Parameter(Type::Range(factory()->NewNumber(min), |
| 297 factory()->NewNumber(max), zone())); |
| 298 Node* base = HeapConstant(array); |
| 299 Node* context = UndefinedConstant(); |
| 300 Node* effect = graph()->start(); |
252 Node* control = graph()->start(); | 301 Node* control = graph()->start(); |
253 Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base, | 302 Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base, |
254 key, context); | 303 key, context); |
255 if (FLAG_turbo_deoptimization) { | 304 if (FLAG_turbo_deoptimization) { |
256 node->AppendInput(zone(), UndefinedConstant()); | 305 node->AppendInput(zone(), UndefinedConstant()); |
257 } | 306 } |
258 node->AppendInput(zone(), effect); | 307 node->AppendInput(zone(), effect); |
259 node->AppendInput(zone(), control); | 308 node->AppendInput(zone(), control); |
260 Reduction r = Reduce(node); | 309 Reduction r = Reduce(node); |
261 | 310 |
262 ASSERT_TRUE(r.Changed()); | 311 ASSERT_TRUE(r.Changed()); |
263 EXPECT_THAT(r.replacement(), | 312 EXPECT_THAT( |
264 IsLoadElement( | 313 r.replacement(), |
265 AccessBuilder::ForTypedArrayElement(type, true), | 314 IsLoadElement(access, |
266 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), | 315 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), |
267 key, IsNumberConstant(array->length()->Number()), effect)); | 316 key, effect, control)); |
268 } | 317 } |
269 } | 318 } |
270 | 319 |
271 | 320 |
272 // ----------------------------------------------------------------------------- | 321 // ----------------------------------------------------------------------------- |
273 // JSStoreProperty | 322 // JSStoreProperty |
274 | 323 |
275 | 324 |
276 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) { | 325 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) { |
277 const size_t kLength = 17; | 326 const size_t kLength = 17; |
278 double backing_store[kLength]; | 327 double backing_store[kLength]; |
279 Handle<JSArrayBuffer> buffer = | 328 Handle<JSArrayBuffer> buffer = |
280 NewArrayBuffer(backing_store, sizeof(backing_store)); | 329 NewArrayBuffer(backing_store, sizeof(backing_store)); |
281 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { | 330 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { |
282 TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) { | 331 TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) { |
283 Handle<JSTypedArray> array = | 332 Handle<JSTypedArray> array = |
284 factory()->NewJSTypedArray(type, buffer, 0, kLength); | 333 factory()->NewJSTypedArray(type, buffer, 0, kLength); |
| 334 int const element_size = static_cast<int>(array->element_size()); |
285 | 335 |
286 Node* key = Parameter(Type::Integral32()); | 336 Node* key = Parameter( |
| 337 Type::Range(factory()->NewNumber(kMinInt / element_size), |
| 338 factory()->NewNumber(kMaxInt / element_size), zone())); |
287 Node* base = HeapConstant(array); | 339 Node* base = HeapConstant(array); |
288 Node* value = | 340 Node* value = |
289 Parameter(AccessBuilder::ForTypedArrayElement(type, true).type); | 341 Parameter(AccessBuilder::ForTypedArrayElement(type, true).type); |
290 Node* context = UndefinedConstant(); | 342 Node* context = UndefinedConstant(); |
291 Node* effect = graph()->start(); | 343 Node* effect = graph()->start(); |
292 Node* control = graph()->start(); | 344 Node* control = graph()->start(); |
293 Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode), | 345 Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode), |
294 base, key, value, context); | 346 base, key, value, context); |
295 if (FLAG_turbo_deoptimization) { | 347 if (FLAG_turbo_deoptimization) { |
296 node->AppendInput(zone(), UndefinedConstant()); | 348 node->AppendInput(zone(), UndefinedConstant()); |
297 } | 349 } |
298 node->AppendInput(zone(), effect); | 350 node->AppendInput(zone(), effect); |
299 node->AppendInput(zone(), control); | 351 node->AppendInput(zone(), control); |
300 Reduction r = Reduce(node); | 352 Reduction r = Reduce(node); |
301 | 353 |
| 354 Matcher<Node*> offset_matcher = |
| 355 element_size == 1 |
| 356 ? key |
| 357 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); |
| 358 |
302 ASSERT_TRUE(r.Changed()); | 359 ASSERT_TRUE(r.Changed()); |
303 EXPECT_THAT(r.replacement(), | 360 EXPECT_THAT( |
304 IsStoreElement( | 361 r.replacement(), |
305 AccessBuilder::ForTypedArrayElement(type, true), | 362 IsStoreBuffer(BufferAccess(type), |
306 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), | 363 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), |
307 key, IsNumberConstant(array->length()->Number()), value, | 364 offset_matcher, |
308 effect, control)); | 365 IsNumberConstant(array->byte_length()->Number()), value, |
| 366 effect, control)); |
309 } | 367 } |
310 } | 368 } |
311 } | 369 } |
312 | 370 |
313 | 371 |
314 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) { | 372 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) { |
315 const size_t kLength = 17; | 373 const size_t kLength = 17; |
316 double backing_store[kLength]; | 374 double backing_store[kLength]; |
317 Handle<JSArrayBuffer> buffer = | 375 Handle<JSArrayBuffer> buffer = |
318 NewArrayBuffer(backing_store, sizeof(backing_store)); | 376 NewArrayBuffer(backing_store, sizeof(backing_store)); |
319 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { | 377 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { |
320 TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) { | 378 TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) { |
321 Handle<JSTypedArray> array = | 379 Handle<JSTypedArray> array = |
322 factory()->NewJSTypedArray(type, buffer, 0, kLength); | 380 factory()->NewJSTypedArray(type, buffer, 0, kLength); |
| 381 int const element_size = static_cast<int>(array->element_size()); |
323 | 382 |
324 Node* key = Parameter(Type::Integral32()); | 383 Node* key = Parameter( |
| 384 Type::Range(factory()->NewNumber(kMinInt / element_size), |
| 385 factory()->NewNumber(kMaxInt / element_size), zone())); |
325 Node* base = HeapConstant(array); | 386 Node* base = HeapConstant(array); |
326 Node* value = Parameter(Type::Any()); | 387 Node* value = Parameter(Type::Any()); |
327 Node* context = UndefinedConstant(); | 388 Node* context = UndefinedConstant(); |
328 Node* effect = graph()->start(); | 389 Node* effect = graph()->start(); |
329 Node* control = graph()->start(); | 390 Node* control = graph()->start(); |
330 Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode), | 391 Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode), |
331 base, key, value, context); | 392 base, key, value, context); |
332 if (FLAG_turbo_deoptimization) { | 393 if (FLAG_turbo_deoptimization) { |
333 node->AppendInput(zone(), UndefinedConstant()); | 394 node->AppendInput(zone(), UndefinedConstant()); |
334 } | 395 } |
335 node->AppendInput(zone(), effect); | 396 node->AppendInput(zone(), effect); |
336 node->AppendInput(zone(), control); | 397 node->AppendInput(zone(), control); |
337 Reduction r = Reduce(node); | 398 Reduction r = Reduce(node); |
338 | 399 |
| 400 Matcher<Node*> offset_matcher = |
| 401 element_size == 1 |
| 402 ? key |
| 403 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size))); |
| 404 |
339 Matcher<Node*> value_matcher = | 405 Matcher<Node*> value_matcher = |
340 IsToNumber(value, context, effect, control); | 406 IsToNumber(value, context, effect, control); |
341 Matcher<Node*> effect_matcher = value_matcher; | 407 Matcher<Node*> effect_matcher = value_matcher; |
342 if (AccessBuilder::ForTypedArrayElement(type, true) | 408 if (AccessBuilder::ForTypedArrayElement(type, true) |
343 .type->Is(Type::Signed32())) { | 409 .type->Is(Type::Signed32())) { |
344 value_matcher = IsNumberToInt32(value_matcher); | 410 value_matcher = IsNumberToInt32(value_matcher); |
345 } else if (AccessBuilder::ForTypedArrayElement(type, true) | 411 } else if (AccessBuilder::ForTypedArrayElement(type, true) |
346 .type->Is(Type::Unsigned32())) { | 412 .type->Is(Type::Unsigned32())) { |
347 value_matcher = IsNumberToUint32(value_matcher); | 413 value_matcher = IsNumberToUint32(value_matcher); |
348 } | 414 } |
349 | 415 |
350 ASSERT_TRUE(r.Changed()); | 416 ASSERT_TRUE(r.Changed()); |
351 EXPECT_THAT(r.replacement(), | 417 EXPECT_THAT( |
352 IsStoreElement( | 418 r.replacement(), |
353 AccessBuilder::ForTypedArrayElement(type, true), | 419 IsStoreBuffer(BufferAccess(type), |
354 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), | 420 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), |
355 key, IsNumberConstant(array->length()->Number()), | 421 offset_matcher, |
356 value_matcher, effect_matcher, control)); | 422 IsNumberConstant(array->byte_length()->Number()), |
| 423 value_matcher, effect_matcher, control)); |
357 } | 424 } |
358 } | 425 } |
359 } | 426 } |
| 427 |
| 428 |
| 429 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) { |
| 430 const size_t kLength = 17; |
| 431 double backing_store[kLength]; |
| 432 Handle<JSArrayBuffer> buffer = |
| 433 NewArrayBuffer(backing_store, sizeof(backing_store)); |
| 434 TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) { |
| 435 TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) { |
| 436 Handle<JSTypedArray> array = |
| 437 factory()->NewJSTypedArray(type, buffer, 0, kLength); |
| 438 ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true); |
| 439 |
| 440 int min = random_number_generator()->NextInt(static_cast<int>(kLength)); |
| 441 int max = random_number_generator()->NextInt(static_cast<int>(kLength)); |
| 442 if (min > max) std::swap(min, max); |
| 443 Node* key = Parameter(Type::Range(factory()->NewNumber(min), |
| 444 factory()->NewNumber(max), zone())); |
| 445 Node* base = HeapConstant(array); |
| 446 Node* value = Parameter(access.type); |
| 447 Node* context = UndefinedConstant(); |
| 448 Node* effect = graph()->start(); |
| 449 Node* control = graph()->start(); |
| 450 Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode), |
| 451 base, key, value, context); |
| 452 if (FLAG_turbo_deoptimization) { |
| 453 node->AppendInput(zone(), UndefinedConstant()); |
| 454 } |
| 455 node->AppendInput(zone(), effect); |
| 456 node->AppendInput(zone(), control); |
| 457 Reduction r = Reduce(node); |
| 458 |
| 459 ASSERT_TRUE(r.Changed()); |
| 460 EXPECT_THAT( |
| 461 r.replacement(), |
| 462 IsStoreElement( |
| 463 access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])), |
| 464 key, value, effect, control)); |
| 465 } |
| 466 } |
| 467 } |
360 | 468 |
361 } // namespace compiler | 469 } // namespace compiler |
362 } // namespace internal | 470 } // namespace internal |
363 } // namespace v8 | 471 } // namespace v8 |
OLD | NEW |