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