OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3438 int id() { return id_; } | 3438 int id() { return id_; } |
3439 void increment() { number_of_weak_calls_++; } | 3439 void increment() { number_of_weak_calls_++; } |
3440 int NumberOfWeakCalls() { return number_of_weak_calls_; } | 3440 int NumberOfWeakCalls() { return number_of_weak_calls_; } |
3441 private: | 3441 private: |
3442 int id_; | 3442 int id_; |
3443 int number_of_weak_calls_; | 3443 int number_of_weak_calls_; |
3444 }; | 3444 }; |
3445 | 3445 |
3446 | 3446 |
3447 template<typename T> | 3447 template<typename T> |
3448 static void WeakPointerCallback(v8::Isolate* isolate, | 3448 struct WeakCallCounterAndPersistent { |
3449 Persistent<T>* handle, | 3449 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter) |
3450 WeakCallCounter* counter) { | 3450 : counter(counter) {} |
3451 CHECK_EQ(1234, counter->id()); | 3451 WeakCallCounter* counter; |
3452 counter->increment(); | 3452 v8::Persistent<T> handle; |
3453 handle->Reset(); | 3453 }; |
| 3454 |
| 3455 |
| 3456 template <typename T> |
| 3457 static void WeakPointerCallback( |
| 3458 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) { |
| 3459 CHECK_EQ(1234, data.GetParameter()->counter->id()); |
| 3460 data.GetParameter()->counter->increment(); |
| 3461 data.GetParameter()->handle.Reset(); |
3454 } | 3462 } |
3455 | 3463 |
3456 | 3464 |
3457 template<typename T> | 3465 template<typename T> |
3458 static UniqueId MakeUniqueId(const Persistent<T>& p) { | 3466 static UniqueId MakeUniqueId(const Persistent<T>& p) { |
3459 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); | 3467 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); |
3460 } | 3468 } |
3461 | 3469 |
3462 | 3470 |
3463 THREADED_TEST(ApiObjectGroups) { | 3471 THREADED_TEST(ApiObjectGroups) { |
3464 LocalContext env; | 3472 LocalContext env; |
3465 v8::Isolate* iso = env->GetIsolate(); | 3473 v8::Isolate* iso = env->GetIsolate(); |
3466 HandleScope scope(iso); | 3474 HandleScope scope(iso); |
3467 | 3475 |
3468 Persistent<Value> g1s1; | 3476 WeakCallCounter counter(1234); |
3469 Persistent<Value> g1s2; | |
3470 Persistent<Value> g1c1; | |
3471 Persistent<Value> g2s1; | |
3472 Persistent<Value> g2s2; | |
3473 Persistent<Value> g2c1; | |
3474 | 3477 |
3475 WeakCallCounter counter(1234); | 3478 WeakCallCounterAndPersistent<Value> g1s1(&counter); |
| 3479 WeakCallCounterAndPersistent<Value> g1s2(&counter); |
| 3480 WeakCallCounterAndPersistent<Value> g1c1(&counter); |
| 3481 WeakCallCounterAndPersistent<Value> g2s1(&counter); |
| 3482 WeakCallCounterAndPersistent<Value> g2s2(&counter); |
| 3483 WeakCallCounterAndPersistent<Value> g2c1(&counter); |
3476 | 3484 |
3477 { | 3485 { |
3478 HandleScope scope(iso); | 3486 HandleScope scope(iso); |
3479 g1s1.Reset(iso, Object::New()); | 3487 g1s1.handle.Reset(iso, Object::New()); |
3480 g1s2.Reset(iso, Object::New()); | 3488 g1s2.handle.Reset(iso, Object::New()); |
3481 g1c1.Reset(iso, Object::New()); | 3489 g1c1.handle.Reset(iso, Object::New()); |
3482 g1s1.MakeWeak(&counter, &WeakPointerCallback); | 3490 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); |
3483 g1s2.MakeWeak(&counter, &WeakPointerCallback); | 3491 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); |
3484 g1c1.MakeWeak(&counter, &WeakPointerCallback); | 3492 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); |
3485 | 3493 |
3486 g2s1.Reset(iso, Object::New()); | 3494 g2s1.handle.Reset(iso, Object::New()); |
3487 g2s2.Reset(iso, Object::New()); | 3495 g2s2.handle.Reset(iso, Object::New()); |
3488 g2c1.Reset(iso, Object::New()); | 3496 g2c1.handle.Reset(iso, Object::New()); |
3489 g2s1.MakeWeak(&counter, &WeakPointerCallback); | 3497 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); |
3490 g2s2.MakeWeak(&counter, &WeakPointerCallback); | 3498 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); |
3491 g2c1.MakeWeak(&counter, &WeakPointerCallback); | 3499 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); |
3492 } | 3500 } |
3493 | 3501 |
3494 Persistent<Value> root(iso, g1s1); // make a root. | 3502 WeakCallCounterAndPersistent<Value> root(&counter); |
| 3503 root.handle.Reset(iso, g1s1.handle); // make a root. |
3495 | 3504 |
3496 // Connect group 1 and 2, make a cycle. | 3505 // Connect group 1 and 2, make a cycle. |
3497 { | 3506 { |
3498 HandleScope scope(iso); | 3507 HandleScope scope(iso); |
3499 CHECK(Local<Object>::New(iso, g1s2.As<Object>())-> | 3508 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())-> |
3500 Set(0, Local<Value>::New(iso, g2s2))); | 3509 Set(0, Local<Value>::New(iso, g2s2.handle))); |
3501 CHECK(Local<Object>::New(iso, g2s1.As<Object>())-> | 3510 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())-> |
3502 Set(0, Local<Value>::New(iso, g1s1))); | 3511 Set(0, Local<Value>::New(iso, g1s1.handle))); |
3503 } | 3512 } |
3504 | 3513 |
3505 { | 3514 { |
3506 UniqueId id1 = MakeUniqueId(g1s1); | 3515 UniqueId id1 = MakeUniqueId(g1s1.handle); |
3507 UniqueId id2 = MakeUniqueId(g2s2); | 3516 UniqueId id2 = MakeUniqueId(g2s2.handle); |
3508 iso->SetObjectGroupId(g1s1, id1); | 3517 iso->SetObjectGroupId(g1s1.handle, id1); |
3509 iso->SetObjectGroupId(g1s2, id1); | 3518 iso->SetObjectGroupId(g1s2.handle, id1); |
3510 iso->SetReferenceFromGroup(id1, g1c1); | 3519 iso->SetReferenceFromGroup(id1, g1c1.handle); |
3511 iso->SetObjectGroupId(g2s1, id2); | 3520 iso->SetObjectGroupId(g2s1.handle, id2); |
3512 iso->SetObjectGroupId(g2s2, id2); | 3521 iso->SetObjectGroupId(g2s2.handle, id2); |
3513 iso->SetReferenceFromGroup(id2, g2c1); | 3522 iso->SetReferenceFromGroup(id2, g2c1.handle); |
3514 } | 3523 } |
3515 // Do a single full GC, ensure incremental marking is stopped. | 3524 // Do a single full GC, ensure incremental marking is stopped. |
3516 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( | 3525 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( |
3517 iso)->heap(); | 3526 iso)->heap(); |
3518 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3527 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3519 | 3528 |
3520 // All object should be alive. | 3529 // All object should be alive. |
3521 CHECK_EQ(0, counter.NumberOfWeakCalls()); | 3530 CHECK_EQ(0, counter.NumberOfWeakCalls()); |
3522 | 3531 |
3523 // Weaken the root. | 3532 // Weaken the root. |
3524 root.MakeWeak(&counter, &WeakPointerCallback); | 3533 root.handle.SetWeak(&root, &WeakPointerCallback); |
3525 // But make children strong roots---all the objects (except for children) | 3534 // But make children strong roots---all the objects (except for children) |
3526 // should be collectable now. | 3535 // should be collectable now. |
3527 g1c1.ClearWeak(); | 3536 g1c1.handle.ClearWeak(); |
3528 g2c1.ClearWeak(); | 3537 g2c1.handle.ClearWeak(); |
3529 | 3538 |
3530 // Groups are deleted, rebuild groups. | 3539 // Groups are deleted, rebuild groups. |
3531 { | 3540 { |
3532 UniqueId id1 = MakeUniqueId(g1s1); | 3541 UniqueId id1 = MakeUniqueId(g1s1.handle); |
3533 UniqueId id2 = MakeUniqueId(g2s2); | 3542 UniqueId id2 = MakeUniqueId(g2s2.handle); |
3534 iso->SetObjectGroupId(g1s1, id1); | 3543 iso->SetObjectGroupId(g1s1.handle, id1); |
3535 iso->SetObjectGroupId(g1s2, id1); | 3544 iso->SetObjectGroupId(g1s2.handle, id1); |
3536 iso->SetReferenceFromGroup(id1, g1c1); | 3545 iso->SetReferenceFromGroup(id1, g1c1.handle); |
3537 iso->SetObjectGroupId(g2s1, id2); | 3546 iso->SetObjectGroupId(g2s1.handle, id2); |
3538 iso->SetObjectGroupId(g2s2, id2); | 3547 iso->SetObjectGroupId(g2s2.handle, id2); |
3539 iso->SetReferenceFromGroup(id2, g2c1); | 3548 iso->SetReferenceFromGroup(id2, g2c1.handle); |
3540 } | 3549 } |
3541 | 3550 |
3542 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3551 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3543 | 3552 |
3544 // All objects should be gone. 5 global handles in total. | 3553 // All objects should be gone. 5 global handles in total. |
3545 CHECK_EQ(5, counter.NumberOfWeakCalls()); | 3554 CHECK_EQ(5, counter.NumberOfWeakCalls()); |
3546 | 3555 |
3547 // And now make children weak again and collect them. | 3556 // And now make children weak again and collect them. |
3548 g1c1.MakeWeak(&counter, &WeakPointerCallback); | 3557 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); |
3549 g2c1.MakeWeak(&counter, &WeakPointerCallback); | 3558 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); |
3550 | 3559 |
3551 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3560 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3552 CHECK_EQ(7, counter.NumberOfWeakCalls()); | 3561 CHECK_EQ(7, counter.NumberOfWeakCalls()); |
3553 } | 3562 } |
3554 | 3563 |
3555 | 3564 |
3556 THREADED_TEST(ApiObjectGroupsForSubtypes) { | 3565 THREADED_TEST(ApiObjectGroupsForSubtypes) { |
3557 LocalContext env; | 3566 LocalContext env; |
3558 v8::Isolate* iso = env->GetIsolate(); | 3567 v8::Isolate* iso = env->GetIsolate(); |
3559 HandleScope scope(iso); | 3568 HandleScope scope(iso); |
3560 | 3569 |
3561 Persistent<Object> g1s1; | 3570 WeakCallCounter counter(1234); |
3562 Persistent<String> g1s2; | |
3563 Persistent<String> g1c1; | |
3564 Persistent<Object> g2s1; | |
3565 Persistent<String> g2s2; | |
3566 Persistent<String> g2c1; | |
3567 | 3571 |
3568 WeakCallCounter counter(1234); | 3572 WeakCallCounterAndPersistent<Object> g1s1(&counter); |
| 3573 WeakCallCounterAndPersistent<String> g1s2(&counter); |
| 3574 WeakCallCounterAndPersistent<String> g1c1(&counter); |
| 3575 WeakCallCounterAndPersistent<Object> g2s1(&counter); |
| 3576 WeakCallCounterAndPersistent<String> g2s2(&counter); |
| 3577 WeakCallCounterAndPersistent<String> g2c1(&counter); |
3569 | 3578 |
3570 { | 3579 { |
3571 HandleScope scope(iso); | 3580 HandleScope scope(iso); |
3572 g1s1.Reset(iso, Object::New()); | 3581 g1s1.handle.Reset(iso, Object::New()); |
3573 g1s2.Reset(iso, String::NewFromUtf8(iso, "foo1")); | 3582 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1")); |
3574 g1c1.Reset(iso, String::NewFromUtf8(iso, "foo2")); | 3583 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2")); |
3575 g1s1.MakeWeak(&counter, &WeakPointerCallback); | 3584 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); |
3576 g1s2.MakeWeak(&counter, &WeakPointerCallback); | 3585 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); |
3577 g1c1.MakeWeak(&counter, &WeakPointerCallback); | 3586 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); |
3578 | 3587 |
3579 g2s1.Reset(iso, Object::New()); | 3588 g2s1.handle.Reset(iso, Object::New()); |
3580 g2s2.Reset(iso, String::NewFromUtf8(iso, "foo3")); | 3589 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3")); |
3581 g2c1.Reset(iso, String::NewFromUtf8(iso, "foo4")); | 3590 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4")); |
3582 g2s1.MakeWeak(&counter, &WeakPointerCallback); | 3591 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); |
3583 g2s2.MakeWeak(&counter, &WeakPointerCallback); | 3592 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); |
3584 g2c1.MakeWeak(&counter, &WeakPointerCallback); | 3593 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); |
3585 } | 3594 } |
3586 | 3595 |
3587 Persistent<Value> root(iso, g1s1); // make a root. | 3596 WeakCallCounterAndPersistent<Value> root(&counter); |
| 3597 root.handle.Reset(iso, g1s1.handle); // make a root. |
3588 | 3598 |
3589 // Connect group 1 and 2, make a cycle. | 3599 // Connect group 1 and 2, make a cycle. |
3590 { | 3600 { |
3591 HandleScope scope(iso); | 3601 HandleScope scope(iso); |
3592 CHECK(Local<Object>::New(iso, g1s1)->Set(0, Local<Object>::New(iso, g2s1))); | 3602 CHECK(Local<Object>::New(iso, g1s1.handle) |
3593 CHECK(Local<Object>::New(iso, g2s1)->Set(0, Local<Object>::New(iso, g1s1))); | 3603 ->Set(0, Local<Object>::New(iso, g2s1.handle))); |
| 3604 CHECK(Local<Object>::New(iso, g2s1.handle) |
| 3605 ->Set(0, Local<Object>::New(iso, g1s1.handle))); |
3594 } | 3606 } |
3595 | 3607 |
3596 { | 3608 { |
3597 UniqueId id1 = MakeUniqueId(g1s1); | 3609 UniqueId id1 = MakeUniqueId(g1s1.handle); |
3598 UniqueId id2 = MakeUniqueId(g2s2); | 3610 UniqueId id2 = MakeUniqueId(g2s2.handle); |
3599 iso->SetObjectGroupId(g1s1, id1); | 3611 iso->SetObjectGroupId(g1s1.handle, id1); |
3600 iso->SetObjectGroupId(g1s2, id1); | 3612 iso->SetObjectGroupId(g1s2.handle, id1); |
3601 iso->SetReference(g1s1, g1c1); | 3613 iso->SetReference(g1s1.handle, g1c1.handle); |
3602 iso->SetObjectGroupId(g2s1, id2); | 3614 iso->SetObjectGroupId(g2s1.handle, id2); |
3603 iso->SetObjectGroupId(g2s2, id2); | 3615 iso->SetObjectGroupId(g2s2.handle, id2); |
3604 iso->SetReferenceFromGroup(id2, g2c1); | 3616 iso->SetReferenceFromGroup(id2, g2c1.handle); |
3605 } | 3617 } |
3606 // Do a single full GC, ensure incremental marking is stopped. | 3618 // Do a single full GC, ensure incremental marking is stopped. |
3607 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( | 3619 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( |
3608 iso)->heap(); | 3620 iso)->heap(); |
3609 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3621 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3610 | 3622 |
3611 // All object should be alive. | 3623 // All object should be alive. |
3612 CHECK_EQ(0, counter.NumberOfWeakCalls()); | 3624 CHECK_EQ(0, counter.NumberOfWeakCalls()); |
3613 | 3625 |
3614 // Weaken the root. | 3626 // Weaken the root. |
3615 root.MakeWeak(&counter, &WeakPointerCallback); | 3627 root.handle.SetWeak(&root, &WeakPointerCallback); |
3616 // But make children strong roots---all the objects (except for children) | 3628 // But make children strong roots---all the objects (except for children) |
3617 // should be collectable now. | 3629 // should be collectable now. |
3618 g1c1.ClearWeak(); | 3630 g1c1.handle.ClearWeak(); |
3619 g2c1.ClearWeak(); | 3631 g2c1.handle.ClearWeak(); |
3620 | 3632 |
3621 // Groups are deleted, rebuild groups. | 3633 // Groups are deleted, rebuild groups. |
3622 { | 3634 { |
3623 UniqueId id1 = MakeUniqueId(g1s1); | 3635 UniqueId id1 = MakeUniqueId(g1s1.handle); |
3624 UniqueId id2 = MakeUniqueId(g2s2); | 3636 UniqueId id2 = MakeUniqueId(g2s2.handle); |
3625 iso->SetObjectGroupId(g1s1, id1); | 3637 iso->SetObjectGroupId(g1s1.handle, id1); |
3626 iso->SetObjectGroupId(g1s2, id1); | 3638 iso->SetObjectGroupId(g1s2.handle, id1); |
3627 iso->SetReference(g1s1, g1c1); | 3639 iso->SetReference(g1s1.handle, g1c1.handle); |
3628 iso->SetObjectGroupId(g2s1, id2); | 3640 iso->SetObjectGroupId(g2s1.handle, id2); |
3629 iso->SetObjectGroupId(g2s2, id2); | 3641 iso->SetObjectGroupId(g2s2.handle, id2); |
3630 iso->SetReferenceFromGroup(id2, g2c1); | 3642 iso->SetReferenceFromGroup(id2, g2c1.handle); |
3631 } | 3643 } |
3632 | 3644 |
3633 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3645 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3634 | 3646 |
3635 // All objects should be gone. 5 global handles in total. | 3647 // All objects should be gone. 5 global handles in total. |
3636 CHECK_EQ(5, counter.NumberOfWeakCalls()); | 3648 CHECK_EQ(5, counter.NumberOfWeakCalls()); |
3637 | 3649 |
3638 // And now make children weak again and collect them. | 3650 // And now make children weak again and collect them. |
3639 g1c1.MakeWeak(&counter, &WeakPointerCallback); | 3651 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback); |
3640 g2c1.MakeWeak(&counter, &WeakPointerCallback); | 3652 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback); |
3641 | 3653 |
3642 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3654 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3643 CHECK_EQ(7, counter.NumberOfWeakCalls()); | 3655 CHECK_EQ(7, counter.NumberOfWeakCalls()); |
3644 } | 3656 } |
3645 | 3657 |
3646 | 3658 |
3647 THREADED_TEST(ApiObjectGroupsCycle) { | 3659 THREADED_TEST(ApiObjectGroupsCycle) { |
3648 LocalContext env; | 3660 LocalContext env; |
3649 v8::Isolate* iso = env->GetIsolate(); | 3661 v8::Isolate* iso = env->GetIsolate(); |
3650 HandleScope scope(iso); | 3662 HandleScope scope(iso); |
3651 | 3663 |
3652 WeakCallCounter counter(1234); | 3664 WeakCallCounter counter(1234); |
3653 | 3665 |
3654 Persistent<Value> g1s1; | 3666 WeakCallCounterAndPersistent<Value> g1s1(&counter); |
3655 Persistent<Value> g1s2; | 3667 WeakCallCounterAndPersistent<Value> g1s2(&counter); |
3656 Persistent<Value> g2s1; | 3668 WeakCallCounterAndPersistent<Value> g2s1(&counter); |
3657 Persistent<Value> g2s2; | 3669 WeakCallCounterAndPersistent<Value> g2s2(&counter); |
3658 Persistent<Value> g3s1; | 3670 WeakCallCounterAndPersistent<Value> g3s1(&counter); |
3659 Persistent<Value> g3s2; | 3671 WeakCallCounterAndPersistent<Value> g3s2(&counter); |
3660 Persistent<Value> g4s1; | 3672 WeakCallCounterAndPersistent<Value> g4s1(&counter); |
3661 Persistent<Value> g4s2; | 3673 WeakCallCounterAndPersistent<Value> g4s2(&counter); |
3662 | 3674 |
3663 { | 3675 { |
3664 HandleScope scope(iso); | 3676 HandleScope scope(iso); |
3665 g1s1.Reset(iso, Object::New()); | 3677 g1s1.handle.Reset(iso, Object::New()); |
3666 g1s2.Reset(iso, Object::New()); | 3678 g1s2.handle.Reset(iso, Object::New()); |
3667 g1s1.MakeWeak(&counter, &WeakPointerCallback); | 3679 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); |
3668 g1s2.MakeWeak(&counter, &WeakPointerCallback); | 3680 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); |
3669 CHECK(g1s1.IsWeak()); | 3681 CHECK(g1s1.handle.IsWeak()); |
3670 CHECK(g1s2.IsWeak()); | 3682 CHECK(g1s2.handle.IsWeak()); |
3671 | 3683 |
3672 g2s1.Reset(iso, Object::New()); | 3684 g2s1.handle.Reset(iso, Object::New()); |
3673 g2s2.Reset(iso, Object::New()); | 3685 g2s2.handle.Reset(iso, Object::New()); |
3674 g2s1.MakeWeak(&counter, &WeakPointerCallback); | 3686 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); |
3675 g2s2.MakeWeak(&counter, &WeakPointerCallback); | 3687 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); |
3676 CHECK(g2s1.IsWeak()); | 3688 CHECK(g2s1.handle.IsWeak()); |
3677 CHECK(g2s2.IsWeak()); | 3689 CHECK(g2s2.handle.IsWeak()); |
3678 | 3690 |
3679 g3s1.Reset(iso, Object::New()); | 3691 g3s1.handle.Reset(iso, Object::New()); |
3680 g3s2.Reset(iso, Object::New()); | 3692 g3s2.handle.Reset(iso, Object::New()); |
3681 g3s1.MakeWeak(&counter, &WeakPointerCallback); | 3693 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); |
3682 g3s2.MakeWeak(&counter, &WeakPointerCallback); | 3694 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); |
3683 CHECK(g3s1.IsWeak()); | 3695 CHECK(g3s1.handle.IsWeak()); |
3684 CHECK(g3s2.IsWeak()); | 3696 CHECK(g3s2.handle.IsWeak()); |
3685 | 3697 |
3686 g4s1.Reset(iso, Object::New()); | 3698 g4s1.handle.Reset(iso, Object::New()); |
3687 g4s2.Reset(iso, Object::New()); | 3699 g4s2.handle.Reset(iso, Object::New()); |
3688 g4s1.MakeWeak(&counter, &WeakPointerCallback); | 3700 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback); |
3689 g4s2.MakeWeak(&counter, &WeakPointerCallback); | 3701 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback); |
3690 CHECK(g4s1.IsWeak()); | 3702 CHECK(g4s1.handle.IsWeak()); |
3691 CHECK(g4s2.IsWeak()); | 3703 CHECK(g4s2.handle.IsWeak()); |
3692 } | 3704 } |
3693 | 3705 |
3694 Persistent<Value> root(iso, g1s1); // make a root. | 3706 WeakCallCounterAndPersistent<Value> root(&counter); |
| 3707 root.handle.Reset(iso, g1s1.handle); // make a root. |
3695 | 3708 |
3696 // Connect groups. We're building the following cycle: | 3709 // Connect groups. We're building the following cycle: |
3697 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other | 3710 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other |
3698 // groups. | 3711 // groups. |
3699 { | 3712 { |
3700 UniqueId id1 = MakeUniqueId(g1s1); | 3713 UniqueId id1 = MakeUniqueId(g1s1.handle); |
3701 UniqueId id2 = MakeUniqueId(g2s1); | 3714 UniqueId id2 = MakeUniqueId(g2s1.handle); |
3702 UniqueId id3 = MakeUniqueId(g3s1); | 3715 UniqueId id3 = MakeUniqueId(g3s1.handle); |
3703 UniqueId id4 = MakeUniqueId(g4s1); | 3716 UniqueId id4 = MakeUniqueId(g4s1.handle); |
3704 iso->SetObjectGroupId(g1s1, id1); | 3717 iso->SetObjectGroupId(g1s1.handle, id1); |
3705 iso->SetObjectGroupId(g1s2, id1); | 3718 iso->SetObjectGroupId(g1s2.handle, id1); |
3706 iso->SetReferenceFromGroup(id1, g2s1); | 3719 iso->SetReferenceFromGroup(id1, g2s1.handle); |
3707 iso->SetObjectGroupId(g2s1, id2); | 3720 iso->SetObjectGroupId(g2s1.handle, id2); |
3708 iso->SetObjectGroupId(g2s2, id2); | 3721 iso->SetObjectGroupId(g2s2.handle, id2); |
3709 iso->SetReferenceFromGroup(id2, g3s1); | 3722 iso->SetReferenceFromGroup(id2, g3s1.handle); |
3710 iso->SetObjectGroupId(g3s1, id3); | 3723 iso->SetObjectGroupId(g3s1.handle, id3); |
3711 iso->SetObjectGroupId(g3s2, id3); | 3724 iso->SetObjectGroupId(g3s2.handle, id3); |
3712 iso->SetReferenceFromGroup(id3, g4s1); | 3725 iso->SetReferenceFromGroup(id3, g4s1.handle); |
3713 iso->SetObjectGroupId(g4s1, id4); | 3726 iso->SetObjectGroupId(g4s1.handle, id4); |
3714 iso->SetObjectGroupId(g4s2, id4); | 3727 iso->SetObjectGroupId(g4s2.handle, id4); |
3715 iso->SetReferenceFromGroup(id4, g1s1); | 3728 iso->SetReferenceFromGroup(id4, g1s1.handle); |
3716 } | 3729 } |
3717 // Do a single full GC | 3730 // Do a single full GC |
3718 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( | 3731 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( |
3719 iso)->heap(); | 3732 iso)->heap(); |
3720 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3733 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3721 | 3734 |
3722 // All object should be alive. | 3735 // All object should be alive. |
3723 CHECK_EQ(0, counter.NumberOfWeakCalls()); | 3736 CHECK_EQ(0, counter.NumberOfWeakCalls()); |
3724 | 3737 |
3725 // Weaken the root. | 3738 // Weaken the root. |
3726 root.MakeWeak(&counter, &WeakPointerCallback); | 3739 root.handle.SetWeak(&root, &WeakPointerCallback); |
3727 | 3740 |
3728 // Groups are deleted, rebuild groups. | 3741 // Groups are deleted, rebuild groups. |
3729 { | 3742 { |
3730 UniqueId id1 = MakeUniqueId(g1s1); | 3743 UniqueId id1 = MakeUniqueId(g1s1.handle); |
3731 UniqueId id2 = MakeUniqueId(g2s1); | 3744 UniqueId id2 = MakeUniqueId(g2s1.handle); |
3732 UniqueId id3 = MakeUniqueId(g3s1); | 3745 UniqueId id3 = MakeUniqueId(g3s1.handle); |
3733 UniqueId id4 = MakeUniqueId(g4s1); | 3746 UniqueId id4 = MakeUniqueId(g4s1.handle); |
3734 iso->SetObjectGroupId(g1s1, id1); | 3747 iso->SetObjectGroupId(g1s1.handle, id1); |
3735 iso->SetObjectGroupId(g1s2, id1); | 3748 iso->SetObjectGroupId(g1s2.handle, id1); |
3736 iso->SetReferenceFromGroup(id1, g2s1); | 3749 iso->SetReferenceFromGroup(id1, g2s1.handle); |
3737 iso->SetObjectGroupId(g2s1, id2); | 3750 iso->SetObjectGroupId(g2s1.handle, id2); |
3738 iso->SetObjectGroupId(g2s2, id2); | 3751 iso->SetObjectGroupId(g2s2.handle, id2); |
3739 iso->SetReferenceFromGroup(id2, g3s1); | 3752 iso->SetReferenceFromGroup(id2, g3s1.handle); |
3740 iso->SetObjectGroupId(g3s1, id3); | 3753 iso->SetObjectGroupId(g3s1.handle, id3); |
3741 iso->SetObjectGroupId(g3s2, id3); | 3754 iso->SetObjectGroupId(g3s2.handle, id3); |
3742 iso->SetReferenceFromGroup(id3, g4s1); | 3755 iso->SetReferenceFromGroup(id3, g4s1.handle); |
3743 iso->SetObjectGroupId(g4s1, id4); | 3756 iso->SetObjectGroupId(g4s1.handle, id4); |
3744 iso->SetObjectGroupId(g4s2, id4); | 3757 iso->SetObjectGroupId(g4s2.handle, id4); |
3745 iso->SetReferenceFromGroup(id4, g1s1); | 3758 iso->SetReferenceFromGroup(id4, g1s1.handle); |
3746 } | 3759 } |
3747 | 3760 |
3748 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3761 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
3749 | 3762 |
3750 // All objects should be gone. 9 global handles in total. | 3763 // All objects should be gone. 9 global handles in total. |
3751 CHECK_EQ(9, counter.NumberOfWeakCalls()); | 3764 CHECK_EQ(9, counter.NumberOfWeakCalls()); |
3752 } | 3765 } |
3753 | 3766 |
3754 | 3767 |
3755 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures | 3768 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures |
3756 // on the buildbots, so was made non-threaded for the time being. | 3769 // on the buildbots, so was made non-threaded for the time being. |
3757 TEST(ApiObjectGroupsCycleForScavenger) { | 3770 TEST(ApiObjectGroupsCycleForScavenger) { |
3758 i::FLAG_stress_compaction = false; | 3771 i::FLAG_stress_compaction = false; |
3759 i::FLAG_gc_global = false; | 3772 i::FLAG_gc_global = false; |
3760 LocalContext env; | 3773 LocalContext env; |
3761 v8::Isolate* iso = env->GetIsolate(); | 3774 v8::Isolate* iso = env->GetIsolate(); |
3762 HandleScope scope(iso); | 3775 HandleScope scope(iso); |
3763 | 3776 |
3764 WeakCallCounter counter(1234); | 3777 WeakCallCounter counter(1234); |
3765 | 3778 |
3766 Persistent<Value> g1s1; | 3779 WeakCallCounterAndPersistent<Value> g1s1(&counter); |
3767 Persistent<Value> g1s2; | 3780 WeakCallCounterAndPersistent<Value> g1s2(&counter); |
3768 Persistent<Value> g2s1; | 3781 WeakCallCounterAndPersistent<Value> g2s1(&counter); |
3769 Persistent<Value> g2s2; | 3782 WeakCallCounterAndPersistent<Value> g2s2(&counter); |
3770 Persistent<Value> g3s1; | 3783 WeakCallCounterAndPersistent<Value> g3s1(&counter); |
3771 Persistent<Value> g3s2; | 3784 WeakCallCounterAndPersistent<Value> g3s2(&counter); |
3772 | 3785 |
3773 { | 3786 { |
3774 HandleScope scope(iso); | 3787 HandleScope scope(iso); |
3775 g1s1.Reset(iso, Object::New()); | 3788 g1s1.handle.Reset(iso, Object::New()); |
3776 g1s2.Reset(iso, Object::New()); | 3789 g1s2.handle.Reset(iso, Object::New()); |
3777 g1s1.MakeWeak(&counter, &WeakPointerCallback); | 3790 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback); |
3778 g1s2.MakeWeak(&counter, &WeakPointerCallback); | 3791 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback); |
3779 | 3792 |
3780 g2s1.Reset(iso, Object::New()); | 3793 g2s1.handle.Reset(iso, Object::New()); |
3781 g2s2.Reset(iso, Object::New()); | 3794 g2s2.handle.Reset(iso, Object::New()); |
3782 g2s1.MakeWeak(&counter, &WeakPointerCallback); | 3795 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback); |
3783 g2s2.MakeWeak(&counter, &WeakPointerCallback); | 3796 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback); |
3784 | 3797 |
3785 g3s1.Reset(iso, Object::New()); | 3798 g3s1.handle.Reset(iso, Object::New()); |
3786 g3s2.Reset(iso, Object::New()); | 3799 g3s2.handle.Reset(iso, Object::New()); |
3787 g3s1.MakeWeak(&counter, &WeakPointerCallback); | 3800 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback); |
3788 g3s2.MakeWeak(&counter, &WeakPointerCallback); | 3801 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback); |
3789 } | 3802 } |
3790 | 3803 |
3791 // Make a root. | 3804 // Make a root. |
3792 Persistent<Value> root(iso, g1s1); | 3805 WeakCallCounterAndPersistent<Value> root(&counter); |
3793 root.MarkPartiallyDependent(); | 3806 root.handle.Reset(iso, g1s1.handle); |
| 3807 root.handle.MarkPartiallyDependent(); |
3794 | 3808 |
3795 // Connect groups. We're building the following cycle: | 3809 // Connect groups. We're building the following cycle: |
3796 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other | 3810 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other |
3797 // groups. | 3811 // groups. |
3798 { | 3812 { |
3799 HandleScope handle_scope(iso); | 3813 HandleScope handle_scope(iso); |
3800 g1s1.MarkPartiallyDependent(); | 3814 g1s1.handle.MarkPartiallyDependent(); |
3801 g1s2.MarkPartiallyDependent(); | 3815 g1s2.handle.MarkPartiallyDependent(); |
3802 g2s1.MarkPartiallyDependent(); | 3816 g2s1.handle.MarkPartiallyDependent(); |
3803 g2s2.MarkPartiallyDependent(); | 3817 g2s2.handle.MarkPartiallyDependent(); |
3804 g3s1.MarkPartiallyDependent(); | 3818 g3s1.handle.MarkPartiallyDependent(); |
3805 g3s2.MarkPartiallyDependent(); | 3819 g3s2.handle.MarkPartiallyDependent(); |
3806 iso->SetObjectGroupId(g1s1, UniqueId(1)); | 3820 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); |
3807 iso->SetObjectGroupId(g1s2, UniqueId(1)); | 3821 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); |
3808 Local<Object>::New(iso, g1s1.As<Object>())->Set( | 3822 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( |
3809 v8_str("x"), Local<Value>::New(iso, g2s1)); | 3823 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); |
3810 iso->SetObjectGroupId(g2s1, UniqueId(2)); | 3824 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); |
3811 iso->SetObjectGroupId(g2s2, UniqueId(2)); | 3825 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); |
3812 Local<Object>::New(iso, g2s1.As<Object>())->Set( | 3826 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( |
3813 v8_str("x"), Local<Value>::New(iso, g3s1)); | 3827 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); |
3814 iso->SetObjectGroupId(g3s1, UniqueId(3)); | 3828 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); |
3815 iso->SetObjectGroupId(g3s2, UniqueId(3)); | 3829 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); |
3816 Local<Object>::New(iso, g3s1.As<Object>())->Set( | 3830 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( |
3817 v8_str("x"), Local<Value>::New(iso, g1s1)); | 3831 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); |
3818 } | 3832 } |
3819 | 3833 |
3820 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( | 3834 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( |
3821 iso)->heap(); | 3835 iso)->heap(); |
3822 heap->CollectGarbage(i::NEW_SPACE); | 3836 heap->CollectGarbage(i::NEW_SPACE); |
3823 | 3837 |
3824 // All objects should be alive. | 3838 // All objects should be alive. |
3825 CHECK_EQ(0, counter.NumberOfWeakCalls()); | 3839 CHECK_EQ(0, counter.NumberOfWeakCalls()); |
3826 | 3840 |
3827 // Weaken the root. | 3841 // Weaken the root. |
3828 root.MakeWeak(&counter, &WeakPointerCallback); | 3842 root.handle.SetWeak(&root, &WeakPointerCallback); |
3829 root.MarkPartiallyDependent(); | 3843 root.handle.MarkPartiallyDependent(); |
3830 | 3844 |
3831 // Groups are deleted, rebuild groups. | 3845 // Groups are deleted, rebuild groups. |
3832 { | 3846 { |
3833 HandleScope handle_scope(iso); | 3847 HandleScope handle_scope(iso); |
3834 g1s1.MarkPartiallyDependent(); | 3848 g1s1.handle.MarkPartiallyDependent(); |
3835 g1s2.MarkPartiallyDependent(); | 3849 g1s2.handle.MarkPartiallyDependent(); |
3836 g2s1.MarkPartiallyDependent(); | 3850 g2s1.handle.MarkPartiallyDependent(); |
3837 g2s2.MarkPartiallyDependent(); | 3851 g2s2.handle.MarkPartiallyDependent(); |
3838 g3s1.MarkPartiallyDependent(); | 3852 g3s1.handle.MarkPartiallyDependent(); |
3839 g3s2.MarkPartiallyDependent(); | 3853 g3s2.handle.MarkPartiallyDependent(); |
3840 iso->SetObjectGroupId(g1s1, UniqueId(1)); | 3854 iso->SetObjectGroupId(g1s1.handle, UniqueId(1)); |
3841 iso->SetObjectGroupId(g1s2, UniqueId(1)); | 3855 iso->SetObjectGroupId(g1s2.handle, UniqueId(1)); |
3842 Local<Object>::New(iso, g1s1.As<Object>())->Set( | 3856 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set( |
3843 v8_str("x"), Local<Value>::New(iso, g2s1)); | 3857 v8_str("x"), Local<Value>::New(iso, g2s1.handle)); |
3844 iso->SetObjectGroupId(g2s1, UniqueId(2)); | 3858 iso->SetObjectGroupId(g2s1.handle, UniqueId(2)); |
3845 iso->SetObjectGroupId(g2s2, UniqueId(2)); | 3859 iso->SetObjectGroupId(g2s2.handle, UniqueId(2)); |
3846 Local<Object>::New(iso, g2s1.As<Object>())->Set( | 3860 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set( |
3847 v8_str("x"), Local<Value>::New(iso, g3s1)); | 3861 v8_str("x"), Local<Value>::New(iso, g3s1.handle)); |
3848 iso->SetObjectGroupId(g3s1, UniqueId(3)); | 3862 iso->SetObjectGroupId(g3s1.handle, UniqueId(3)); |
3849 iso->SetObjectGroupId(g3s2, UniqueId(3)); | 3863 iso->SetObjectGroupId(g3s2.handle, UniqueId(3)); |
3850 Local<Object>::New(iso, g3s1.As<Object>())->Set( | 3864 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set( |
3851 v8_str("x"), Local<Value>::New(iso, g1s1)); | 3865 v8_str("x"), Local<Value>::New(iso, g1s1.handle)); |
3852 } | 3866 } |
3853 | 3867 |
3854 heap->CollectGarbage(i::NEW_SPACE); | 3868 heap->CollectGarbage(i::NEW_SPACE); |
3855 | 3869 |
3856 // All objects should be gone. 7 global handles in total. | 3870 // All objects should be gone. 7 global handles in total. |
3857 CHECK_EQ(7, counter.NumberOfWeakCalls()); | 3871 CHECK_EQ(7, counter.NumberOfWeakCalls()); |
3858 } | 3872 } |
3859 | 3873 |
3860 | 3874 |
3861 THREADED_TEST(ScriptException) { | 3875 THREADED_TEST(ScriptException) { |
(...skipping 3078 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6940 LocalContext context; | 6954 LocalContext context; |
6941 v8::HandleScope scope(context->GetIsolate()); | 6955 v8::HandleScope scope(context->GetIsolate()); |
6942 v8::V8::AddMessageListener(MissingScriptInfoMessageListener); | 6956 v8::V8::AddMessageListener(MissingScriptInfoMessageListener); |
6943 Script::Compile(v8_str("throw Error()"))->Run(); | 6957 Script::Compile(v8_str("throw Error()"))->Run(); |
6944 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener); | 6958 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener); |
6945 } | 6959 } |
6946 | 6960 |
6947 | 6961 |
6948 int global_index = 0; | 6962 int global_index = 0; |
6949 | 6963 |
| 6964 template<typename T> |
6950 class Snorkel { | 6965 class Snorkel { |
6951 public: | 6966 public: |
6952 Snorkel() { index_ = global_index++; } | 6967 explicit Snorkel(v8::Persistent<T>* handle) : handle_(handle) { |
| 6968 index_ = global_index++; |
| 6969 } |
| 6970 v8::Persistent<T>* handle_; |
6953 int index_; | 6971 int index_; |
6954 }; | 6972 }; |
6955 | 6973 |
6956 class Whammy { | 6974 class Whammy { |
6957 public: | 6975 public: |
6958 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { } | 6976 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { } |
6959 ~Whammy() { script_.Reset(); } | 6977 ~Whammy() { script_.Reset(); } |
6960 v8::Handle<Script> getScript() { | 6978 v8::Handle<Script> getScript() { |
6961 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo")); | 6979 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo")); |
6962 return Local<Script>::New(isolate_, script_); | 6980 return Local<Script>::New(isolate_, script_); |
6963 } | 6981 } |
6964 | 6982 |
6965 public: | 6983 public: |
6966 static const int kObjectCount = 256; | 6984 static const int kObjectCount = 256; |
6967 int cursor_; | 6985 int cursor_; |
6968 v8::Isolate* isolate_; | 6986 v8::Isolate* isolate_; |
6969 v8::Persistent<v8::Object> objects_[kObjectCount]; | 6987 v8::Persistent<v8::Object> objects_[kObjectCount]; |
6970 v8::Persistent<Script> script_; | 6988 v8::Persistent<Script> script_; |
6971 }; | 6989 }; |
6972 | 6990 |
6973 static void HandleWeakReference(v8::Isolate* isolate, | 6991 static void HandleWeakReference( |
6974 v8::Persistent<v8::Value>* obj, | 6992 const v8::WeakCallbackData<v8::Value, Snorkel<v8::Value> >& data) { |
6975 Snorkel* snorkel) { | 6993 data.GetParameter()->handle_->ClearWeak(); |
6976 delete snorkel; | 6994 delete data.GetParameter(); |
6977 obj->ClearWeak(); | |
6978 } | 6995 } |
6979 | 6996 |
6980 void WhammyPropertyGetter(Local<String> name, | 6997 void WhammyPropertyGetter(Local<String> name, |
6981 const v8::PropertyCallbackInfo<v8::Value>& info) { | 6998 const v8::PropertyCallbackInfo<v8::Value>& info) { |
6982 Whammy* whammy = | 6999 Whammy* whammy = |
6983 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); | 7000 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); |
6984 | 7001 |
6985 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_]; | 7002 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_]; |
6986 | 7003 |
6987 v8::Handle<v8::Object> obj = v8::Object::New(); | 7004 v8::Handle<v8::Object> obj = v8::Object::New(); |
6988 if (!prev.IsEmpty()) { | 7005 if (!prev.IsEmpty()) { |
6989 v8::Local<v8::Object>::New(info.GetIsolate(), prev) | 7006 v8::Local<v8::Object>::New(info.GetIsolate(), prev) |
6990 ->Set(v8_str("next"), obj); | 7007 ->Set(v8_str("next"), obj); |
6991 prev.MakeWeak<Value, Snorkel>(new Snorkel(), &HandleWeakReference); | 7008 prev.SetWeak<Value, Snorkel<Value> >(new Snorkel<Value>(&prev.As<Value>()), |
| 7009 &HandleWeakReference); |
6992 } | 7010 } |
6993 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj); | 7011 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj); |
6994 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount; | 7012 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount; |
6995 info.GetReturnValue().Set(whammy->getScript()->Run()); | 7013 info.GetReturnValue().Set(whammy->getScript()->Run()); |
6996 } | 7014 } |
6997 | 7015 |
6998 | 7016 |
6999 THREADED_TEST(WeakReference) { | 7017 THREADED_TEST(WeakReference) { |
7000 v8::HandleScope handle_scope(CcTest::isolate()); | 7018 v8::HandleScope handle_scope(CcTest::isolate()); |
7001 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(); | 7019 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(); |
(...skipping 17 matching lines...) Expand all Loading... |
7019 " last = obj;" | 7037 " last = obj;" |
7020 "}" | 7038 "}" |
7021 "gc();" | 7039 "gc();" |
7022 "4"; | 7040 "4"; |
7023 v8::Handle<Value> result = CompileRun(code); | 7041 v8::Handle<Value> result = CompileRun(code); |
7024 CHECK_EQ(4.0, result->NumberValue()); | 7042 CHECK_EQ(4.0, result->NumberValue()); |
7025 delete whammy; | 7043 delete whammy; |
7026 } | 7044 } |
7027 | 7045 |
7028 | 7046 |
7029 static void DisposeAndSetFlag(v8::Isolate* isolate, | 7047 struct FlagAndPersistent { |
7030 v8::Persistent<v8::Object>* obj, | 7048 bool flag; |
7031 bool* data) { | 7049 v8::Persistent<v8::Object> handle; |
7032 obj->Reset(); | 7050 }; |
7033 *(data) = true; | 7051 |
| 7052 |
| 7053 static void DisposeAndSetFlag( |
| 7054 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { |
| 7055 data.GetParameter()->handle.Reset(); |
| 7056 data.GetParameter()->flag = true; |
7034 } | 7057 } |
7035 | 7058 |
7036 | 7059 |
7037 THREADED_TEST(IndependentWeakHandle) { | 7060 THREADED_TEST(IndependentWeakHandle) { |
7038 v8::Isolate* iso = CcTest::isolate(); | 7061 v8::Isolate* iso = CcTest::isolate(); |
7039 v8::HandleScope scope(iso); | 7062 v8::HandleScope scope(iso); |
7040 v8::Handle<Context> context = Context::New(iso); | 7063 v8::Handle<Context> context = Context::New(iso); |
7041 Context::Scope context_scope(context); | 7064 Context::Scope context_scope(context); |
7042 | 7065 |
7043 v8::Persistent<v8::Object> object_a, object_b; | 7066 FlagAndPersistent object_a, object_b; |
7044 | 7067 |
7045 { | 7068 { |
7046 v8::HandleScope handle_scope(iso); | 7069 v8::HandleScope handle_scope(iso); |
7047 object_a.Reset(iso, v8::Object::New()); | 7070 object_a.handle.Reset(iso, v8::Object::New()); |
7048 object_b.Reset(iso, v8::Object::New()); | 7071 object_b.handle.Reset(iso, v8::Object::New()); |
7049 } | 7072 } |
7050 | 7073 |
7051 bool object_a_disposed = false; | 7074 object_a.flag = false; |
7052 bool object_b_disposed = false; | 7075 object_b.flag = false; |
7053 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag); | 7076 object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag); |
7054 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag); | 7077 object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag); |
7055 CHECK(!object_b.IsIndependent()); | 7078 CHECK(!object_b.handle.IsIndependent()); |
7056 object_a.MarkIndependent(); | 7079 object_a.handle.MarkIndependent(); |
7057 object_b.MarkIndependent(); | 7080 object_b.handle.MarkIndependent(); |
7058 CHECK(object_b.IsIndependent()); | 7081 CHECK(object_b.handle.IsIndependent()); |
7059 CcTest::heap()->PerformScavenge(); | 7082 CcTest::heap()->PerformScavenge(); |
7060 CHECK(object_a_disposed); | 7083 CHECK(object_a.flag); |
7061 CHECK(object_b_disposed); | 7084 CHECK(object_b.flag); |
7062 } | 7085 } |
7063 | 7086 |
7064 | 7087 |
7065 static void InvokeScavenge() { | 7088 static void InvokeScavenge() { |
7066 CcTest::heap()->PerformScavenge(); | 7089 CcTest::heap()->PerformScavenge(); |
7067 } | 7090 } |
7068 | 7091 |
7069 | 7092 |
7070 static void InvokeMarkSweep() { | 7093 static void InvokeMarkSweep() { |
7071 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); | 7094 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); |
7072 } | 7095 } |
7073 | 7096 |
7074 | 7097 |
7075 static void ForceScavenge(v8::Isolate* isolate, | 7098 static void ForceScavenge( |
7076 v8::Persistent<v8::Object>* obj, | 7099 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { |
7077 bool* data) { | 7100 data.GetParameter()->handle.Reset(); |
7078 obj->Reset(); | 7101 data.GetParameter()->flag = true; |
7079 *(data) = true; | |
7080 InvokeScavenge(); | 7102 InvokeScavenge(); |
7081 } | 7103 } |
7082 | 7104 |
7083 | 7105 |
7084 static void ForceMarkSweep(v8::Isolate* isolate, | 7106 static void ForceMarkSweep( |
7085 v8::Persistent<v8::Object>* obj, | 7107 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { |
7086 bool* data) { | 7108 data.GetParameter()->handle.Reset(); |
7087 obj->Reset(); | 7109 data.GetParameter()->flag = true; |
7088 *(data) = true; | |
7089 InvokeMarkSweep(); | 7110 InvokeMarkSweep(); |
7090 } | 7111 } |
7091 | 7112 |
7092 | 7113 |
7093 THREADED_TEST(GCFromWeakCallbacks) { | 7114 THREADED_TEST(GCFromWeakCallbacks) { |
7094 v8::Isolate* isolate = CcTest::isolate(); | 7115 v8::Isolate* isolate = CcTest::isolate(); |
7095 v8::HandleScope scope(isolate); | 7116 v8::HandleScope scope(isolate); |
7096 v8::Handle<Context> context = Context::New(isolate); | 7117 v8::Handle<Context> context = Context::New(isolate); |
7097 Context::Scope context_scope(context); | 7118 Context::Scope context_scope(context); |
7098 | 7119 |
7099 static const int kNumberOfGCTypes = 2; | 7120 static const int kNumberOfGCTypes = 2; |
7100 typedef v8::WeakReferenceCallbacks<v8::Object, bool>::Revivable Callback; | 7121 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback |
| 7122 Callback; |
7101 Callback gc_forcing_callback[kNumberOfGCTypes] = | 7123 Callback gc_forcing_callback[kNumberOfGCTypes] = |
7102 {&ForceScavenge, &ForceMarkSweep}; | 7124 {&ForceScavenge, &ForceMarkSweep}; |
7103 | 7125 |
7104 typedef void (*GCInvoker)(); | 7126 typedef void (*GCInvoker)(); |
7105 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; | 7127 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; |
7106 | 7128 |
7107 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { | 7129 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { |
7108 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { | 7130 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { |
7109 v8::Persistent<v8::Object> object; | 7131 FlagAndPersistent object; |
7110 { | 7132 { |
7111 v8::HandleScope handle_scope(isolate); | 7133 v8::HandleScope handle_scope(isolate); |
7112 object.Reset(isolate, v8::Object::New()); | 7134 object.handle.Reset(isolate, v8::Object::New()); |
7113 } | 7135 } |
7114 bool disposed = false; | 7136 object.flag = false; |
7115 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]); | 7137 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]); |
7116 object.MarkIndependent(); | 7138 object.handle.MarkIndependent(); |
7117 invoke_gc[outer_gc](); | 7139 invoke_gc[outer_gc](); |
7118 CHECK(disposed); | 7140 CHECK(object.flag); |
7119 } | 7141 } |
7120 } | 7142 } |
7121 } | 7143 } |
7122 | 7144 |
7123 | 7145 |
7124 static void RevivingCallback(v8::Isolate* isolate, | 7146 static void RevivingCallback( |
7125 v8::Persistent<v8::Object>* obj, | 7147 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) { |
7126 bool* data) { | 7148 data.GetParameter()->handle.ClearWeak(); |
7127 obj->ClearWeak(); | 7149 data.GetParameter()->flag = true; |
7128 *(data) = true; | |
7129 } | 7150 } |
7130 | 7151 |
7131 | 7152 |
7132 THREADED_TEST(IndependentHandleRevival) { | 7153 THREADED_TEST(IndependentHandleRevival) { |
7133 v8::Isolate* isolate = CcTest::isolate(); | 7154 v8::Isolate* isolate = CcTest::isolate(); |
7134 v8::HandleScope scope(isolate); | 7155 v8::HandleScope scope(isolate); |
7135 v8::Handle<Context> context = Context::New(isolate); | 7156 v8::Handle<Context> context = Context::New(isolate); |
7136 Context::Scope context_scope(context); | 7157 Context::Scope context_scope(context); |
7137 | 7158 |
7138 v8::Persistent<v8::Object> object; | 7159 FlagAndPersistent object; |
7139 { | 7160 { |
7140 v8::HandleScope handle_scope(isolate); | 7161 v8::HandleScope handle_scope(isolate); |
7141 v8::Local<v8::Object> o = v8::Object::New(); | 7162 v8::Local<v8::Object> o = v8::Object::New(); |
7142 object.Reset(isolate, o); | 7163 object.handle.Reset(isolate, o); |
7143 o->Set(v8_str("x"), v8::Integer::New(1)); | 7164 o->Set(v8_str("x"), v8::Integer::New(1)); |
7144 v8::Local<String> y_str = v8_str("y"); | 7165 v8::Local<String> y_str = v8_str("y"); |
7145 o->Set(y_str, y_str); | 7166 o->Set(y_str, y_str); |
7146 } | 7167 } |
7147 bool revived = false; | 7168 object.flag = false; |
7148 object.MakeWeak(&revived, &RevivingCallback); | 7169 object.handle.SetWeak(&object, &RevivingCallback); |
7149 object.MarkIndependent(); | 7170 object.handle.MarkIndependent(); |
7150 CcTest::heap()->PerformScavenge(); | 7171 CcTest::heap()->PerformScavenge(); |
7151 CHECK(revived); | 7172 CHECK(object.flag); |
7152 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 7173 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
7153 { | 7174 { |
7154 v8::HandleScope handle_scope(isolate); | 7175 v8::HandleScope handle_scope(isolate); |
7155 v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, object); | 7176 v8::Local<v8::Object> o = |
| 7177 v8::Local<v8::Object>::New(isolate, object.handle); |
7156 v8::Local<String> y_str = v8_str("y"); | 7178 v8::Local<String> y_str = v8_str("y"); |
7157 CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x"))); | 7179 CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x"))); |
7158 CHECK(o->Get(y_str)->Equals(y_str)); | 7180 CHECK(o->Get(y_str)->Equals(y_str)); |
7159 } | 7181 } |
7160 } | 7182 } |
7161 | 7183 |
7162 | 7184 |
7163 v8::Handle<Function> args_fun; | 7185 v8::Handle<Function> args_fun; |
7164 | 7186 |
7165 | 7187 |
(...skipping 5933 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13099 reinterpret_cast<i::Isolate*>(isolate)->heap()-> | 13121 reinterpret_cast<i::Isolate*>(isolate)->heap()-> |
13100 CollectAllGarbage(i::Heap::kNoGCFlags); | 13122 CollectAllGarbage(i::Heap::kNoGCFlags); |
13101 // Verify disposed. | 13123 // Verify disposed. |
13102 CHECK_EQ(initial_handles, globals->global_handles_count()); | 13124 CHECK_EQ(initial_handles, globals->global_handles_count()); |
13103 } | 13125 } |
13104 | 13126 |
13105 | 13127 |
13106 v8::Persistent<v8::Object> some_object; | 13128 v8::Persistent<v8::Object> some_object; |
13107 v8::Persistent<v8::Object> bad_handle; | 13129 v8::Persistent<v8::Object> bad_handle; |
13108 | 13130 |
13109 void NewPersistentHandleCallback(v8::Isolate* isolate, | 13131 void NewPersistentHandleCallback( |
13110 v8::Persistent<v8::Value>* handle, | 13132 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { |
13111 void*) { | 13133 v8::HandleScope scope(data.GetIsolate()); |
13112 v8::HandleScope scope(isolate); | 13134 bad_handle.Reset(data.GetIsolate(), some_object); |
13113 bad_handle.Reset(isolate, some_object); | 13135 data.GetParameter()->Reset(); |
13114 handle->Reset(); | |
13115 } | 13136 } |
13116 | 13137 |
13117 | 13138 |
13118 THREADED_TEST(NewPersistentHandleFromWeakCallback) { | 13139 THREADED_TEST(NewPersistentHandleFromWeakCallback) { |
13119 LocalContext context; | 13140 LocalContext context; |
13120 v8::Isolate* isolate = context->GetIsolate(); | 13141 v8::Isolate* isolate = context->GetIsolate(); |
13121 | 13142 |
13122 v8::Persistent<v8::Object> handle1, handle2; | 13143 v8::Persistent<v8::Object> handle1, handle2; |
13123 { | 13144 { |
13124 v8::HandleScope scope(isolate); | 13145 v8::HandleScope scope(isolate); |
13125 some_object.Reset(isolate, v8::Object::New()); | 13146 some_object.Reset(isolate, v8::Object::New()); |
13126 handle1.Reset(isolate, v8::Object::New()); | 13147 handle1.Reset(isolate, v8::Object::New()); |
13127 handle2.Reset(isolate, v8::Object::New()); | 13148 handle2.Reset(isolate, v8::Object::New()); |
13128 } | 13149 } |
13129 // Note: order is implementation dependent alas: currently | 13150 // Note: order is implementation dependent alas: currently |
13130 // global handle nodes are processed by PostGarbageCollectionProcessing | 13151 // global handle nodes are processed by PostGarbageCollectionProcessing |
13131 // in reverse allocation order, so if second allocated handle is deleted, | 13152 // in reverse allocation order, so if second allocated handle is deleted, |
13132 // weak callback of the first handle would be able to 'reallocate' it. | 13153 // weak callback of the first handle would be able to 'reallocate' it. |
13133 handle1.MakeWeak<v8::Value, void>(NULL, NewPersistentHandleCallback); | 13154 handle1.SetWeak(&handle1, NewPersistentHandleCallback); |
13134 handle2.Reset(); | 13155 handle2.Reset(); |
13135 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); | 13156 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); |
13136 } | 13157 } |
13137 | 13158 |
13138 | 13159 |
13139 v8::Persistent<v8::Object> to_be_disposed; | 13160 v8::Persistent<v8::Object> to_be_disposed; |
13140 | 13161 |
13141 void DisposeAndForceGcCallback(v8::Isolate* isolate, | 13162 void DisposeAndForceGcCallback( |
13142 v8::Persistent<v8::Value>* handle, | 13163 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { |
13143 void*) { | |
13144 to_be_disposed.Reset(); | 13164 to_be_disposed.Reset(); |
13145 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); | 13165 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); |
13146 handle->Reset(); | 13166 data.GetParameter()->Reset(); |
13147 } | 13167 } |
13148 | 13168 |
13149 | 13169 |
13150 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { | 13170 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { |
13151 LocalContext context; | 13171 LocalContext context; |
13152 v8::Isolate* isolate = context->GetIsolate(); | 13172 v8::Isolate* isolate = context->GetIsolate(); |
13153 | 13173 |
13154 v8::Persistent<v8::Object> handle1, handle2; | 13174 v8::Persistent<v8::Object> handle1, handle2; |
13155 { | 13175 { |
13156 v8::HandleScope scope(isolate); | 13176 v8::HandleScope scope(isolate); |
13157 handle1.Reset(isolate, v8::Object::New()); | 13177 handle1.Reset(isolate, v8::Object::New()); |
13158 handle2.Reset(isolate, v8::Object::New()); | 13178 handle2.Reset(isolate, v8::Object::New()); |
13159 } | 13179 } |
13160 handle1.MakeWeak<v8::Value, void>(NULL, DisposeAndForceGcCallback); | 13180 handle1.SetWeak(&handle1, DisposeAndForceGcCallback); |
13161 to_be_disposed.Reset(isolate, handle2); | 13181 to_be_disposed.Reset(isolate, handle2); |
13162 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); | 13182 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); |
13163 } | 13183 } |
13164 | 13184 |
13165 void DisposingCallback(v8::Isolate* isolate, | 13185 void DisposingCallback( |
13166 v8::Persistent<v8::Value>* handle, | 13186 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { |
13167 void*) { | 13187 data.GetParameter()->Reset(); |
13168 handle->Reset(); | |
13169 } | 13188 } |
13170 | 13189 |
13171 void HandleCreatingCallback(v8::Isolate* isolate, | 13190 void HandleCreatingCallback( |
13172 v8::Persistent<v8::Value>* handle, | 13191 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) { |
13173 void*) { | 13192 v8::HandleScope scope(data.GetIsolate()); |
13174 v8::HandleScope scope(isolate); | 13193 v8::Persistent<v8::Object>(data.GetIsolate(), v8::Object::New()); |
13175 v8::Persistent<v8::Object>(isolate, v8::Object::New()); | 13194 data.GetParameter()->Reset(); |
13176 handle->Reset(); | |
13177 } | 13195 } |
13178 | 13196 |
13179 | 13197 |
13180 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { | 13198 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { |
13181 LocalContext context; | 13199 LocalContext context; |
13182 v8::Isolate* isolate = context->GetIsolate(); | 13200 v8::Isolate* isolate = context->GetIsolate(); |
13183 | 13201 |
13184 v8::Persistent<v8::Object> handle1, handle2, handle3; | 13202 v8::Persistent<v8::Object> handle1, handle2, handle3; |
13185 { | 13203 { |
13186 v8::HandleScope scope(isolate); | 13204 v8::HandleScope scope(isolate); |
13187 handle3.Reset(isolate, v8::Object::New()); | 13205 handle3.Reset(isolate, v8::Object::New()); |
13188 handle2.Reset(isolate, v8::Object::New()); | 13206 handle2.Reset(isolate, v8::Object::New()); |
13189 handle1.Reset(isolate, v8::Object::New()); | 13207 handle1.Reset(isolate, v8::Object::New()); |
13190 } | 13208 } |
13191 handle2.MakeWeak<v8::Value, void>(NULL, DisposingCallback); | 13209 handle2.SetWeak(&handle2, DisposingCallback); |
13192 handle3.MakeWeak<v8::Value, void>(NULL, HandleCreatingCallback); | 13210 handle3.SetWeak(&handle3, HandleCreatingCallback); |
13193 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); | 13211 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); |
13194 } | 13212 } |
13195 | 13213 |
13196 | 13214 |
13197 THREADED_TEST(CheckForCrossContextObjectLiterals) { | 13215 THREADED_TEST(CheckForCrossContextObjectLiterals) { |
13198 v8::V8::Initialize(); | 13216 v8::V8::Initialize(); |
13199 | 13217 |
13200 const int nof = 2; | 13218 const int nof = 2; |
13201 const char* sources[nof] = { | 13219 const char* sources[nof] = { |
13202 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", | 13220 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", |
(...skipping 7651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
20854 } | 20872 } |
20855 for (int i = 0; i < runs; i++) { | 20873 for (int i = 0; i < runs; i++) { |
20856 Local<String> expected; | 20874 Local<String> expected; |
20857 if (i != 0) { | 20875 if (i != 0) { |
20858 CHECK_EQ(v8_str("escape value"), values[i]); | 20876 CHECK_EQ(v8_str("escape value"), values[i]); |
20859 } else { | 20877 } else { |
20860 CHECK(values[i].IsEmpty()); | 20878 CHECK(values[i].IsEmpty()); |
20861 } | 20879 } |
20862 } | 20880 } |
20863 } | 20881 } |
OLD | NEW |