Commit f8051275 authored by lrn@chromium.org's avatar lrn@chromium.org

Add test for GC during RegExp.

Fix bug found by test.


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1327 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 563287b0
......@@ -1046,7 +1046,7 @@ int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(uc16** buffer,
}
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address,
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
Code* re_code) {
if (StackGuard::IsStackOverflow()) {
Top::StackOverflow();
......@@ -1059,15 +1059,16 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address,
// Prepare for possible GC.
Handle<Code> code_handle(re_code);
ASSERT(re_code->instruction_start() <= return_address);
ASSERT(return_address <=
ASSERT(re_code->instruction_start() <= *return_address);
ASSERT(*return_address <=
re_code->instruction_start() + re_code->instruction_size());
Object* result = Execution::HandleStackGuardInterrupt();
if (*code_handle != re_code) { // Return address no longer valid
int delta = *code_handle - re_code;
*reinterpret_cast<int32_t*>(return_address) += delta;
// Overwrite the return address on the stack.
*return_address += delta;
}
if (result->IsException()) {
......
......@@ -166,7 +166,7 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
// Called from RegExp if the stack-guard is triggered.
// If the code object is relocated, the return address is fixed before
// returning.
static int CheckStackGuardState(Address return_address, Code* re_code);
static int CheckStackGuardState(Address* return_address, Code* re_code);
// Called from RegExp if the backtrack stack limit is hit.
// Tries to expand the stack. Returns the new stack-pointer if
......
......@@ -5658,3 +5658,123 @@ THREADED_TEST(CrossContextNew) {
context0.Dispose();
context1.Dispose();
}
class RegExpInterruptTest {
public:
void RunTest() {
block_ = i::OS::CreateSemaphore(0);
gc_count_ = 0;
gc_during_regexp_ = 0;
regexp_success_ = false;
gc_success_ = false;
GCThread gc_thread(this);
gc_thread.Start();
v8::Locker::StartPreemption(1);
LongRunningRegExp();
{
v8::Unlocker unlock;
gc_thread.Join();
}
v8::Locker::StopPreemption();
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)
: test_(test) {}
virtual void Run() {
test_->CollectGarbage();
}
private:
RegExpInterruptTest* test_;
};
void CollectGarbage() {
block_->Wait();
while (gc_during_regexp_ < kRequiredGCs) {
{
v8::Locker lock;
// TODO(lrn): Perhaps create some garbage before collecting.
i::Heap::CollectAllGarbage();
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;
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.
RegExpInterruptTest().RunTest();
local_env->Exit();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment