Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: test/cctest/test-api.cc

Issue 26848011: Fix regexp interrupt test. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: beef up test Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698