| 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 |