This commit is contained in:
Nicholas Nethercote 2010-10-20 16:30:48 -07:00
commit de2d9819dd
5 changed files with 182 additions and 66 deletions

View File

@ -71,6 +71,7 @@ CPPSRCS = \
testScriptObject.cpp \
testSetPropertyWithNativeGetterStubSetter.cpp \
testBug604087.cpp \
testThreads.cpp \
testTrap.cpp \
testUTF8.cpp \
testXDR.cpp \

View File

@ -29,58 +29,6 @@ BEGIN_TEST(testContexts_IsRunning)
}
END_TEST(testContexts_IsRunning)
#ifdef JS_THREADSAFE
#include "prthread.h"
struct ThreadData {
JSRuntime *rt;
JSObject *obj;
const char *code;
bool ok;
};
BEGIN_TEST(testContexts_bug561444)
{
const char *code = "<a><b/></a>.b.@c = '';";
EXEC(code);
jsrefcount rc = JS_SuspendRequest(cx);
{
ThreadData data = {rt, global, code, false};
PRThread *thread =
PR_CreateThread(PR_USER_THREAD, threadMain, &data,
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
CHECK(thread);
PR_JoinThread(thread);
CHECK(data.ok);
}
JS_ResumeRequest(cx, rc);
return true;
}
static void threadMain(void *arg) {
ThreadData *d = (ThreadData *) arg;
JSContext *cx = JS_NewContext(d->rt, 8192);
if (!cx)
return;
JS_BeginRequest(cx);
{
jsvalRoot v(cx);
JSAutoEnterCompartment ac;
ac.enterAndIgnoreErrors(cx, d->obj);
if (!JS_EvaluateScript(cx, d->obj, d->code, strlen(d->code), __FILE__, __LINE__, v.addr()))
return;
}
JS_DestroyContext(cx);
d->ok = true;
}
END_TEST(testContexts_bug561444)
#endif
BEGIN_TEST(testContexts_bug563735)
{
JSContext *cx2 = JS_NewContext(rt, 8192);

View File

@ -0,0 +1,155 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*/
#ifdef JS_THREADSAFE
#include "tests.h"
#include "prthread.h"
struct ThreadData {
JSRuntime *rt;
JSObject *obj;
const char *code;
bool ok;
};
BEGIN_TEST(testThreads_bug561444)
{
const char *code = "<a><b/></a>.b.@c = '';";
EXEC(code);
jsrefcount rc = JS_SuspendRequest(cx);
{
ThreadData data = {rt, global, code, false};
PRThread *thread =
PR_CreateThread(PR_USER_THREAD, threadMain, &data,
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
CHECK(thread);
PR_JoinThread(thread);
CHECK(data.ok);
}
JS_ResumeRequest(cx, rc);
return true;
}
static void threadMain(void *arg) {
ThreadData *d = (ThreadData *) arg;
JSContext *cx = JS_NewContext(d->rt, 8192);
if (!cx)
return;
JS_BeginRequest(cx);
{
JSAutoEnterCompartment ac;
jsval v;
d->ok = ac.enter(cx, d->obj) &&
JS_EvaluateScript(cx, d->obj, d->code, strlen(d->code), __FILE__, __LINE__,
&v);
}
JS_DestroyContext(cx);
}
END_TEST(testThreads_bug561444)
template <class T>
class Repeat {
size_t n;
const T &t;
public:
Repeat(size_t n, const T &t) : n(n), t(t) {}
bool operator()() const {
for (size_t i = 0; i < n; i++)
if (!t())
return false;
return true;
}
};
template <class T> Repeat<T> repeat(size_t n, const T &t) { return Repeat<T>(n, t); }
/* Class of callable that does something in n parallel threads. */
template <class T>
class Parallel {
size_t n;
const T &t;
struct pair { const Parallel *self; bool ok; };
static void threadMain(void *arg) {
pair *p = (pair *) arg;
if (!p->self->t())
p->ok = false;
}
public:
Parallel(size_t n, const T &t) : n(n), t(t) {}
bool operator()() const {
pair p = {this, true};
PRThread **thread = new PRThread *[n];
if (!thread)
return false;
size_t i;
for (i = 0; i < n; i++) {
thread[i] = PR_CreateThread(PR_USER_THREAD, threadMain, &p, PR_PRIORITY_NORMAL,
PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
if (thread[i] == NULL) {
p.ok = false;
break;
}
}
while (i--)
PR_JoinThread(thread[i]);
delete[] thread;
return p.ok;
}
};
template <class T> Parallel<T> parallel(size_t n, const T &t) { return Parallel<T>(n, t); }
/* Class of callable that creates a compartment and runs some code in it. */
class eval {
JSRuntime *rt;
const char *code;
public:
eval(JSRuntime *rt, const char *code) : rt(rt), code(code) {}
bool operator()() const {
JSContext *cx = JS_NewContext(rt, 8192);
if (!cx)
return false;
bool ok = false;
{
JSAutoRequest ar(cx);
JSObject *global =
JS_NewCompartmentAndGlobalObject(cx, JSAPITest::basicGlobalClass(), NULL);
if (global) {
JS_SetGlobalObject(cx, global);
jsval rval;
ok = JS_InitStandardClasses(cx, global) &&
JS_EvaluateScript(cx, global, code, strlen(code), "", 0, &rval);
}
}
JS_DestroyContextMaybeGC(cx);
return ok;
}
};
BEGIN_TEST(testThreads_bug604782)
{
jsrefcount rc = JS_SuspendRequest(cx);
bool ok = repeat(20, parallel(3, eval(rt, "for(i=0;i<1000;i++);")))();
JS_ResumeRequest(cx, rc);
CHECK(ok);
return true;
}
END_TEST(testThreads_bug604782)
#endif

View File

@ -48,7 +48,7 @@
class jsvalRoot
{
public:
public:
explicit jsvalRoot(JSContext *context, jsval value = JSVAL_NULL)
: cx(context), v(value)
{
@ -70,7 +70,7 @@ public:
jsval * addr() { return &v; }
jsval value() const { return v; }
private:
private:
JSContext *cx;
jsval v;
};
@ -78,7 +78,7 @@ private:
/* Note: Aborts on OOM. */
class JSAPITestString {
js::Vector<char, 0, js::SystemAllocPolicy> chars;
public:
public:
JSAPITestString() {}
JSAPITestString(const char *s) { *this += s; }
JSAPITestString(const JSAPITestString &s) { *this += s; }
@ -105,7 +105,7 @@ inline JSAPITestString operator+(JSAPITestString a, const JSAPITestString &b) {
class JSAPITest
{
public:
public:
static JSAPITest *list;
JSAPITest *next;
@ -217,7 +217,17 @@ public:
JSAPITestString messages() const { return msgs; }
protected:
static JSClass * basicGlobalClass() {
static JSClass c = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
return &c;
}
protected:
static JSBool
print(JSContext *cx, uintN argc, jsval *vp)
{
@ -271,13 +281,7 @@ protected:
}
virtual JSClass * getGlobalClass() {
static JSClass basicGlobalClass = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
return &basicGlobalClass;
return basicGlobalClass();
}
virtual JSObject * createGlobal() {
@ -300,7 +304,7 @@ protected:
#define BEGIN_TEST(testname) \
class cls_##testname : public JSAPITest { \
public: \
public: \
virtual const char * name() { return #testname; } \
virtual bool run()
@ -318,7 +322,7 @@ protected:
#define BEGIN_FIXTURE_TEST(fixture, testname) \
class cls_##testname : public fixture { \
public: \
public: \
virtual const char * name() { return #testname; } \
virtual bool run()

View File

@ -625,6 +625,13 @@ js_CurrentThread(JSRuntime *rt)
JSThread::Map::AddPtr p = rt->threads.lookupForAdd(id);
if (p) {
thread = p->value;
/*
* If thread has no contexts, it might be left over from a previous
* thread with the same id but a different stack address.
*/
if (JS_CLIST_IS_EMPTY(&thread->contextList))
thread->data.nativeStackBase = GetNativeStackBase();
} else {
JS_UNLOCK_GC(rt);
thread = NewThread(id);
@ -642,6 +649,7 @@ js_CurrentThread(JSRuntime *rt)
JS_ASSERT(p->value == thread);
}
JS_ASSERT(thread->id == id);
JS_ASSERT(thread->data.nativeStackBase == GetNativeStackBase());
return thread;
}