Chromium Code Reviews| Index: test/cctest/test-api.cc |
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc |
| index 428b6365b95783fe70a20d2253a9aa12e162a766..f4ed084ca627b7aaed9d470b53513ec45ad985c0 100644 |
| --- a/test/cctest/test-api.cc |
| +++ b/test/cctest/test-api.cc |
| @@ -5685,6 +5685,8 @@ THREADED_TEST(CrossContextNew) { |
| class RegExpInterruptTest { |
| public: |
| + RegExpInterruptTest() : block_(NULL) {} |
| + ~RegExpInterruptTest() { delete block_; } |
| void RunTest() { |
| block_ = i::OS::CreateSemaphore(0); |
| gc_count_ = 0; |
| @@ -5704,8 +5706,6 @@ class RegExpInterruptTest { |
| CHECK(regexp_success_); |
| CHECK(gc_success_); |
| } |
| - RegExpInterruptTest() : block_(NULL) {} |
| - ~RegExpInterruptTest() { delete block_; } |
| private: |
| // Number of garbage collections required. |
| static const int kRequiredGCs = 5; |
| @@ -5741,7 +5741,7 @@ class RegExpInterruptTest { |
| while (gc_during_regexp_ < kRequiredGCs) { |
| int gc_before = gc_count_; |
| { |
| - // match 15-30 "a"'s against 14 and a "b". |
| + // Match 15-30 "a"'s against 14 and a "b". |
| const char* c_source = |
|
Erik Corry
2009/03/20 12:45:42
It would be nice to test GC during execution of a
Lasse Reichstein
2009/03/20 13:26:11
Are they more likely to fail?
In any case, that wo
|
| "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" |
| ".exec('aaaaaaaaaaaaaaab') === null"; |
| @@ -5754,7 +5754,7 @@ class RegExpInterruptTest { |
| } |
| } |
| { |
| - // match 15-30 "a"'s against 15 and a "b". |
| + // Match 15-30 "a"'s against 15 and a "b". |
| const char* c_source = |
| "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" |
| ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'"; |
| @@ -5837,3 +5837,171 @@ TEST(ObjectClone) { |
| CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); |
| CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta"))); |
| } |
| + |
| + |
| +class RegExpStringModificationTest { |
| + public: |
| + RegExpStringModificationTest() |
| + : two_byte_content_(), |
| + block_(i::OS::CreateSemaphore(0)), |
| + morphs_(0), |
| + morphs_during_regexp_(0), |
| + ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)), |
| + uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {} |
| + ~RegExpStringModificationTest() { delete block_; } |
| + void RunTest() { |
| + regexp_success_ = false; |
| + morph_success_ = false; |
| + |
| + for (int i = 0; i < 14; i++) { |
| + two_byte_content_[i] = 'a'; |
| + } |
| + two_byte_content_[14] = 'b'; |
| + |
| + // Create the input string for the regexp - the one we are going to change |
| + // properties of. |
| + input_ = i::Factory::NewExternalStringFromAscii(&ascii_resource_); |
| + |
| + // Inject the input as a global variable. |
| + i::Handle<i::String> input_name = |
| + i::Factory::NewStringFromAscii(i::Vector<const char>("input", 5)); |
| + i::Top::global_context()->global()->SetProperty(*input_name, *input_, NONE); |
| + |
| + |
| + MorphThread morph_thread(this); |
| + morph_thread.Start(); |
| + v8::Locker::StartPreemption(1); |
| + LongRunningRegExp(); |
| + { |
| + v8::Unlocker unlock; |
| + morph_thread.Join(); |
| + } |
| + v8::Locker::StopPreemption(); |
| + CHECK(regexp_success_); |
| + CHECK(morph_success_); |
| + } |
| + private: |
| + |
| + class AsciiVectorResource : public v8::String::ExternalAsciiStringResource { |
| + public: |
| + explicit AsciiVectorResource(i::Vector<const char> vector) |
| + : data_(vector) {} |
| + virtual ~AsciiVectorResource() {} |
| + virtual size_t length() const { return data_.length(); } |
| + virtual const char* data() const { return data_.start(); } |
| + private: |
| + i::Vector<const char> data_; |
| + }; |
| + class UC16VectorResource : public v8::String::ExternalStringResource { |
| + public: |
| + explicit UC16VectorResource(i::Vector<const i::uc16> vector) |
| + : data_(vector) {} |
| + virtual ~UC16VectorResource() {} |
| + virtual size_t length() const { return data_.length(); } |
| + virtual const i::uc16* data() const { return data_.start(); } |
| + private: |
| + i::Vector<const i::uc16> data_; |
| + }; |
| + // Number of string modifications required. |
| + static const int kRequiredModifications = 5; |
| + static const int kMaxModifications = 100; |
| + |
| + class MorphThread : public i::Thread { |
| + public: |
| + explicit MorphThread(RegExpStringModificationTest* test) |
| + : test_(test) {} |
| + virtual void Run() { |
| + test_->MorphString(); |
| + } |
| + private: |
| + RegExpStringModificationTest* test_; |
| + }; |
| + |
| + void MorphString() { |
| + block_->Wait(); |
| + while (morphs_during_regexp_ < kRequiredModifications && |
| + morphs_ < kMaxModifications) { |
| + { |
| + v8::Locker lock; |
| + // Swap string between ascii and two-byte representation. |
| + i::String* string = *input_; |
| + CHECK(i::StringShape(string).IsExternal()); |
| + if (i::StringShape(string).IsAsciiRepresentation()) { |
| + // Morph external string to be TwoByte string. |
| + i::ExternalAsciiString* ext_string = |
| + i::ExternalAsciiString::cast(string); |
| + i::ExternalTwoByteString* morphed = |
| + reinterpret_cast<i::ExternalTwoByteString*>(ext_string); |
| + morphed->map()->set_instance_type(i::SHORT_EXTERNAL_STRING_TYPE); |
| + morphed->set_resource(&uc16_resource_); |
| + } else { |
| + // Morph external string to be ASCII string. |
| + i::ExternalTwoByteString* ext_string = |
| + i::ExternalTwoByteString::cast(string); |
| + i::ExternalAsciiString* morphed = |
| + reinterpret_cast<i::ExternalAsciiString*>(ext_string); |
| + morphed->map()->set_instance_type( |
| + i::SHORT_EXTERNAL_ASCII_STRING_TYPE); |
| + morphed->set_resource(&ascii_resource_); |
| + } |
| + morphs_++; |
| + } |
| + i::OS::Sleep(1); |
| + } |
| + morph_success_ = true; |
| + } |
| + |
| + void LongRunningRegExp() { |
| + block_->Signal(); // Enable morphing thread on next preemption. |
| + while (morphs_during_regexp_ < kRequiredModifications && |
| + morphs_ < kMaxModifications) { |
| + int morphs_before = morphs_; |
| + { |
| + // Match 15-30 "a"'s against 14 and a "b". |
|
Erik Corry
2009/03/20 12:45:42
14 "a"s
|
| + const char* c_source = |
| + "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" |
| + ".exec(input) === null"; |
| + Local<String> source = String::New(c_source); |
| + Local<Script> script = Script::Compile(source); |
| + Local<Value> result = script->Run(); |
| + CHECK(result->IsTrue()); |
| + } |
| + int morphs_after = morphs_; |
| + morphs_during_regexp_ += morphs_after - morphs_before; |
| + } |
| + regexp_success_ = true; |
| + } |
| + |
| + i::uc16 two_byte_content_[15]; |
| + i::Semaphore* block_; |
| + int morphs_; |
| + int morphs_during_regexp_; |
| + bool regexp_success_; |
| + bool morph_success_; |
| + i::Handle<i::String> input_; |
| + AsciiVectorResource ascii_resource_; |
| + UC16VectorResource uc16_resource_; |
| +}; |
| + |
| + |
| +// Test that a regular expression execution can be interrupted and |
| +// the string changed without failing. |
| +TEST(RegExpStringModification) { |
| + v8::Locker lock; |
| + v8::V8::Initialize(); |
| + v8::HandleScope scope; |
| + Local<Context> local_env; |
| + { |
| + LocalContext env; |
| + local_env = env.local(); |
| + } |
| + |
| + // Local context should still be live. |
| + CHECK(!local_env.IsEmpty()); |
| + local_env->Enter(); |
| + |
| + // Should complete without problems. |
| + RegExpStringModificationTest().RunTest(); |
| + |
| + local_env->Exit(); |
| +} |