| 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 3300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3311 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { } | 3311 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { } |
| 3312 int id() { return id_; } | 3312 int id() { return id_; } |
| 3313 void increment() { number_of_weak_calls_++; } | 3313 void increment() { number_of_weak_calls_++; } |
| 3314 int NumberOfWeakCalls() { return number_of_weak_calls_; } | 3314 int NumberOfWeakCalls() { return number_of_weak_calls_; } |
| 3315 private: | 3315 private: |
| 3316 int id_; | 3316 int id_; |
| 3317 int number_of_weak_calls_; | 3317 int number_of_weak_calls_; |
| 3318 }; | 3318 }; |
| 3319 | 3319 |
| 3320 | 3320 |
| 3321 template<typename T> |
| 3321 static void WeakPointerCallback(v8::Isolate* isolate, | 3322 static void WeakPointerCallback(v8::Isolate* isolate, |
| 3322 Persistent<Value>* handle, | 3323 Persistent<T>* handle, |
| 3323 WeakCallCounter* counter) { | 3324 WeakCallCounter* counter) { |
| 3324 CHECK_EQ(1234, counter->id()); | 3325 CHECK_EQ(1234, counter->id()); |
| 3325 counter->increment(); | 3326 counter->increment(); |
| 3326 handle->Dispose(); | 3327 handle->Dispose(); |
| 3327 } | 3328 } |
| 3328 | 3329 |
| 3329 | 3330 |
| 3330 static UniqueId MakeUniqueId(const Persistent<Value>& p) { | 3331 template<typename T> |
| 3332 static UniqueId MakeUniqueId(const Persistent<T>& p) { |
| 3331 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); | 3333 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); |
| 3332 } | 3334 } |
| 3333 | 3335 |
| 3334 | 3336 |
| 3335 THREADED_TEST(ApiObjectGroups) { | 3337 THREADED_TEST(ApiObjectGroups) { |
| 3336 LocalContext env; | 3338 LocalContext env; |
| 3337 v8::Isolate* iso = env->GetIsolate(); | 3339 v8::Isolate* iso = env->GetIsolate(); |
| 3338 HandleScope scope(iso); | 3340 HandleScope scope(iso); |
| 3339 | 3341 |
| 3340 Persistent<Value> g1s1; | 3342 Persistent<Value> g1s1; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3418 | 3420 |
| 3419 // And now make children weak again and collect them. | 3421 // And now make children weak again and collect them. |
| 3420 g1c1.MakeWeak(&counter, &WeakPointerCallback); | 3422 g1c1.MakeWeak(&counter, &WeakPointerCallback); |
| 3421 g2c1.MakeWeak(&counter, &WeakPointerCallback); | 3423 g2c1.MakeWeak(&counter, &WeakPointerCallback); |
| 3422 | 3424 |
| 3423 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); | 3425 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
| 3424 CHECK_EQ(7, counter.NumberOfWeakCalls()); | 3426 CHECK_EQ(7, counter.NumberOfWeakCalls()); |
| 3425 } | 3427 } |
| 3426 | 3428 |
| 3427 | 3429 |
| 3430 THREADED_TEST(ApiObjectGroupsForSubtypes) { |
| 3431 LocalContext env; |
| 3432 v8::Isolate* iso = env->GetIsolate(); |
| 3433 HandleScope scope(iso); |
| 3434 |
| 3435 Persistent<Object> g1s1; |
| 3436 Persistent<String> g1s2; |
| 3437 Persistent<String> g1c1; |
| 3438 Persistent<Object> g2s1; |
| 3439 Persistent<String> g2s2; |
| 3440 Persistent<String> g2c1; |
| 3441 |
| 3442 WeakCallCounter counter(1234); |
| 3443 |
| 3444 { |
| 3445 HandleScope scope(iso); |
| 3446 g1s1.Reset(iso, Object::New()); |
| 3447 g1s2.Reset(iso, String::New("foo1")); |
| 3448 g1c1.Reset(iso, String::New("foo2")); |
| 3449 g1s1.MakeWeak(&counter, &WeakPointerCallback); |
| 3450 g1s2.MakeWeak(&counter, &WeakPointerCallback); |
| 3451 g1c1.MakeWeak(&counter, &WeakPointerCallback); |
| 3452 |
| 3453 g2s1.Reset(iso, Object::New()); |
| 3454 g2s2.Reset(iso, String::New("foo3")); |
| 3455 g2c1.Reset(iso, String::New("foo4")); |
| 3456 g2s1.MakeWeak(&counter, &WeakPointerCallback); |
| 3457 g2s2.MakeWeak(&counter, &WeakPointerCallback); |
| 3458 g2c1.MakeWeak(&counter, &WeakPointerCallback); |
| 3459 } |
| 3460 |
| 3461 Persistent<Value> root(iso, g1s1); // make a root. |
| 3462 |
| 3463 // Connect group 1 and 2, make a cycle. |
| 3464 { |
| 3465 HandleScope scope(iso); |
| 3466 CHECK(Local<Object>::New(iso, g1s1)->Set(0, Local<Object>::New(iso, g2s1))); |
| 3467 CHECK(Local<Object>::New(iso, g2s1)->Set(0, Local<Object>::New(iso, g1s1))); |
| 3468 } |
| 3469 |
| 3470 { |
| 3471 UniqueId id1 = MakeUniqueId(g1s1); |
| 3472 UniqueId id2 = MakeUniqueId(g2s2); |
| 3473 iso->SetObjectGroupId(g1s1, id1); |
| 3474 iso->SetObjectGroupId(g1s2, id1); |
| 3475 iso->SetReference(g1s1, g1c1); |
| 3476 iso->SetObjectGroupId(g2s1, id2); |
| 3477 iso->SetObjectGroupId(g2s2, id2); |
| 3478 iso->SetReferenceFromGroup(id2, g2c1); |
| 3479 } |
| 3480 // Do a single full GC, ensure incremental marking is stopped. |
| 3481 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( |
| 3482 iso)->heap(); |
| 3483 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
| 3484 |
| 3485 // All object should be alive. |
| 3486 CHECK_EQ(0, counter.NumberOfWeakCalls()); |
| 3487 |
| 3488 // Weaken the root. |
| 3489 root.MakeWeak(&counter, &WeakPointerCallback); |
| 3490 // But make children strong roots---all the objects (except for children) |
| 3491 // should be collectable now. |
| 3492 g1c1.ClearWeak(); |
| 3493 g2c1.ClearWeak(); |
| 3494 |
| 3495 // Groups are deleted, rebuild groups. |
| 3496 { |
| 3497 UniqueId id1 = MakeUniqueId(g1s1); |
| 3498 UniqueId id2 = MakeUniqueId(g2s2); |
| 3499 iso->SetObjectGroupId(g1s1, id1); |
| 3500 iso->SetObjectGroupId(g1s2, id1); |
| 3501 iso->SetReference(g1s1, g1c1); |
| 3502 iso->SetObjectGroupId(g2s1, id2); |
| 3503 iso->SetObjectGroupId(g2s2, id2); |
| 3504 iso->SetReferenceFromGroup(id2, g2c1); |
| 3505 } |
| 3506 |
| 3507 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
| 3508 |
| 3509 // All objects should be gone. 5 global handles in total. |
| 3510 CHECK_EQ(5, counter.NumberOfWeakCalls()); |
| 3511 |
| 3512 // And now make children weak again and collect them. |
| 3513 g1c1.MakeWeak(&counter, &WeakPointerCallback); |
| 3514 g2c1.MakeWeak(&counter, &WeakPointerCallback); |
| 3515 |
| 3516 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); |
| 3517 CHECK_EQ(7, counter.NumberOfWeakCalls()); |
| 3518 } |
| 3519 |
| 3520 |
| 3428 THREADED_TEST(ApiObjectGroupsCycle) { | 3521 THREADED_TEST(ApiObjectGroupsCycle) { |
| 3429 LocalContext env; | 3522 LocalContext env; |
| 3430 v8::Isolate* iso = env->GetIsolate(); | 3523 v8::Isolate* iso = env->GetIsolate(); |
| 3431 HandleScope scope(iso); | 3524 HandleScope scope(iso); |
| 3432 | 3525 |
| 3433 WeakCallCounter counter(1234); | 3526 WeakCallCounter counter(1234); |
| 3434 | 3527 |
| 3435 Persistent<Value> g1s1; | 3528 Persistent<Value> g1s1; |
| 3436 Persistent<Value> g1s2; | 3529 Persistent<Value> g1s2; |
| 3437 Persistent<Value> g2s1; | 3530 Persistent<Value> g2s1; |
| (...skipping 10878 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14316 // result has the 'x' property. | 14409 // result has the 'x' property. |
| 14317 context1->Enter(); | 14410 context1->Enter(); |
| 14318 context1->Global()->Set(v8_str("other"), context0->Global()); | 14411 context1->Global()->Set(v8_str("other"), context0->Global()); |
| 14319 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); | 14412 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); |
| 14320 CHECK(value->IsInt32()); | 14413 CHECK(value->IsInt32()); |
| 14321 CHECK_EQ(42, value->Int32Value()); | 14414 CHECK_EQ(42, value->Int32Value()); |
| 14322 context1->Exit(); | 14415 context1->Exit(); |
| 14323 } | 14416 } |
| 14324 | 14417 |
| 14325 | 14418 |
| 14326 class RegExpInterruptTest { | |
| 14327 public: | |
| 14328 RegExpInterruptTest() : block_(0) {} | |
| 14329 ~RegExpInterruptTest() {} | |
| 14330 void RunTest() { | |
| 14331 gc_count_ = 0; | |
| 14332 gc_during_regexp_ = 0; | |
| 14333 regexp_success_ = false; | |
| 14334 gc_success_ = false; | |
| 14335 GCThread gc_thread(this); | |
| 14336 gc_thread.Start(); | |
| 14337 v8::Isolate* isolate = CcTest::isolate(); | |
| 14338 v8::Locker::StartPreemption(isolate, 1); | |
| 14339 | |
| 14340 LongRunningRegExp(); | |
| 14341 { | |
| 14342 v8::Unlocker unlock(isolate); | |
| 14343 gc_thread.Join(); | |
| 14344 } | |
| 14345 v8::Locker::StopPreemption(isolate); | |
| 14346 CHECK(regexp_success_); | |
| 14347 CHECK(gc_success_); | |
| 14348 } | |
| 14349 | |
| 14350 private: | |
| 14351 // Number of garbage collections required. | |
| 14352 static const int kRequiredGCs = 5; | |
| 14353 | |
| 14354 class GCThread : public i::Thread { | |
| 14355 public: | |
| 14356 explicit GCThread(RegExpInterruptTest* test) | |
| 14357 : Thread("GCThread"), test_(test) {} | |
| 14358 virtual void Run() { | |
| 14359 test_->CollectGarbage(); | |
| 14360 } | |
| 14361 private: | |
| 14362 RegExpInterruptTest* test_; | |
| 14363 }; | |
| 14364 | |
| 14365 void CollectGarbage() { | |
| 14366 block_.Wait(); | |
| 14367 while (gc_during_regexp_ < kRequiredGCs) { | |
| 14368 { | |
| 14369 v8::Locker lock(CcTest::isolate()); | |
| 14370 v8::Isolate::Scope isolate_scope(CcTest::isolate()); | |
| 14371 // TODO(lrn): Perhaps create some garbage before collecting. | |
| 14372 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags); | |
| 14373 gc_count_++; | |
| 14374 } | |
| 14375 i::OS::Sleep(1); | |
| 14376 } | |
| 14377 gc_success_ = true; | |
| 14378 } | |
| 14379 | |
| 14380 void LongRunningRegExp() { | |
| 14381 block_.Signal(); // Enable garbage collection thread on next preemption. | |
| 14382 int rounds = 0; | |
| 14383 while (gc_during_regexp_ < kRequiredGCs) { | |
| 14384 int gc_before = gc_count_; | |
| 14385 { | |
| 14386 // Match 15-30 "a"'s against 14 and a "b". | |
| 14387 const char* c_source = | |
| 14388 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" | |
| 14389 ".exec('aaaaaaaaaaaaaaab') === null"; | |
| 14390 Local<String> source = String::New(c_source); | |
| 14391 Local<Script> script = Script::Compile(source); | |
| 14392 Local<Value> result = script->Run(); | |
| 14393 if (!result->BooleanValue()) { | |
| 14394 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit. | |
| 14395 return; | |
| 14396 } | |
| 14397 } | |
| 14398 { | |
| 14399 // Match 15-30 "a"'s against 15 and a "b". | |
| 14400 const char* c_source = | |
| 14401 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" | |
| 14402 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'"; | |
| 14403 Local<String> source = String::New(c_source); | |
| 14404 Local<Script> script = Script::Compile(source); | |
| 14405 Local<Value> result = script->Run(); | |
| 14406 if (!result->BooleanValue()) { | |
| 14407 gc_during_regexp_ = kRequiredGCs; | |
| 14408 return; | |
| 14409 } | |
| 14410 } | |
| 14411 int gc_after = gc_count_; | |
| 14412 gc_during_regexp_ += gc_after - gc_before; | |
| 14413 rounds++; | |
| 14414 i::OS::Sleep(1); | |
| 14415 } | |
| 14416 regexp_success_ = true; | |
| 14417 } | |
| 14418 | |
| 14419 i::Semaphore block_; | |
| 14420 int gc_count_; | |
| 14421 int gc_during_regexp_; | |
| 14422 bool regexp_success_; | |
| 14423 bool gc_success_; | |
| 14424 }; | |
| 14425 | |
| 14426 | |
| 14427 // Test that a regular expression execution can be interrupted and | |
| 14428 // survive a garbage collection. | |
| 14429 TEST(RegExpInterruption) { | |
| 14430 v8::Locker lock(CcTest::isolate()); | |
| 14431 v8::HandleScope scope(CcTest::isolate()); | |
| 14432 Local<Context> local_env; | |
| 14433 { | |
| 14434 LocalContext env; | |
| 14435 local_env = env.local(); | |
| 14436 } | |
| 14437 | |
| 14438 // Local context should still be live. | |
| 14439 CHECK(!local_env.IsEmpty()); | |
| 14440 local_env->Enter(); | |
| 14441 | |
| 14442 // Should complete without problems. | |
| 14443 RegExpInterruptTest().RunTest(); | |
| 14444 | |
| 14445 local_env->Exit(); | |
| 14446 } | |
| 14447 | |
| 14448 | |
| 14449 class ApplyInterruptTest { | 14419 class ApplyInterruptTest { |
| 14450 public: | 14420 public: |
| 14451 ApplyInterruptTest() : block_(0) {} | 14421 ApplyInterruptTest() : block_(0) {} |
| 14452 ~ApplyInterruptTest() {} | 14422 ~ApplyInterruptTest() {} |
| 14453 void RunTest() { | 14423 void RunTest() { |
| 14454 gc_count_ = 0; | 14424 gc_count_ = 0; |
| 14455 gc_during_apply_ = 0; | 14425 gc_during_apply_ = 0; |
| 14456 apply_success_ = false; | 14426 apply_success_ = false; |
| 14457 gc_success_ = false; | 14427 gc_success_ = false; |
| 14458 GCThread gc_thread(this); | 14428 GCThread gc_thread(this); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 14728 UC16VectorResource uc16_resource( | 14698 UC16VectorResource uc16_resource( |
| 14729 i::Vector<const uint16_t>(two_byte_string, | 14699 i::Vector<const uint16_t>(two_byte_string, |
| 14730 i::StrLength(ascii_sources[i]))); | 14700 i::StrLength(ascii_sources[i]))); |
| 14731 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource); | 14701 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource); |
| 14732 v8::Script::Compile(source); | 14702 v8::Script::Compile(source); |
| 14733 i::DeleteArray(two_byte_string); | 14703 i::DeleteArray(two_byte_string); |
| 14734 } | 14704 } |
| 14735 } | 14705 } |
| 14736 | 14706 |
| 14737 | 14707 |
| 14738 class RegExpStringModificationTest { | 14708 #ifndef V8_INTERPRETED_REGEXP |
| 14709 |
| 14710 struct RegExpInterruptionData { |
| 14711 int loop_count; |
| 14712 UC16VectorResource* string_resource; |
| 14713 v8::Persistent<v8::String> string; |
| 14714 } regexp_interruption_data; |
| 14715 |
| 14716 |
| 14717 class RegExpInterruptionThread : public i::Thread { |
| 14739 public: | 14718 public: |
| 14740 RegExpStringModificationTest() | 14719 explicit RegExpInterruptionThread(v8::Isolate* isolate) |
| 14741 : block_(0), | 14720 : Thread("TimeoutThread"), isolate_(isolate) {} |
| 14742 morphs_(0), | |
| 14743 morphs_during_regexp_(0), | |
| 14744 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)), | |
| 14745 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {} | |
| 14746 ~RegExpStringModificationTest() {} | |
| 14747 void RunTest() { | |
| 14748 v8::Isolate* isolate = CcTest::isolate(); | |
| 14749 i::Factory* factory = CcTest::i_isolate()->factory(); | |
| 14750 | 14721 |
| 14751 regexp_success_ = false; | 14722 virtual void Run() { |
| 14752 morph_success_ = false; | 14723 for (regexp_interruption_data.loop_count = 0; |
| 14753 | 14724 regexp_interruption_data.loop_count < 7; |
| 14754 // Initialize the contents of two_byte_content_ to be a uc16 representation | 14725 regexp_interruption_data.loop_count++) { |
| 14755 // of "aaaaaaaaaaaaaab". | 14726 i::OS::Sleep(50); // Wait a bit before requesting GC. |
| 14756 for (int i = 0; i < 14; i++) { | 14727 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); |
| 14757 two_byte_content_[i] = 'a'; | |
| 14758 } | 14728 } |
| 14759 two_byte_content_[14] = 'b'; | 14729 i::OS::Sleep(50); // Wait a bit before terminating. |
| 14760 | 14730 v8::V8::TerminateExecution(isolate_); |
| 14761 // Create the input string for the regexp - the one we are going to change | |
| 14762 // properties of. | |
| 14763 input_ = factory->NewExternalStringFromAscii(&ascii_resource_); | |
| 14764 | |
| 14765 // Inject the input as a global variable. | |
| 14766 i::Handle<i::String> input_name = | |
| 14767 factory->NewStringFromAscii(i::Vector<const char>("input", 5)); | |
| 14768 i::JSReceiver::SetProperty( | |
| 14769 i::handle(CcTest::i_isolate()->native_context()->global_object()), | |
| 14770 input_name, | |
| 14771 input_, | |
| 14772 NONE, | |
| 14773 i::kNonStrictMode); | |
| 14774 | |
| 14775 MorphThread morph_thread(this); | |
| 14776 morph_thread.Start(); | |
| 14777 v8::Locker::StartPreemption(isolate, 1); | |
| 14778 LongRunningRegExp(); | |
| 14779 { | |
| 14780 v8::Unlocker unlock(isolate); | |
| 14781 morph_thread.Join(); | |
| 14782 } | |
| 14783 v8::Locker::StopPreemption(isolate); | |
| 14784 CHECK(regexp_success_); | |
| 14785 CHECK(morph_success_); | |
| 14786 } | 14731 } |
| 14787 | 14732 |
| 14788 private: | 14733 private: |
| 14789 // Number of string modifications required. | 14734 v8::Isolate* isolate_; |
| 14790 static const int kRequiredModifications = 5; | |
| 14791 static const int kMaxModifications = 100; | |
| 14792 | |
| 14793 class MorphThread : public i::Thread { | |
| 14794 public: | |
| 14795 explicit MorphThread(RegExpStringModificationTest* test) | |
| 14796 : Thread("MorphThread"), test_(test) {} | |
| 14797 virtual void Run() { | |
| 14798 test_->MorphString(); | |
| 14799 } | |
| 14800 private: | |
| 14801 RegExpStringModificationTest* test_; | |
| 14802 }; | |
| 14803 | |
| 14804 void MorphString() { | |
| 14805 block_.Wait(); | |
| 14806 while (morphs_during_regexp_ < kRequiredModifications && | |
| 14807 morphs_ < kMaxModifications) { | |
| 14808 { | |
| 14809 v8::Locker lock(CcTest::isolate()); | |
| 14810 v8::Isolate::Scope isolate_scope(CcTest::isolate()); | |
| 14811 // Swap string between ascii and two-byte representation. | |
| 14812 i::String* string = *input_; | |
| 14813 MorphAString(string, &ascii_resource_, &uc16_resource_); | |
| 14814 morphs_++; | |
| 14815 } | |
| 14816 i::OS::Sleep(1); | |
| 14817 } | |
| 14818 morph_success_ = true; | |
| 14819 } | |
| 14820 | |
| 14821 void LongRunningRegExp() { | |
| 14822 block_.Signal(); // Enable morphing thread on next preemption. | |
| 14823 while (morphs_during_regexp_ < kRequiredModifications && | |
| 14824 morphs_ < kMaxModifications) { | |
| 14825 int morphs_before = morphs_; | |
| 14826 { | |
| 14827 v8::HandleScope scope(CcTest::isolate()); | |
| 14828 // Match 15-30 "a"'s against 14 and a "b". | |
| 14829 const char* c_source = | |
| 14830 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" | |
| 14831 ".exec(input) === null"; | |
| 14832 Local<String> source = String::New(c_source); | |
| 14833 Local<Script> script = Script::Compile(source); | |
| 14834 Local<Value> result = script->Run(); | |
| 14835 CHECK(result->IsTrue()); | |
| 14836 } | |
| 14837 int morphs_after = morphs_; | |
| 14838 morphs_during_regexp_ += morphs_after - morphs_before; | |
| 14839 } | |
| 14840 regexp_success_ = true; | |
| 14841 } | |
| 14842 | |
| 14843 i::uc16 two_byte_content_[15]; | |
| 14844 i::Semaphore block_; | |
| 14845 int morphs_; | |
| 14846 int morphs_during_regexp_; | |
| 14847 bool regexp_success_; | |
| 14848 bool morph_success_; | |
| 14849 i::Handle<i::String> input_; | |
| 14850 AsciiVectorResource ascii_resource_; | |
| 14851 UC16VectorResource uc16_resource_; | |
| 14852 }; | 14735 }; |
| 14853 | 14736 |
| 14854 | 14737 |
| 14855 // Test that a regular expression execution can be interrupted and | 14738 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) { |
| 14856 // the string changed without failing. | 14739 if (regexp_interruption_data.loop_count != 2) return; |
| 14857 TEST(RegExpStringModification) { | |
| 14858 v8::Locker lock(CcTest::isolate()); | |
| 14859 v8::HandleScope scope(CcTest::isolate()); | 14740 v8::HandleScope scope(CcTest::isolate()); |
| 14860 Local<Context> local_env; | 14741 v8::Local<v8::String> string = v8::Local<v8::String>::New( |
| 14861 { | 14742 CcTest::isolate(), regexp_interruption_data.string); |
| 14862 LocalContext env; | 14743 string->MakeExternal(regexp_interruption_data.string_resource); |
| 14863 local_env = env.local(); | 14744 } |
| 14864 } | |
| 14865 | 14745 |
| 14866 // Local context should still be live. | |
| 14867 CHECK(!local_env.IsEmpty()); | |
| 14868 local_env->Enter(); | |
| 14869 | 14746 |
| 14870 // Should complete without problems. | 14747 // Test that RegExp execution can be interrupted. Specifically, we test |
| 14871 RegExpStringModificationTest().RunTest(); | 14748 // * interrupting with GC |
| 14749 // * turn the subject string from one-byte internal to two-byte external string |
| 14750 // * force termination |
| 14751 TEST(RegExpInterruption) { |
| 14752 v8::HandleScope scope(CcTest::isolate()); |
| 14753 LocalContext env; |
| 14872 | 14754 |
| 14873 local_env->Exit(); | 14755 RegExpInterruptionThread timeout_thread(CcTest::isolate()); |
| 14756 |
| 14757 v8::V8::AddGCPrologueCallback(RunBeforeGC); |
| 14758 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; |
| 14759 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content); |
| 14760 v8::Local<v8::String> string = v8_str(ascii_content); |
| 14761 |
| 14762 CcTest::global()->Set(v8_str("a"), string); |
| 14763 regexp_interruption_data.string.Reset(CcTest::isolate(), string); |
| 14764 regexp_interruption_data.string_resource = new UC16VectorResource( |
| 14765 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content))); |
| 14766 |
| 14767 v8::TryCatch try_catch; |
| 14768 timeout_thread.Start(); |
| 14769 |
| 14770 CompileRun("/((a*)*)*b/.exec(a)"); |
| 14771 CHECK(try_catch.HasTerminated()); |
| 14772 |
| 14773 timeout_thread.Join(); |
| 14774 |
| 14775 delete regexp_interruption_data.string_resource; |
| 14776 regexp_interruption_data.string.Dispose(); |
| 14874 } | 14777 } |
| 14875 | 14778 |
| 14779 #endif // V8_INTERPRETED_REGEXP |
| 14780 |
| 14876 | 14781 |
| 14877 // Test that we cannot set a property on the global object if there | 14782 // Test that we cannot set a property on the global object if there |
| 14878 // is a read-only property in the prototype chain. | 14783 // is a read-only property in the prototype chain. |
| 14879 TEST(ReadOnlyPropertyInGlobalProto) { | 14784 TEST(ReadOnlyPropertyInGlobalProto) { |
| 14880 i::FLAG_es5_readonly = true; | 14785 i::FLAG_es5_readonly = true; |
| 14881 v8::HandleScope scope(CcTest::isolate()); | 14786 v8::HandleScope scope(CcTest::isolate()); |
| 14882 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); | 14787 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); |
| 14883 LocalContext context(0, templ); | 14788 LocalContext context(0, templ); |
| 14884 v8::Handle<v8::Object> global = context->Global(); | 14789 v8::Handle<v8::Object> global = context->Global(); |
| 14885 v8::Handle<v8::Object> global_proto = | 14790 v8::Handle<v8::Object> global_proto = |
| (...skipping 2706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 17592 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); | 17497 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); |
| 17593 v8::Handle<v8::String> script = v8::String::New( | 17498 v8::Handle<v8::String> script = v8::String::New( |
| 17594 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); | 17499 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); |
| 17595 v8::Script::Compile(script, &origin)->Run(); | 17500 v8::Script::Compile(script, &origin)->Run(); |
| 17596 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( | 17501 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( |
| 17597 env->Global()->Get(v8::String::New("f"))); | 17502 env->Global()->Get(v8::String::New("f"))); |
| 17598 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())); | 17503 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())); |
| 17599 } | 17504 } |
| 17600 | 17505 |
| 17601 | 17506 |
| 17507 THREADED_TEST(FunctionGetDisplayName) { |
| 17508 LocalContext env; |
| 17509 v8::HandleScope scope(env->GetIsolate()); |
| 17510 const char* code = "var error = false;" |
| 17511 "function a() { this.x = 1; };" |
| 17512 "a.displayName = 'display_a';" |
| 17513 "var b = (function() {" |
| 17514 " var f = function() { this.x = 2; };" |
| 17515 " f.displayName = 'display_b';" |
| 17516 " return f;" |
| 17517 "})();" |
| 17518 "var c = function() {};" |
| 17519 "c.__defineGetter__('displayName', function() {" |
| 17520 " error = true;" |
| 17521 " throw new Error();" |
| 17522 "});" |
| 17523 "function d() {};" |
| 17524 "d.__defineGetter__('displayName', function() {" |
| 17525 " error = true;" |
| 17526 " return 'wrong_display_name';" |
| 17527 "});" |
| 17528 "function e() {};" |
| 17529 "e.displayName = 'wrong_display_name';" |
| 17530 "e.__defineSetter__('displayName', function() {" |
| 17531 " error = true;" |
| 17532 " throw new Error();" |
| 17533 "});" |
| 17534 "function f() {};" |
| 17535 "f.displayName = { 'foo': 6, toString: function() {" |
| 17536 " error = true;" |
| 17537 " return 'wrong_display_name';" |
| 17538 "}};" |
| 17539 "var g = function() {" |
| 17540 " arguments.callee.displayName = 'set_in_runtime';" |
| 17541 "}; g();" |
| 17542 ; |
| 17543 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); |
| 17544 v8::Script::Compile(v8::String::New(code), &origin)->Run(); |
| 17545 v8::Local<v8::Value> error = env->Global()->Get(v8::String::New("error")); |
| 17546 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast( |
| 17547 env->Global()->Get(v8::String::New("a"))); |
| 17548 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast( |
| 17549 env->Global()->Get(v8::String::New("b"))); |
| 17550 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast( |
| 17551 env->Global()->Get(v8::String::New("c"))); |
| 17552 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast( |
| 17553 env->Global()->Get(v8::String::New("d"))); |
| 17554 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast( |
| 17555 env->Global()->Get(v8::String::New("e"))); |
| 17556 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( |
| 17557 env->Global()->Get(v8::String::New("f"))); |
| 17558 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( |
| 17559 env->Global()->Get(v8::String::New("g"))); |
| 17560 CHECK_EQ(false, error->BooleanValue()); |
| 17561 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName())); |
| 17562 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName())); |
| 17563 CHECK(c->GetDisplayName()->IsUndefined()); |
| 17564 CHECK(d->GetDisplayName()->IsUndefined()); |
| 17565 CHECK(e->GetDisplayName()->IsUndefined()); |
| 17566 CHECK(f->GetDisplayName()->IsUndefined()); |
| 17567 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())); |
| 17568 } |
| 17569 |
| 17570 |
| 17602 THREADED_TEST(ScriptLineNumber) { | 17571 THREADED_TEST(ScriptLineNumber) { |
| 17603 LocalContext env; | 17572 LocalContext env; |
| 17604 v8::HandleScope scope(env->GetIsolate()); | 17573 v8::HandleScope scope(env->GetIsolate()); |
| 17605 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); | 17574 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); |
| 17606 v8::Handle<v8::String> script = v8::String::New( | 17575 v8::Handle<v8::String> script = v8::String::New( |
| 17607 "function f() {}\n\nfunction g() {}"); | 17576 "function f() {}\n\nfunction g() {}"); |
| 17608 v8::Script::Compile(script, &origin)->Run(); | 17577 v8::Script::Compile(script, &origin)->Run(); |
| 17609 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( | 17578 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( |
| 17610 env->Global()->Get(v8::String::New("f"))); | 17579 env->Global()->Get(v8::String::New("f"))); |
| 17611 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( | 17580 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( |
| (...skipping 13 matching lines...) Expand all Loading... |
| 17625 v8::Script::Compile(script, &origin)->Run(); | 17594 v8::Script::Compile(script, &origin)->Run(); |
| 17626 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( | 17595 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( |
| 17627 env->Global()->Get(v8::String::New("foo"))); | 17596 env->Global()->Get(v8::String::New("foo"))); |
| 17628 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( | 17597 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( |
| 17629 env->Global()->Get(v8::String::New("bar"))); | 17598 env->Global()->Get(v8::String::New("bar"))); |
| 17630 CHECK_EQ(14, foo->GetScriptColumnNumber()); | 17599 CHECK_EQ(14, foo->GetScriptColumnNumber()); |
| 17631 CHECK_EQ(17, bar->GetScriptColumnNumber()); | 17600 CHECK_EQ(17, bar->GetScriptColumnNumber()); |
| 17632 } | 17601 } |
| 17633 | 17602 |
| 17634 | 17603 |
| 17604 THREADED_TEST(FunctionIsBuiltin) { |
| 17605 LocalContext env; |
| 17606 v8::HandleScope scope(env->GetIsolate()); |
| 17607 v8::Local<v8::Function> f; |
| 17608 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor")); |
| 17609 CHECK(f->IsBuiltin()); |
| 17610 f = v8::Local<v8::Function>::Cast(CompileRun("Object")); |
| 17611 CHECK(f->IsBuiltin()); |
| 17612 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__")); |
| 17613 CHECK(f->IsBuiltin()); |
| 17614 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString")); |
| 17615 CHECK(f->IsBuiltin()); |
| 17616 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;")); |
| 17617 CHECK(!f->IsBuiltin()); |
| 17618 } |
| 17619 |
| 17620 |
| 17635 THREADED_TEST(FunctionGetScriptId) { | 17621 THREADED_TEST(FunctionGetScriptId) { |
| 17636 LocalContext env; | 17622 LocalContext env; |
| 17637 v8::HandleScope scope(env->GetIsolate()); | 17623 v8::HandleScope scope(env->GetIsolate()); |
| 17638 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"), | 17624 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"), |
| 17639 v8::Integer::New(3), v8::Integer::New(2)); | 17625 v8::Integer::New(3), v8::Integer::New(2)); |
| 17640 v8::Handle<v8::String> scriptSource = v8::String::New( | 17626 v8::Handle<v8::String> scriptSource = v8::String::New( |
| 17641 "function foo() {}\n\n function bar() {}"); | 17627 "function foo() {}\n\n function bar() {}"); |
| 17642 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin)); | 17628 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin)); |
| 17643 script->Run(); | 17629 script->Run(); |
| 17644 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( | 17630 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( |
| (...skipping 3080 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 20725 } | 20711 } |
| 20726 for (int i = 0; i < runs; i++) { | 20712 for (int i = 0; i < runs; i++) { |
| 20727 Local<String> expected; | 20713 Local<String> expected; |
| 20728 if (i != 0) { | 20714 if (i != 0) { |
| 20729 CHECK_EQ(v8_str("escape value"), values[i]); | 20715 CHECK_EQ(v8_str("escape value"), values[i]); |
| 20730 } else { | 20716 } else { |
| 20731 CHECK(values[i].IsEmpty()); | 20717 CHECK(values[i].IsEmpty()); |
| 20732 } | 20718 } |
| 20733 } | 20719 } |
| 20734 } | 20720 } |
| OLD | NEW |