| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 22e207785888f2857db01f6e20486a8a64c216d4..ae6dbfad33706eae42819747e6270ea222bc9db4 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -14323,129 +14323,6 @@ THREADED_TEST(CrossContextNew) {
|
| }
|
|
|
|
|
| -class RegExpInterruptTest {
|
| - public:
|
| - RegExpInterruptTest() : block_(0) {}
|
| - ~RegExpInterruptTest() {}
|
| - void RunTest() {
|
| - gc_count_ = 0;
|
| - gc_during_regexp_ = 0;
|
| - regexp_success_ = false;
|
| - gc_success_ = false;
|
| - GCThread gc_thread(this);
|
| - gc_thread.Start();
|
| - v8::Isolate* isolate = CcTest::isolate();
|
| - v8::Locker::StartPreemption(isolate, 1);
|
| -
|
| - LongRunningRegExp();
|
| - {
|
| - v8::Unlocker unlock(isolate);
|
| - gc_thread.Join();
|
| - }
|
| - v8::Locker::StopPreemption(isolate);
|
| - CHECK(regexp_success_);
|
| - CHECK(gc_success_);
|
| - }
|
| -
|
| - private:
|
| - // Number of garbage collections required.
|
| - static const int kRequiredGCs = 5;
|
| -
|
| - class GCThread : public i::Thread {
|
| - public:
|
| - explicit GCThread(RegExpInterruptTest* test)
|
| - : Thread("GCThread"), test_(test) {}
|
| - virtual void Run() {
|
| - test_->CollectGarbage();
|
| - }
|
| - private:
|
| - RegExpInterruptTest* test_;
|
| - };
|
| -
|
| - void CollectGarbage() {
|
| - block_.Wait();
|
| - while (gc_during_regexp_ < kRequiredGCs) {
|
| - {
|
| - v8::Locker lock(CcTest::isolate());
|
| - v8::Isolate::Scope isolate_scope(CcTest::isolate());
|
| - // TODO(lrn): Perhaps create some garbage before collecting.
|
| - CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
| - gc_count_++;
|
| - }
|
| - i::OS::Sleep(1);
|
| - }
|
| - gc_success_ = true;
|
| - }
|
| -
|
| - void LongRunningRegExp() {
|
| - block_.Signal(); // Enable garbage collection thread on next preemption.
|
| - int rounds = 0;
|
| - while (gc_during_regexp_ < kRequiredGCs) {
|
| - int gc_before = gc_count_;
|
| - {
|
| - // Match 15-30 "a"'s against 14 and a "b".
|
| - const char* c_source =
|
| - "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
|
| - ".exec('aaaaaaaaaaaaaaab') === null";
|
| - Local<String> source = String::New(c_source);
|
| - Local<Script> script = Script::Compile(source);
|
| - Local<Value> result = script->Run();
|
| - if (!result->BooleanValue()) {
|
| - gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
|
| - return;
|
| - }
|
| - }
|
| - {
|
| - // 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'";
|
| - Local<String> source = String::New(c_source);
|
| - Local<Script> script = Script::Compile(source);
|
| - Local<Value> result = script->Run();
|
| - if (!result->BooleanValue()) {
|
| - gc_during_regexp_ = kRequiredGCs;
|
| - return;
|
| - }
|
| - }
|
| - int gc_after = gc_count_;
|
| - gc_during_regexp_ += gc_after - gc_before;
|
| - rounds++;
|
| - i::OS::Sleep(1);
|
| - }
|
| - regexp_success_ = true;
|
| - }
|
| -
|
| - i::Semaphore block_;
|
| - int gc_count_;
|
| - int gc_during_regexp_;
|
| - bool regexp_success_;
|
| - bool gc_success_;
|
| -};
|
| -
|
| -
|
| -// Test that a regular expression execution can be interrupted and
|
| -// survive a garbage collection.
|
| -TEST(RegExpInterruption) {
|
| - v8::Locker lock(CcTest::isolate());
|
| - v8::HandleScope scope(CcTest::isolate());
|
| - 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.
|
| - RegExpInterruptTest().RunTest();
|
| -
|
| - local_env->Exit();
|
| -}
|
| -
|
| -
|
| class ApplyInterruptTest {
|
| public:
|
| ApplyInterruptTest() : block_(0) {}
|
| @@ -14735,142 +14612,73 @@ TEST(CompileExternalTwoByteSource) {
|
| }
|
|
|
|
|
| -class RegExpStringModificationTest {
|
| - public:
|
| - RegExpStringModificationTest()
|
| - : block_(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() {}
|
| - void RunTest() {
|
| - v8::Isolate* isolate = CcTest::isolate();
|
| - i::Factory* factory = CcTest::i_isolate()->factory();
|
| +struct RegExpInterruptionData {
|
| + int loop_count;
|
| + UC16VectorResource* string_resource;
|
| + v8::Persistent<v8::String> string;
|
| +} regexp_interruption_data;
|
|
|
| - regexp_success_ = false;
|
| - morph_success_ = false;
|
|
|
| - // Initialize the contents of two_byte_content_ to be a uc16 representation
|
| - // of "aaaaaaaaaaaaaab".
|
| - 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_ = factory->NewExternalStringFromAscii(&ascii_resource_);
|
| -
|
| - // Inject the input as a global variable.
|
| - i::Handle<i::String> input_name =
|
| - factory->NewStringFromAscii(i::Vector<const char>("input", 5));
|
| - i::JSReceiver::SetProperty(
|
| - i::handle(CcTest::i_isolate()->native_context()->global_object()),
|
| - input_name,
|
| - input_,
|
| - NONE,
|
| - i::kNonStrictMode);
|
| -
|
| - MorphThread morph_thread(this);
|
| - morph_thread.Start();
|
| - v8::Locker::StartPreemption(isolate, 1);
|
| - LongRunningRegExp();
|
| - {
|
| - v8::Unlocker unlock(isolate);
|
| - morph_thread.Join();
|
| +class RegExpInterruptionThread : public i::Thread {
|
| + public:
|
| + explicit RegExpInterruptionThread(v8::Isolate* isolate)
|
| + : Thread("TimeoutThread"), isolate_(isolate) {}
|
| +
|
| + virtual void Run() {
|
| + for (regexp_interruption_data.loop_count = 0;
|
| + regexp_interruption_data.loop_count < 7;
|
| + regexp_interruption_data.loop_count++) {
|
| + i::OS::Sleep(50); // Wait a bit before requesting GC.
|
| + reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
|
| }
|
| - v8::Locker::StopPreemption(isolate);
|
| - CHECK(regexp_success_);
|
| - CHECK(morph_success_);
|
| + i::OS::Sleep(50); // Wait a bit before terminating.
|
| + v8::V8::TerminateExecution(isolate_);
|
| }
|
|
|
| private:
|
| - // Number of string modifications required.
|
| - static const int kRequiredModifications = 5;
|
| - static const int kMaxModifications = 100;
|
| + v8::Isolate* isolate_;
|
| +};
|
|
|
| - class MorphThread : public i::Thread {
|
| - public:
|
| - explicit MorphThread(RegExpStringModificationTest* test)
|
| - : Thread("MorphThread"), test_(test) {}
|
| - virtual void Run() {
|
| - test_->MorphString();
|
| - }
|
| - private:
|
| - RegExpStringModificationTest* test_;
|
| - };
|
|
|
| - void MorphString() {
|
| - block_.Wait();
|
| - while (morphs_during_regexp_ < kRequiredModifications &&
|
| - morphs_ < kMaxModifications) {
|
| - {
|
| - v8::Locker lock(CcTest::isolate());
|
| - v8::Isolate::Scope isolate_scope(CcTest::isolate());
|
| - // Swap string between ascii and two-byte representation.
|
| - i::String* string = *input_;
|
| - MorphAString(string, &ascii_resource_, &uc16_resource_);
|
| - morphs_++;
|
| - }
|
| - i::OS::Sleep(1);
|
| - }
|
| - morph_success_ = true;
|
| - }
|
| +void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
|
| + if (regexp_interruption_data.loop_count != 2) return;
|
| + v8::HandleScope scope(CcTest::isolate());
|
| + v8::Local<v8::String> string = v8::Local<v8::String>::New(
|
| + CcTest::isolate(), regexp_interruption_data.string);
|
| + string->MakeExternal(regexp_interruption_data.string_resource);
|
| +}
|
|
|
| - void LongRunningRegExp() {
|
| - block_.Signal(); // Enable morphing thread on next preemption.
|
| - while (morphs_during_regexp_ < kRequiredModifications &&
|
| - morphs_ < kMaxModifications) {
|
| - int morphs_before = morphs_;
|
| - {
|
| - v8::HandleScope scope(CcTest::isolate());
|
| - // Match 15-30 "a"'s against 14 and a "b".
|
| - 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 RegExp execution can be interrupted. Specifically, we test
|
| +// * interrupting with GC
|
| +// * turn the subject string from one-byte internal to two-byte external string
|
| +// * force termination
|
| +TEST(RegExpInterruption) {
|
| + v8::HandleScope scope(CcTest::isolate());
|
| + LocalContext env;
|
|
|
| + RegExpInterruptionThread timeout_thread(CcTest::isolate());
|
|
|
| -// Test that a regular expression execution can be interrupted and
|
| -// the string changed without failing.
|
| -TEST(RegExpStringModification) {
|
| - v8::Locker lock(CcTest::isolate());
|
| - v8::HandleScope scope(CcTest::isolate());
|
| - Local<Context> local_env;
|
| - {
|
| - LocalContext env;
|
| - local_env = env.local();
|
| - }
|
| + v8::V8::AddGCPrologueCallback(RunBeforeGC);
|
| + static const char* ascii_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
| + i::uc16* uc16_content = AsciiToTwoByteString(ascii_content);
|
| + v8::Local<v8::String> string = v8_str(ascii_content);
|
|
|
| - // Local context should still be live.
|
| - CHECK(!local_env.IsEmpty());
|
| - local_env->Enter();
|
| + CcTest::global()->Set(v8_str("a"), string);
|
| + regexp_interruption_data.string.Reset(CcTest::isolate(), string);
|
| + regexp_interruption_data.string_resource = new UC16VectorResource(
|
| + i::Vector<const i::uc16>(uc16_content, i::StrLength(ascii_content)));
|
|
|
| - // Should complete without problems.
|
| - RegExpStringModificationTest().RunTest();
|
| + v8::TryCatch try_catch;
|
| + timeout_thread.Start();
|
|
|
| - local_env->Exit();
|
| + CompileRun("/((a*)*)*b/.exec(a)");
|
| + CHECK(try_catch.HasTerminated());
|
| +
|
| + timeout_thread.Join();
|
| +
|
| + delete regexp_interruption_data.string_resource;
|
| + regexp_interruption_data.string.Dispose();
|
| }
|
|
|
|
|
|
|