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 14305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14316 // result has the 'x' property. | 14316 // result has the 'x' property. |
14317 context1->Enter(); | 14317 context1->Enter(); |
14318 context1->Global()->Set(v8_str("other"), context0->Global()); | 14318 context1->Global()->Set(v8_str("other"), context0->Global()); |
14319 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); | 14319 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); |
14320 CHECK(value->IsInt32()); | 14320 CHECK(value->IsInt32()); |
14321 CHECK_EQ(42, value->Int32Value()); | 14321 CHECK_EQ(42, value->Int32Value()); |
14322 context1->Exit(); | 14322 context1->Exit(); |
14323 } | 14323 } |
14324 | 14324 |
14325 | 14325 |
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 { | 14326 class ApplyInterruptTest { |
14450 public: | 14327 public: |
14451 ApplyInterruptTest() : block_(0) {} | 14328 ApplyInterruptTest() : block_(0) {} |
14452 ~ApplyInterruptTest() {} | 14329 ~ApplyInterruptTest() {} |
14453 void RunTest() { | 14330 void RunTest() { |
14454 gc_count_ = 0; | 14331 gc_count_ = 0; |
14455 gc_during_apply_ = 0; | 14332 gc_during_apply_ = 0; |
14456 apply_success_ = false; | 14333 apply_success_ = false; |
14457 gc_success_ = false; | 14334 gc_success_ = false; |
14458 GCThread gc_thread(this); | 14335 GCThread gc_thread(this); |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14728 UC16VectorResource uc16_resource( | 14605 UC16VectorResource uc16_resource( |
14729 i::Vector<const uint16_t>(two_byte_string, | 14606 i::Vector<const uint16_t>(two_byte_string, |
14730 i::StrLength(ascii_sources[i]))); | 14607 i::StrLength(ascii_sources[i]))); |
14731 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource); | 14608 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource); |
14732 v8::Script::Compile(source); | 14609 v8::Script::Compile(source); |
14733 i::DeleteArray(two_byte_string); | 14610 i::DeleteArray(two_byte_string); |
14734 } | 14611 } |
14735 } | 14612 } |
14736 | 14613 |
14737 | 14614 |
14738 class RegExpStringModificationTest { | 14615 struct RegExpInterruptionData { |
| 14616 int loop_count; |
| 14617 UC16VectorResource* string_resource; |
| 14618 v8::Persistent<v8::String> string; |
| 14619 } regexp_interruption_data; |
| 14620 |
| 14621 |
| 14622 class RegExpInterruptionThread : public i::Thread { |
14739 public: | 14623 public: |
14740 RegExpStringModificationTest() | 14624 explicit RegExpInterruptionThread(v8::Isolate* isolate) |
14741 : block_(0), | 14625 : 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 | 14626 |
14751 regexp_success_ = false; | 14627 virtual void Run() { |
14752 morph_success_ = false; | 14628 for (regexp_interruption_data.loop_count = 0; |
14753 | 14629 regexp_interruption_data.loop_count < 7; |
14754 // Initialize the contents of two_byte_content_ to be a uc16 representation | 14630 regexp_interruption_data.loop_count++) { |
14755 // of "aaaaaaaaaaaaaab". | 14631 i::OS::Sleep(50); // Wait a bit before requesting GC. |
14756 for (int i = 0; i < 14; i++) { | 14632 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC(); |
14757 two_byte_content_[i] = 'a'; | |
14758 } | 14633 } |
14759 two_byte_content_[14] = 'b'; | 14634 i::OS::Sleep(50); // Wait a bit before terminating. |
14760 | 14635 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 } | 14636 } |
14787 | 14637 |
14788 private: | 14638 private: |
14789 // Number of string modifications required. | 14639 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 }; | 14640 }; |
14853 | 14641 |
14854 | 14642 |
14855 // Test that a regular expression execution can be interrupted and | 14643 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) { |
14856 // the string changed without failing. | 14644 if (regexp_interruption_data.loop_count != 2) return; |
14857 TEST(RegExpStringModification) { | |
14858 v8::Locker lock(CcTest::isolate()); | |
14859 v8::HandleScope scope(CcTest::isolate()); | 14645 v8::HandleScope scope(CcTest::isolate()); |
14860 Local<Context> local_env; | 14646 v8::Local<v8::String> string = v8::Local<v8::String>::New( |
14861 { | 14647 CcTest::isolate(), regexp_interruption_data.string); |
14862 LocalContext env; | 14648 string->MakeExternal(regexp_interruption_data.string_resource); |
14863 local_env = env.local(); | |
14864 } | |
14865 | |
14866 // Local context should still be live. | |
14867 CHECK(!local_env.IsEmpty()); | |
14868 local_env->Enter(); | |
14869 | |
14870 // Should complete without problems. | |
14871 RegExpStringModificationTest().RunTest(); | |
14872 | |
14873 local_env->Exit(); | |
14874 } | 14649 } |
14875 | 14650 |
14876 | 14651 |
| 14652 // Test that RegExp execution can be interrupted. Specifically, we test |
| 14653 // * interrupting with GC |
| 14654 // * turn the subject string from one-byte internal to two-byte external string |
| 14655 // * force termination |
| 14656 TEST(RegExpInterruption) { |
| 14657 v8::HandleScope scope(CcTest::isolate()); |
| 14658 LocalContext env; |
| 14659 |
| 14660 RegExpInterruptionThread timeout_thread(CcTest::isolate()); |
| 14661 |
| 14662 v8::V8::AddGCPrologueCallback(RunBeforeGC); |
| 14663 static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; |
| 14664 i::uc16* uc16_content = AsciiToTwoByteString(ascii_content); |
| 14665 v8::Local<v8::String> string = v8_str(ascii_content); |
| 14666 |
| 14667 CcTest::global()->Set(v8_str("a"), string); |
| 14668 regexp_interruption_data.string.Reset(CcTest::isolate(), string); |
| 14669 regexp_interruption_data.string_resource = new UC16VectorResource( |
| 14670 i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content))); |
| 14671 |
| 14672 v8::TryCatch try_catch; |
| 14673 timeout_thread.Start(); |
| 14674 |
| 14675 CompileRun("/((a*)*)*b/.exec(a)"); |
| 14676 CHECK(try_catch.HasTerminated()); |
| 14677 |
| 14678 timeout_thread.Join(); |
| 14679 |
| 14680 delete regexp_interruption_data.string_resource; |
| 14681 regexp_interruption_data.string.Dispose(); |
| 14682 } |
| 14683 |
| 14684 |
14877 // Test that we cannot set a property on the global object if there | 14685 // Test that we cannot set a property on the global object if there |
14878 // is a read-only property in the prototype chain. | 14686 // is a read-only property in the prototype chain. |
14879 TEST(ReadOnlyPropertyInGlobalProto) { | 14687 TEST(ReadOnlyPropertyInGlobalProto) { |
14880 i::FLAG_es5_readonly = true; | 14688 i::FLAG_es5_readonly = true; |
14881 v8::HandleScope scope(CcTest::isolate()); | 14689 v8::HandleScope scope(CcTest::isolate()); |
14882 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); | 14690 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); |
14883 LocalContext context(0, templ); | 14691 LocalContext context(0, templ); |
14884 v8::Handle<v8::Object> global = context->Global(); | 14692 v8::Handle<v8::Object> global = context->Global(); |
14885 v8::Handle<v8::Object> global_proto = | 14693 v8::Handle<v8::Object> global_proto = |
14886 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); | 14694 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); |
(...skipping 5838 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
20725 } | 20533 } |
20726 for (int i = 0; i < runs; i++) { | 20534 for (int i = 0; i < runs; i++) { |
20727 Local<String> expected; | 20535 Local<String> expected; |
20728 if (i != 0) { | 20536 if (i != 0) { |
20729 CHECK_EQ(v8_str("escape value"), values[i]); | 20537 CHECK_EQ(v8_str("escape value"), values[i]); |
20730 } else { | 20538 } else { |
20731 CHECK(values[i].IsEmpty()); | 20539 CHECK(values[i].IsEmpty()); |
20732 } | 20540 } |
20733 } | 20541 } |
20734 } | 20542 } |
OLD | NEW |