| Index: test/cctest/test-api.cc
|
| ===================================================================
|
| --- test/cctest/test-api.cc (revision 1760)
|
| +++ test/cctest/test-api.cc (working copy)
|
| @@ -6014,6 +6014,112 @@
|
| }
|
|
|
|
|
| +class ApplyInterruptTest {
|
| + public:
|
| + ApplyInterruptTest() : block_(NULL) {}
|
| + ~ApplyInterruptTest() { delete block_; }
|
| + void RunTest() {
|
| + block_ = i::OS::CreateSemaphore(0);
|
| + gc_count_ = 0;
|
| + gc_during_apply_ = 0;
|
| + apply_success_ = false;
|
| + gc_success_ = false;
|
| + GCThread gc_thread(this);
|
| + gc_thread.Start();
|
| + v8::Locker::StartPreemption(1);
|
| +
|
| + LongRunningApply();
|
| + {
|
| + v8::Unlocker unlock;
|
| + gc_thread.Join();
|
| + }
|
| + v8::Locker::StopPreemption();
|
| + CHECK(apply_success_);
|
| + CHECK(gc_success_);
|
| + }
|
| + private:
|
| + // Number of garbage collections required.
|
| + static const int kRequiredGCs = 2;
|
| +
|
| + class GCThread : public i::Thread {
|
| + public:
|
| + explicit GCThread(ApplyInterruptTest* test)
|
| + : test_(test) {}
|
| + virtual void Run() {
|
| + test_->CollectGarbage();
|
| + }
|
| + private:
|
| + ApplyInterruptTest* test_;
|
| + };
|
| +
|
| + void CollectGarbage() {
|
| + block_->Wait();
|
| + while (gc_during_apply_ < kRequiredGCs) {
|
| + {
|
| + v8::Locker lock;
|
| + i::Heap::CollectAllGarbage();
|
| + gc_count_++;
|
| + }
|
| + i::OS::Sleep(1);
|
| + }
|
| + gc_success_ = true;
|
| + }
|
| +
|
| + void LongRunningApply() {
|
| + block_->Signal();
|
| + int rounds = 0;
|
| + while (gc_during_apply_ < kRequiredGCs) {
|
| + int gc_before = gc_count_;
|
| + {
|
| + const char* c_source =
|
| + "function do_very_little(bar) {"
|
| + " this.foo = bar;"
|
| + "}"
|
| + "for (var i = 0; i < 100000; i++) {"
|
| + " do_very_little.apply(this, ['bar']);"
|
| + "}";
|
| + Local<String> source = String::New(c_source);
|
| + Local<Script> script = Script::Compile(source);
|
| + Local<Value> result = script->Run();
|
| + }
|
| + int gc_after = gc_count_;
|
| + gc_during_apply_ += gc_after - gc_before;
|
| + rounds++;
|
| + }
|
| + apply_success_ = true;
|
| + }
|
| +
|
| + i::Semaphore* block_;
|
| + int gc_count_;
|
| + int gc_during_apply_;
|
| + bool apply_success_;
|
| + bool gc_success_;
|
| +};
|
| +
|
| +
|
| +// Test that nothing bad happens if we get a preemption just when we were
|
| +// about to do an apply().
|
| +TEST(ApplyInterruption) {
|
| + 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.
|
| + ApplyInterruptTest().RunTest();
|
| +
|
| + local_env->Exit();
|
| +}
|
| +
|
| +
|
| // Verify that we can clone an object
|
| TEST(ObjectClone) {
|
| v8::HandleScope scope;
|
|
|