diff options
Diffstat (limited to '')
-rw-r--r-- | lang/spidermonkey185/files/patch-bug771281 | 1839 |
1 files changed, 0 insertions, 1839 deletions
diff --git a/lang/spidermonkey185/files/patch-bug771281 b/lang/spidermonkey185/files/patch-bug771281 deleted file mode 100644 index 1b59e5dfeafb..000000000000 --- a/lang/spidermonkey185/files/patch-bug771281 +++ /dev/null @@ -1,1839 +0,0 @@ -diff -ruN src/shell/Makefile.in src.new/shell/Makefile.in ---- shell/Makefile.in 2011-04-01 06:08:36.000000000 +1100 -+++ shell/Makefile.in 2013-03-23 22:01:26.876752286 +1100 -@@ -47,7 +47,6 @@ - PROGRAM = js$(BIN_SUFFIX) - CPPSRCS = \ - js.cpp \ -- jsworkers.cpp \ - $(NULL) - - DEFINES += -DEXPORT_JS_API -diff -ruN src/shell/js.cpp src.new/shell/js.cpp ---- shell/js.cpp 2011-04-01 06:08:36.000000000 +1100 -+++ shell/js.cpp 2013-03-23 22:02:46.436700725 +1100 -@@ -91,8 +91,6 @@ - #endif /* JSDEBUGGER_C_UI */ - #endif /* JSDEBUGGER */ - --#include "jsworkers.h" -- - #include "jsinterpinlines.h" - #include "jsobjinlines.h" - #include "jsscriptinlines.h" -@@ -194,10 +192,6 @@ - JSBool gQuitting = JS_FALSE; - FILE *gErrFile = NULL; - FILE *gOutFile = NULL; --#ifdef JS_THREADSAFE --JSObject *gWorkers = NULL; --js::workers::ThreadPool *gWorkerThreadPool = NULL; --#endif - - static JSBool reportWarnings = JS_TRUE; - static JSBool compileOnly = JS_FALSE; -@@ -1315,10 +1309,6 @@ - JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "/ i", &gExitCode); - - gQuitting = JS_TRUE; --#ifdef JS_THREADSAFE -- if (gWorkerThreadPool) -- js::workers::terminateAll(JS_GetRuntime(cx), gWorkerThreadPool); --#endif - return JS_FALSE; - } - -@@ -4150,10 +4140,6 @@ - gCanceled = true; - if (gExitCode == 0) - gExitCode = EXITCODE_TIMEOUT; --#ifdef JS_THREADSAFE -- if (gWorkerThreadPool) -- js::workers::terminateAll(rt, gWorkerThreadPool); --#endif - JS_TriggerAllOperationCallbacks(rt); - - static const char msg[] = "Script runs for too long, terminating.\n"; -@@ -5681,29 +5667,8 @@ - #endif /* JSDEBUGGER_C_UI */ - #endif /* JSDEBUGGER */ - --#ifdef JS_THREADSAFE -- class ShellWorkerHooks : public js::workers::WorkerHooks { -- public: -- JSObject *newGlobalObject(JSContext *cx) { -- return NewGlobalObject(cx, NEW_COMPARTMENT); -- } -- }; -- ShellWorkerHooks hooks; -- if (!JS_AddNamedObjectRoot(cx, &gWorkers, "Workers") || -- (gWorkerThreadPool = js::workers::init(cx, &hooks, glob, &gWorkers)) == NULL) { -- return 1; -- } --#endif -- - int result = ProcessArgs(cx, glob, argv, argc); - --#ifdef JS_THREADSAFE -- js::workers::finish(cx, gWorkerThreadPool); -- JS_RemoveObjectRoot(cx, &gWorkers); -- if (result == 0) -- result = gExitCode; --#endif -- - #ifdef JSDEBUGGER - if (jsdc) { - #ifdef JSDEBUGGER_C_UI -diff -ruN src/shell/jsworkers.cpp src.new/shell/jsworkers.cpp ---- shell/jsworkers.cpp 2011-04-01 06:08:36.000000000 +1100 -+++ shell/jsworkers.cpp 1970-01-01 10:00:00.000000000 +1000 -@@ -1,1280 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- * vim: set ts=8 sw=4 et tw=99: -- * -- * ***** BEGIN LICENSE BLOCK ***** -- * Version: MPL 1.1/GPL 2.0/LGPL 2.1 -- * -- * The contents of this file are subject to the Mozilla Public License Version -- * 1.1 (the "License"); you may not use this file except in compliance with -- * the License. You may obtain a copy of the License at -- * http://www.mozilla.org/MPL/ -- * -- * Software distributed under the License is distributed on an "AS IS" basis, -- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -- * for the specific language governing rights and limitations under the -- * License. -- * -- * The Original Code is JavaScript shell workers. -- * -- * The Initial Developer of the Original Code is -- * Mozilla Corporation. -- * Portions created by the Initial Developer are Copyright (C) 2010 -- * the Initial Developer. All Rights Reserved. -- * -- * Contributor(s): -- * Jason Orendorff <jorendorff@mozilla.com> -- * -- * Alternatively, the contents of this file may be used under the terms of -- * either of the GNU General Public License Version 2 or later (the "GPL"), -- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -- * in which case the provisions of the GPL or the LGPL are applicable instead -- * of those above. If you wish to allow use of your version of this file only -- * under the terms of either the GPL or the LGPL, and not to allow others to -- * use your version of this file under the terms of the MPL, indicate your -- * decision by deleting the provisions above and replace them with the notice -- * and other provisions required by the GPL or the LGPL. If you do not delete -- * the provisions above, a recipient may use your version of this file under -- * the terms of any one of the MPL, the GPL or the LGPL. -- * -- * ***** END LICENSE BLOCK ***** */ -- --#ifdef JS_THREADSAFE -- --#include <algorithm> --#include <string.h> --#include "prthread.h" --#include "prlock.h" --#include "prcvar.h" --#include "jsapi.h" --#include "jscntxt.h" --#include "jshashtable.h" --#include "jsstdint.h" --#include "jslock.h" --#include "jsvector.h" --#include "jsworkers.h" -- --extern size_t gMaxStackSize; -- --/* -- * JavaScript shell workers. -- * -- * == Object lifetime rules == -- * -- * - The ThreadPool lasts from init() to finish(). -- * -- * - The ThreadPool owns the MainQueue and the WorkerQueue. Those live from -- * the time the first Worker is created until finish(). -- * -- * - Each JS Worker object has the same lifetime as the corresponding C++ -- * Worker object. A Worker is live if (a) the Worker JSObject is still -- * live; (b) the Worker has an incoming event pending or running; (c) it -- * has sent an outgoing event to its parent that is still pending; or (d) -- * it has any live child Workers. -- * -- * - finish() continues to wait for events until all threads are idle. -- * -- * Event objects, however, are basically C++-only. The JS Event objects are -- * just plain old JSObjects. They don't keep anything alive. -- * -- * == Locking scheme == -- * -- * When mixing mutexes and the JSAPI request model, there are two choices: -- * -- * - Always nest the mutexes in requests. Since threads in requests are not -- * supposed to block, this means the mutexes must be only briefly held. -- * -- * - Never nest the mutexes in requests. Since this allows threads to race -- * with the GC, trace() methods must go through the mutexes just like -- * everyone else. -- * -- * This code uses the latter approach for all locks. -- * -- * In one case, a thread holding a Worker's mutex can acquire the mutex of one -- * of its child Workers. See Worker::terminateSelf. (This can't deadlock because -- * the parent-child relationship is a partial order.) -- */ -- --namespace js { --namespace workers { -- --template <class T, class AllocPolicy> --class Queue { -- private: -- typedef Vector<T, 4, AllocPolicy> Vec; -- Vec v1; -- Vec v2; -- Vec *front; -- Vec *back; -- -- // Queue is not copyable. -- Queue(const Queue &); -- Queue & operator=(const Queue &); -- -- public: -- Queue() : front(&v1), back(&v2) {} -- bool push(T t) { return back->append(t); } -- bool empty() { return front->empty() && back->empty(); } -- -- T pop() { -- if (front->empty()) { -- std::reverse(back->begin(), back->end()); -- Vec *tmp = front; -- front = back; -- back = tmp; -- } -- T item = front->back(); -- front->popBack(); -- return item; -- } -- -- void clear() { -- v1.clear(); -- v2.clear(); -- } -- -- void trace(JSTracer *trc) { -- for (T *p = v1.begin(); p != v1.end(); p++) -- (*p)->trace(trc); -- for (T *p = v2.begin(); p != v2.end(); p++) -- (*p)->trace(trc); -- } --}; -- --class Event; --class ThreadPool; --class Worker; -- --class WorkerParent { -- protected: -- typedef HashSet<Worker *, DefaultHasher<Worker *>, SystemAllocPolicy> ChildSet; -- ChildSet children; -- -- bool initWorkerParent() { return children.init(8); } -- -- public: -- virtual JSLock *getLock() = 0; -- virtual ThreadPool *getThreadPool() = 0; -- virtual bool post(Event *item) = 0; // false on OOM or queue closed -- virtual void trace(JSTracer *trc) = 0; -- -- bool addChild(Worker *w) { -- AutoLock hold(getLock()); -- return children.put(w) != NULL; -- } -- -- // This must be called only from GC or when all threads are shut down. It -- // does not bother with locking. -- void removeChild(Worker *w) { -- ChildSet::Ptr p = children.lookup(w); -- JS_ASSERT(p); -- children.remove(p); -- } -- -- void disposeChildren(); --}; -- --template <class T> --class ThreadSafeQueue --{ -- protected: -- Queue<T, SystemAllocPolicy> queue; -- JSLock *lock; -- PRCondVar *condvar; -- bool closed; -- -- private: -- Vector<T, 8, SystemAllocPolicy> busy; -- -- protected: -- ThreadSafeQueue() : lock(NULL), condvar(NULL), closed(false) {} -- -- ~ThreadSafeQueue() { -- if (condvar) -- JS_DESTROY_CONDVAR(condvar); -- if (lock) -- JS_DESTROY_LOCK(lock); -- } -- -- // Called by take() with the lock held. -- virtual bool shouldStop() { return closed; } -- -- public: -- bool initThreadSafeQueue() { -- JS_ASSERT(!lock); -- JS_ASSERT(!condvar); -- return (lock = JS_NEW_LOCK()) && (condvar = JS_NEW_CONDVAR(lock)); -- } -- -- bool post(T t) { -- AutoLock hold(lock); -- if (closed) -- return false; -- if (queue.empty()) -- JS_NOTIFY_ALL_CONDVAR(condvar); -- return queue.push(t); -- } -- -- void close() { -- AutoLock hold(lock); -- closed = true; -- queue.clear(); -- JS_NOTIFY_ALL_CONDVAR(condvar); -- } -- -- // The caller must hold the lock. -- bool take(T *t) { -- while (queue.empty()) { -- if (shouldStop()) -- return false; -- JS_WAIT_CONDVAR(condvar, JS_NO_TIMEOUT); -- } -- *t = queue.pop(); -- busy.append(*t); -- return true; -- } -- -- // The caller must hold the lock. -- void drop(T item) { -- for (T *p = busy.begin(); p != busy.end(); p++) { -- if (*p == item) { -- *p = busy.back(); -- busy.popBack(); -- return; -- } -- } -- JS_NOT_REACHED("removeBusy"); -- } -- -- bool lockedIsIdle() { return busy.empty() && queue.empty(); } -- -- bool isIdle() { -- AutoLock hold(lock); -- return lockedIsIdle(); -- } -- -- void wake() { -- AutoLock hold(lock); -- JS_NOTIFY_ALL_CONDVAR(condvar); -- } -- -- void trace(JSTracer *trc) { -- AutoLock hold(lock); -- for (T *p = busy.begin(); p != busy.end(); p++) -- (*p)->trace(trc); -- queue.trace(trc); -- } --}; -- --class MainQueue; -- --class Event --{ -- protected: -- virtual ~Event() { JS_ASSERT(!data); } -- -- WorkerParent *recipient; -- Worker *child; -- uint64 *data; -- size_t nbytes; -- -- public: -- enum Result { fail = JS_FALSE, ok = JS_TRUE, forwardToParent }; -- -- virtual void destroy(JSContext *cx) { -- JS_free(cx, data); --#ifdef DEBUG -- data = NULL; --#endif -- delete this; -- } -- -- void setChildAndRecipient(Worker *aChild, WorkerParent *aRecipient) { -- child = aChild; -- recipient = aRecipient; -- } -- -- bool deserializeData(JSContext *cx, jsval *vp) { -- return !!JS_ReadStructuredClone(cx, data, nbytes, JS_STRUCTURED_CLONE_VERSION, vp, -- NULL, NULL); -- } -- -- virtual Result process(JSContext *cx) = 0; -- -- inline void trace(JSTracer *trc); -- -- template <class EventType> -- static EventType *createEvent(JSContext *cx, WorkerParent *recipient, Worker *child, -- jsval v) -- { -- uint64 *data; -- size_t nbytes; -- if (!JS_WriteStructuredClone(cx, v, &data, &nbytes, NULL, NULL)) -- return NULL; -- -- EventType *event = new EventType; -- if (!event) { -- JS_ReportOutOfMemory(cx); -- return NULL; -- } -- event->recipient = recipient; -- event->child = child; -- event->data = data; -- event->nbytes = nbytes; -- return event; -- } -- -- Result dispatch(JSContext *cx, JSObject *thisobj, const char *dataPropName, -- const char *methodName, Result noHandler) -- { -- if (!data) -- return fail; -- -- JSBool found; -- if (!JS_HasProperty(cx, thisobj, methodName, &found)) -- return fail; -- if (!found) -- return noHandler; -- -- // Create event object. -- jsval v; -- if (!deserializeData(cx, &v)) -- return fail; -- JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); -- if (!obj || !JS_DefineProperty(cx, obj, dataPropName, v, NULL, NULL, 0)) -- return fail; -- -- // Call event handler. -- jsval argv[1] = { OBJECT_TO_JSVAL(obj) }; -- jsval rval = JSVAL_VOID; -- return Result(JS_CallFunctionName(cx, thisobj, methodName, 1, argv, &rval)); -- } --}; -- --typedef ThreadSafeQueue<Event *> EventQueue; -- --class MainQueue : public EventQueue, public WorkerParent --{ -- private: -- ThreadPool *threadPool; -- -- public: -- explicit MainQueue(ThreadPool *tp) : threadPool(tp) {} -- -- ~MainQueue() { -- JS_ASSERT(queue.empty()); -- } -- -- bool init() { return initThreadSafeQueue() && initWorkerParent(); } -- -- void destroy(JSContext *cx) { -- while (!queue.empty()) -- queue.pop()->destroy(cx); -- delete this; -- } -- -- virtual JSLock *getLock() { return lock; } -- virtual ThreadPool *getThreadPool() { return threadPool; } -- -- protected: -- virtual bool shouldStop(); -- -- public: -- virtual bool post(Event *event) { return EventQueue::post(event); } -- -- virtual void trace(JSTracer *trc); -- -- void traceChildren(JSTracer *trc) { EventQueue::trace(trc); } -- -- JSBool mainThreadWork(JSContext *cx, bool continueOnError) { -- JSAutoSuspendRequest suspend(cx); -- AutoLock hold(lock); -- -- Event *event; -- while (take(&event)) { -- JS_RELEASE_LOCK(lock); -- Event::Result result; -- { -- JSAutoRequest req(cx); -- result = event->process(cx); -- if (result == Event::forwardToParent) { -- // FIXME - pointlessly truncates the string to 8 bits -- jsval data; -- JSAutoByteString bytes; -- if (event->deserializeData(cx, &data) && -- JSVAL_IS_STRING(data) && -- bytes.encode(cx, JSVAL_TO_STRING(data))) { -- JS_ReportError(cx, "%s", bytes.ptr()); -- } else { -- JS_ReportOutOfMemory(cx); -- } -- result = Event::fail; -- } -- if (result == Event::fail && continueOnError) { -- if (JS_IsExceptionPending(cx) && !JS_ReportPendingException(cx)) -- JS_ClearPendingException(cx); -- result = Event::ok; -- } -- } -- JS_ACQUIRE_LOCK(lock); -- drop(event); -- event->destroy(cx); -- if (result != Event::ok) -- return false; -- } -- return true; -- } --}; -- --/* -- * A queue of workers. -- * -- * We keep a queue of workers with pending events, rather than a queue of -- * events, so that two threads won't try to run a Worker at the same time. -- */ --class WorkerQueue : public ThreadSafeQueue<Worker *> --{ -- private: -- MainQueue *main; -- -- public: -- explicit WorkerQueue(MainQueue *main) : main(main) {} -- -- void work(); --}; -- --/* The top-level object that owns everything else. */ --class ThreadPool --{ -- private: -- enum { threadCount = 6 }; -- -- JSObject *obj; -- WorkerHooks *hooks; -- MainQueue *mq; -- WorkerQueue *wq; -- PRThread *threads[threadCount]; -- int32_t terminating; -- -- static JSClass jsClass; -- -- static void start(void* arg) { -- ((WorkerQueue *) arg)->work(); -- } -- -- explicit ThreadPool(WorkerHooks *hooks) : hooks(hooks), mq(NULL), wq(NULL), terminating(0) { -- for (int i = 0; i < threadCount; i++) -- threads[i] = NULL; -- } -- -- public: -- ~ThreadPool() { -- JS_ASSERT(!mq); -- JS_ASSERT(!wq); -- JS_ASSERT(!threads[0]); -- } -- -- static ThreadPool *create(JSContext *cx, WorkerHooks *hooks) { -- ThreadPool *tp = new ThreadPool(hooks); -- if (!tp) { -- JS_ReportOutOfMemory(cx); -- return NULL; -- } -- -- JSObject *obj = JS_NewObject(cx, &jsClass, NULL, NULL); -- if (!obj || !JS_SetPrivate(cx, obj, tp)) { -- delete tp; -- return NULL; -- } -- tp->obj = obj; -- return tp; -- } -- -- JSObject *asObject() { return obj; } -- WorkerHooks *getHooks() { return hooks; } -- WorkerQueue *getWorkerQueue() { return wq; } -- MainQueue *getMainQueue() { return mq; } -- bool isTerminating() { return terminating != 0; } -- -- /* -- * Main thread only. Requires request (to prevent GC, which could see the -- * object in an inconsistent state). -- */ -- bool start(JSContext *cx) { -- JS_ASSERT(!mq && !wq); -- mq = new MainQueue(this); -- if (!mq || !mq->init()) { -- mq->destroy(cx); -- mq = NULL; -- return false; -- } -- wq = new WorkerQueue(mq); -- if (!wq || !wq->initThreadSafeQueue()) { -- delete wq; -- wq = NULL; -- mq->destroy(cx); -- mq = NULL; -- return false; -- } -- JSAutoSuspendRequest suspend(cx); -- bool ok = true; -- for (int i = 0; i < threadCount; i++) { -- threads[i] = PR_CreateThread(PR_USER_THREAD, start, wq, PR_PRIORITY_NORMAL, -- PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); -- if (!threads[i]) { -- shutdown(cx); -- ok = false; -- break; -- } -- } -- return ok; -- } -- -- void terminateAll(JSRuntime *rt) { -- // See comment about JS_ATOMIC_SET in the implementation of -- // JS_TriggerOperationCallback. -- JS_ATOMIC_SET(&terminating, 1); -- JS_TriggerAllOperationCallbacks(rt); -- } -- -- /* This context is used only to free memory. */ -- void shutdown(JSContext *cx) { -- wq->close(); -- for (int i = 0; i < threadCount; i++) { -- if (threads[i]) { -- PR_JoinThread(threads[i]); -- threads[i] = NULL; -- } -- } -- -- delete wq; -- wq = NULL; -- -- mq->disposeChildren(); -- mq->destroy(cx); -- mq = NULL; -- terminating = 0; -- } -- -- private: -- static void jsTraceThreadPool(JSTracer *trc, JSObject *obj) { -- ThreadPool *tp = unwrap(trc->context, obj); -- if (tp->mq) { -- tp->mq->traceChildren(trc); -- tp->wq->trace(trc); -- } -- } -- -- -- static void jsFinalize(JSContext *cx, JSObject *obj) { -- if (ThreadPool *tp = unwrap(cx, obj)) -- delete tp; -- } -- -- public: -- static ThreadPool *unwrap(JSContext *cx, JSObject *obj) { -- JS_ASSERT(JS_GET_CLASS(cx, obj) == &jsClass); -- return (ThreadPool *) JS_GetPrivate(cx, obj); -- } --}; -- --/* -- * A Worker is always in one of 4 states, except when it is being initialized -- * or destroyed, or its lock is held: -- * - idle (!terminated && current == NULL && events.empty()) -- * - enqueued (!terminated && current == NULL && !events.empty()) -- * - busy (!terminated && current != NULL) -- * - terminated (terminated && current == NULL && events.empty()) -- * -- * Separately, there is a terminateFlag that other threads can set -- * asynchronously to tell the Worker to terminate. -- */ --class Worker : public WorkerParent --{ -- private: -- ThreadPool *threadPool; -- WorkerParent *parent; -- JSObject *object; // Worker object exposed to parent -- JSContext *context; -- JSLock *lock; -- Queue<Event *, SystemAllocPolicy> events; // owning pointers to pending events -- Event *current; -- bool terminated; -- int32_t terminateFlag; -- -- static JSClass jsWorkerClass; -- -- Worker() -- : threadPool(NULL), parent(NULL), object(NULL), -- context(NULL), lock(NULL), current(NULL), terminated(false), terminateFlag(0) {} -- -- bool init(JSContext *parentcx, WorkerParent *parent, JSObject *obj) { -- JS_ASSERT(!threadPool && !this->parent && !object && !lock); -- -- if (!initWorkerParent() || !parent->addChild(this)) -- return false; -- threadPool = parent->getThreadPool(); -- this->parent = parent; -- this->object = obj; -- lock = JS_NEW_LOCK(); -- return lock && -- createContext(parentcx, parent) && -- JS_SetPrivate(parentcx, obj, this); -- } -- -- bool createContext(JSContext *parentcx, WorkerParent *parent) { -- JSRuntime *rt = JS_GetRuntime(parentcx); -- context = JS_NewContext(rt, 8192); -- if (!context) -- return false; -- -- // The Worker has a strong reference to the global; see jsTraceWorker. -- // JSOPTION_UNROOTED_GLOBAL ensures that when the worker becomes -- // unreachable, it and its global object can be collected. Otherwise -- // the cx->globalObject root would keep them both alive forever. -- JS_SetOptions(context, JS_GetOptions(parentcx) | JSOPTION_UNROOTED_GLOBAL | -- JSOPTION_DONT_REPORT_UNCAUGHT); -- JS_SetVersion(context, JS_GetVersion(parentcx)); -- JS_SetContextPrivate(context, this); -- JS_SetOperationCallback(context, jsOperationCallback); -- JS_BeginRequest(context); -- -- JSObject *global = threadPool->getHooks()->newGlobalObject(context); -- JSObject *post, *proto, *ctor; -- if (!global) -- goto bad; -- JS_SetGlobalObject(context, global); -- -- // Because the Worker is completely isolated from the rest of the -- // runtime, and because any pending events on a Worker keep the Worker -- // alive, this postMessage function cannot be called after the Worker -- // is collected. Therefore it's safe to stash a pointer (a weak -- // reference) to the C++ Worker object in the reserved slot. -- post = JS_GetFunctionObject(JS_DefineFunction(context, global, "postMessage", -- (JSNative) jsPostMessageToParent, 1, 0)); -- if (!post || !JS_SetReservedSlot(context, post, 0, PRIVATE_TO_JSVAL(this))) -- goto bad; -- -- proto = JS_InitClass(context, global, NULL, &jsWorkerClass, jsConstruct, 1, -- NULL, jsMethods, NULL, NULL); -- if (!proto) -- goto bad; -- -- ctor = JS_GetConstructor(context, proto); -- if (!ctor || !JS_SetReservedSlot(context, ctor, 0, PRIVATE_TO_JSVAL(this))) -- goto bad; -- -- JS_EndRequest(context); -- JS_ClearContextThread(context); -- return true; -- -- bad: -- JS_EndRequest(context); -- JS_DestroyContext(context); -- context = NULL; -- return false; -- } -- -- static void jsTraceWorker(JSTracer *trc, JSObject *obj) { -- JS_ASSERT(JS_GET_CLASS(trc->context, obj) == &jsWorkerClass); -- if (Worker *w = (Worker *) JS_GetPrivate(trc->context, obj)) { -- w->parent->trace(trc); -- w->events.trace(trc); -- if (w->current) -- w->current->trace(trc); -- JS_CALL_OBJECT_TRACER(trc, JS_GetGlobalObject(w->context), "Worker global"); -- } -- } -- -- static void jsFinalize(JSContext *cx, JSObject *obj) { -- JS_ASSERT(JS_GET_CLASS(cx, obj) == &jsWorkerClass); -- if (Worker *w = (Worker *) JS_GetPrivate(cx, obj)) -- delete w; -- } -- -- static JSBool jsOperationCallback(JSContext *cx) { -- Worker *w = (Worker *) JS_GetContextPrivate(cx); -- JSAutoSuspendRequest suspend(cx); // avoid nesting w->lock in a request -- return !w->checkTermination(); -- } -- -- static JSBool jsResolveGlobal(JSContext *cx, JSObject *obj, jsid id, uintN flags, -- JSObject **objp) -- { -- JSBool resolved; -- -- if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) -- return false; -- if (resolved) -- *objp = obj; -- -- return true; -- } -- -- static JSBool jsPostMessageToParent(JSContext *cx, uintN argc, jsval *vp); -- static JSBool jsPostMessageToChild(JSContext *cx, uintN argc, jsval *vp); -- static JSBool jsTerminate(JSContext *cx, uintN argc, jsval *vp); -- -- bool checkTermination() { -- AutoLock hold(lock); -- return lockedCheckTermination(); -- } -- -- bool lockedCheckTermination() { -- if (terminateFlag || threadPool->isTerminating()) { -- terminateSelf(); -- terminateFlag = 0; -- } -- return terminated; -- } -- -- // Caller must hold the lock. -- void terminateSelf() { -- terminated = true; -- while (!events.empty()) -- events.pop()->destroy(context); -- -- // Tell the children to shut down too. An arbitrarily silly amount of -- // processing could happen before the whole tree is terminated; but -- // this way we don't have to worry about blowing the C stack. -- for (ChildSet::Enum e(children); !e.empty(); e.popFront()) -- e.front()->setTerminateFlag(); // note: nesting locks here -- } -- -- public: -- ~Worker() { -- if (parent) -- parent->removeChild(this); -- dispose(); -- } -- -- void dispose() { -- JS_ASSERT(!current); -- while (!events.empty()) -- events.pop()->destroy(context); -- if (lock) { -- JS_DESTROY_LOCK(lock); -- lock = NULL; -- } -- if (context) { -- JS_SetContextThread(context); -- JS_DestroyContextNoGC(context); -- context = NULL; -- } -- object = NULL; -- -- // Do not call parent->removeChild(). This is called either from -- // ~Worker, which calls it for us; or from parent->disposeChildren or -- // Worker::create, which require that it not be called. -- parent = NULL; -- disposeChildren(); -- } -- -- static Worker *create(JSContext *parentcx, WorkerParent *parent, -- JSString *scriptName, JSObject *obj); -- -- JSObject *asObject() { return object; } -- -- JSObject *getGlobal() { return JS_GetGlobalObject(context); } -- -- WorkerParent *getParent() { return parent; } -- -- virtual JSLock *getLock() { return lock; } -- -- virtual ThreadPool *getThreadPool() { return threadPool; } -- -- bool post(Event *event) { -- AutoLock hold(lock); -- if (terminated) -- return false; -- if (!current && events.empty() && !threadPool->getWorkerQueue()->post(this)) -- return false; -- return events.push(event); -- } -- -- void setTerminateFlag() { -- AutoLock hold(lock); -- terminateFlag = true; -- if (current) -- JS_TriggerOperationCallback(context); -- } -- -- void processOneEvent(); -- -- /* Trace method to be called from C++. */ -- void trace(JSTracer *trc) { -- // Just mark the JSObject. If we haven't already been marked, -- // jsTraceWorker will be called, at which point we'll trace referents. -- JS_CALL_OBJECT_TRACER(trc, object, "queued Worker"); -- } -- -- static bool getWorkerParentFromConstructor(JSContext *cx, JSObject *ctor, WorkerParent **p) { -- jsval v; -- if (!JS_GetReservedSlot(cx, ctor, 0, &v)) -- return false; -- if (JSVAL_IS_VOID(v)) { -- // This means ctor is the root Worker constructor (created in -- // Worker::initWorkers as opposed to Worker::createContext, which sets up -- // Worker sandboxes) and nothing is initialized yet. -- if (!JS_GetReservedSlot(cx, ctor, 1, &v)) -- return false; -- ThreadPool *threadPool = (ThreadPool *) JSVAL_TO_PRIVATE(v); -- if (!threadPool->start(cx)) -- return false; -- WorkerParent *parent = threadPool->getMainQueue(); -- if (!JS_SetReservedSlot(cx, ctor, 0, PRIVATE_TO_JSVAL(parent))) { -- threadPool->shutdown(cx); -- return false; -- } -- *p = parent; -- return true; -- } -- *p = (WorkerParent *) JSVAL_TO_PRIVATE(v); -- return true; -- } -- -- static JSBool jsConstruct(JSContext *cx, uintN argc, jsval *vp) { -- WorkerParent *parent; -- if (!getWorkerParentFromConstructor(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), &parent)) -- return false; -- -- -- JSString *scriptName = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID); -- if (!scriptName) -- return false; -- -- JSObject *obj = JS_NewObject(cx, &jsWorkerClass, NULL, NULL); -- if (!obj || !create(cx, parent, scriptName, obj)) -- return false; -- JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); -- return true; -- } -- -- static JSFunctionSpec jsMethods[3]; -- static JSFunctionSpec jsStaticMethod[2]; -- -- static ThreadPool *initWorkers(JSContext *cx, WorkerHooks *hooks, JSObject *global, -- JSObject **objp) { -- // Create the ThreadPool object and its JSObject wrapper. -- ThreadPool *threadPool = ThreadPool::create(cx, hooks); -- if (!threadPool) -- return NULL; -- -- // Root the ThreadPool JSObject early. -- *objp = threadPool->asObject(); -- -- // Create the Worker constructor. -- JSObject *proto = JS_InitClass(cx, global, NULL, &jsWorkerClass, -- jsConstruct, 1, -- NULL, jsMethods, NULL, NULL); -- if (!proto) -- return NULL; -- -- // Stash a pointer to the ThreadPool in constructor reserved slot 1. -- // It will be used later when lazily creating the MainQueue. -- JSObject *ctor = JS_GetConstructor(cx, proto); -- if (!JS_SetReservedSlot(cx, ctor, 1, PRIVATE_TO_JSVAL(threadPool))) -- return NULL; -- -- return threadPool; -- } --}; -- --class InitEvent : public Event --{ -- public: -- static InitEvent *create(JSContext *cx, Worker *worker, JSString *scriptName) { -- return createEvent<InitEvent>(cx, worker, worker, STRING_TO_JSVAL(scriptName)); -- } -- -- Result process(JSContext *cx) { -- jsval s; -- if (!deserializeData(cx, &s)) -- return fail; -- JS_ASSERT(JSVAL_IS_STRING(s)); -- JSAutoByteString filename(cx, JSVAL_TO_STRING(s)); -- if (!filename) -- return fail; -- -- JSObject *scriptObj = JS_CompileFile(cx, child->getGlobal(), filename.ptr()); -- if (!scriptObj) -- return fail; -- -- AutoValueRooter rval(cx); -- JSBool ok = JS_ExecuteScript(cx, child->getGlobal(), scriptObj, Jsvalify(rval.addr())); -- return Result(ok); -- } --}; -- --class DownMessageEvent : public Event --{ -- public: -- static DownMessageEvent *create(JSContext *cx, Worker *child, jsval data) { -- return createEvent<DownMessageEvent>(cx, child, child, data); -- } -- -- Result process(JSContext *cx) { -- return dispatch(cx, child->getGlobal(), "data", "onmessage", ok); -- } --}; -- --class UpMessageEvent : public Event --{ -- public: -- static UpMessageEvent *create(JSContext *cx, Worker *child, jsval data) { -- return createEvent<UpMessageEvent>(cx, child->getParent(), child, data); -- } -- -- Result process(JSContext *cx) { -- return dispatch(cx, child->asObject(), "data", "onmessage", ok); -- } --}; -- --class ErrorEvent : public Event --{ -- public: -- static ErrorEvent *create(JSContext *cx, Worker *child) { -- JSString *data = NULL; -- jsval exc; -- if (JS_GetPendingException(cx, &exc)) { -- AutoValueRooter tvr(cx, Valueify(exc)); -- JS_ClearPendingException(cx); -- -- // Determine what error message to put in the error event. -- // If exc.message is a string, use that; otherwise use String(exc). -- // (This is a little different from what web workers do.) -- if (JSVAL_IS_OBJECT(exc)) { -- jsval msg; -- if (!JS_GetProperty(cx, JSVAL_TO_OBJECT(exc), "message", &msg)) -- JS_ClearPendingException(cx); -- else if (JSVAL_IS_STRING(msg)) -- data = JSVAL_TO_STRING(msg); -- } -- if (!data) { -- data = JS_ValueToString(cx, exc); -- if (!data) -- return NULL; -- } -- } -- return createEvent<ErrorEvent>(cx, child->getParent(), child, -- data ? STRING_TO_JSVAL(data) : JSVAL_VOID); -- } -- -- Result process(JSContext *cx) { -- return dispatch(cx, child->asObject(), "message", "onerror", forwardToParent); -- } --}; -- --} /* namespace workers */ --} /* namespace js */ -- --using namespace js::workers; -- --void --WorkerParent::disposeChildren() --{ -- for (ChildSet::Enum e(children); !e.empty(); e.popFront()) { -- e.front()->dispose(); -- e.removeFront(); -- } --} -- --bool --MainQueue::shouldStop() --{ -- // Note: This deliberately nests WorkerQueue::lock in MainQueue::lock. -- // Releasing MainQueue::lock would risk a race -- isIdle() could return -- // false, but the workers could become idle before we reacquire -- // MainQueue::lock and go to sleep, and we would wait on the condvar -- // forever. -- return closed || threadPool->getWorkerQueue()->isIdle(); --} -- --void --MainQueue::trace(JSTracer *trc) --{ -- JS_CALL_OBJECT_TRACER(trc, threadPool->asObject(), "MainQueue"); --} -- --void --WorkerQueue::work() { -- AutoLock hold(lock); -- -- Worker *w; -- while (take(&w)) { // can block outside the mutex -- JS_RELEASE_LOCK(lock); -- w->processOneEvent(); // enters request on w->context -- JS_ACQUIRE_LOCK(lock); -- drop(w); -- -- if (lockedIsIdle()) { -- JS_RELEASE_LOCK(lock); -- main->wake(); -- JS_ACQUIRE_LOCK(lock); -- } -- } --} -- --const bool mswin = --#ifdef XP_WIN -- true --#else -- false --#endif -- ; -- --template <class Ch> bool --IsAbsolute(const Ch *filename) --{ -- return filename[0] == '/' || -- (mswin && (filename[0] == '\\' || (filename[0] != '\0' && filename[1] == ':'))); --} -- --// Note: base is a filename, not a directory name. --static JSString * --ResolveRelativePath(JSContext *cx, const char *base, JSString *filename) --{ -- size_t fileLen = JS_GetStringLength(filename); -- const jschar *fileChars = JS_GetStringCharsZ(cx, filename); -- if (!fileChars) -- return NULL; -- -- if (IsAbsolute(fileChars)) -- return filename; -- -- // Strip off the filename part of base. -- size_t dirLen = -1; -- for (size_t i = 0; base[i]; i++) { -- if (base[i] == '/' || (mswin && base[i] == '\\')) -- dirLen = i; -- } -- -- // If base is relative and contains no directories, use filename unchanged. -- if (!IsAbsolute(base) && dirLen == (size_t) -1) -- return filename; -- -- // Otherwise return base[:dirLen + 1] + filename. -- js::Vector<jschar, 0, js::ContextAllocPolicy> result(cx); -- size_t nchars; -- if (!JS_DecodeBytes(cx, base, dirLen + 1, NULL, &nchars)) -- return NULL; -- if (!result.reserve(dirLen + 1 + fileLen)) { -- JS_ReportOutOfMemory(cx); -- return NULL; -- } -- JS_ALWAYS_TRUE(result.resize(dirLen + 1)); -- if (!JS_DecodeBytes(cx, base, dirLen + 1, result.begin(), &nchars)) -- return NULL; -- JS_ALWAYS_TRUE(result.append(fileChars, fileLen)); -- return JS_NewUCStringCopyN(cx, result.begin(), result.length()); --} -- --Worker * --Worker::create(JSContext *parentcx, WorkerParent *parent, JSString *scriptName, JSObject *obj) --{ -- Worker *w = new Worker(); -- if (!w || !w->init(parentcx, parent, obj)) { -- delete w; -- return NULL; -- } -- -- JSStackFrame *frame = JS_GetScriptedCaller(parentcx, NULL); -- const char *base = JS_GetScriptFilename(parentcx, JS_GetFrameScript(parentcx, frame)); -- JSString *scriptPath = ResolveRelativePath(parentcx, base, scriptName); -- if (!scriptPath) -- return NULL; -- -- // Post an InitEvent to run the initialization script. -- Event *event = InitEvent::create(parentcx, w, scriptPath); -- if (!event) -- return NULL; -- if (!w->events.push(event) || !w->threadPool->getWorkerQueue()->post(w)) { -- event->destroy(parentcx); -- JS_ReportOutOfMemory(parentcx); -- w->dispose(); -- return NULL; -- } -- return w; --} -- --void --Worker::processOneEvent() --{ -- Event *event; -- { -- AutoLock hold1(lock); -- if (lockedCheckTermination() || events.empty()) -- return; -- -- event = current = events.pop(); -- } -- -- JS_SetContextThread(context); -- JS_SetNativeStackQuota(context, gMaxStackSize); -- -- Event::Result result; -- { -- JSAutoRequest req(context); -- result = event->process(context); -- } -- -- // Note: we have to leave the above request before calling parent->post or -- // checkTermination, both of which acquire locks. -- if (result == Event::forwardToParent) { -- event->setChildAndRecipient(this, parent); -- if (parent->post(event)) { -- event = NULL; // to prevent it from being deleted below -- } else { -- JS_ReportOutOfMemory(context); -- result = Event::fail; -- } -- } -- if (result == Event::fail && !checkTermination()) { -- JSAutoRequest req(context); -- Event *err = ErrorEvent::create(context, this); -- if (err && !parent->post(err)) { -- JS_ReportOutOfMemory(context); -- err->destroy(context); -- err = NULL; -- } -- if (!err) { -- // FIXME - out of memory, probably should panic -- } -- } -- -- if (event) -- event->destroy(context); -- JS_ClearContextThread(context); -- -- { -- AutoLock hold2(lock); -- current = NULL; -- if (!lockedCheckTermination() && !events.empty()) { -- // Re-enqueue this worker. OOM here effectively kills the worker. -- if (!threadPool->getWorkerQueue()->post(this)) -- JS_ReportOutOfMemory(context); -- } -- } --} -- --JSBool --Worker::jsPostMessageToParent(JSContext *cx, uintN argc, jsval *vp) --{ -- jsval workerval; -- if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0, &workerval)) -- return false; -- Worker *w = (Worker *) JSVAL_TO_PRIVATE(workerval); -- -- { -- JSAutoSuspendRequest suspend(cx); // avoid nesting w->lock in a request -- if (w->checkTermination()) -- return false; -- } -- -- jsval data = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID; -- Event *event = UpMessageEvent::create(cx, w, data); -- if (!event) -- return false; -- if (!w->parent->post(event)) { -- event->destroy(cx); -- JS_ReportOutOfMemory(cx); -- return false; -- } -- JS_SET_RVAL(cx, vp, JSVAL_VOID); -- return true; --} -- --JSBool --Worker::jsPostMessageToChild(JSContext *cx, uintN argc, jsval *vp) --{ -- JSObject *workerobj = JS_THIS_OBJECT(cx, vp); -- if (!workerobj) -- return false; -- Worker *w = (Worker *) JS_GetInstancePrivate(cx, workerobj, &jsWorkerClass, JS_ARGV(cx, vp)); -- if (!w) { -- if (!JS_IsExceptionPending(cx)) -- JS_ReportError(cx, "Worker was shut down"); -- return false; -- } -- -- jsval data = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID; -- Event *event = DownMessageEvent::create(cx, w, data); -- if (!event) -- return false; -- if (!w->post(event)) { -- JS_ReportOutOfMemory(cx); -- return false; -- } -- JS_SET_RVAL(cx, vp, JSVAL_VOID); -- return true; --} -- --JSBool --Worker::jsTerminate(JSContext *cx, uintN argc, jsval *vp) --{ -- JS_SET_RVAL(cx, vp, JSVAL_VOID); -- -- JSObject *workerobj = JS_THIS_OBJECT(cx, vp); -- if (!workerobj) -- return false; -- Worker *w = (Worker *) JS_GetInstancePrivate(cx, workerobj, &jsWorkerClass, JS_ARGV(cx, vp)); -- if (!w) -- return !JS_IsExceptionPending(cx); // ok to terminate twice -- -- JSAutoSuspendRequest suspend(cx); -- w->setTerminateFlag(); -- return true; --} -- --void --Event::trace(JSTracer *trc) --{ -- if (recipient) -- recipient->trace(trc); -- if (child) -- JS_CALL_OBJECT_TRACER(trc, child->asObject(), "worker"); --} -- --JSClass ThreadPool::jsClass = { -- "ThreadPool", JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE, -- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, -- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, jsFinalize, -- NULL, NULL, NULL, NULL, -- NULL, NULL, JS_CLASS_TRACE(jsTraceThreadPool), NULL --}; -- --JSClass Worker::jsWorkerClass = { -- "Worker", JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE, -- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, -- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, jsFinalize, -- NULL, NULL, NULL, NULL, -- NULL, NULL, JS_CLASS_TRACE(jsTraceWorker), NULL --}; -- --JSFunctionSpec Worker::jsMethods[3] = { -- JS_FN("postMessage", Worker::jsPostMessageToChild, 1, 0), -- JS_FN("terminate", Worker::jsTerminate, 0, 0), -- JS_FS_END --}; -- --ThreadPool * --js::workers::init(JSContext *cx, WorkerHooks *hooks, JSObject *global, JSObject **rootp) --{ -- return Worker::initWorkers(cx, hooks, global, rootp); --} -- --void --js::workers::terminateAll(JSRuntime *rt, ThreadPool *tp) --{ -- tp->terminateAll(rt); --} -- --void --js::workers::finish(JSContext *cx, ThreadPool *tp) --{ -- if (MainQueue *mq = tp->getMainQueue()) { -- JS_ALWAYS_TRUE(mq->mainThreadWork(cx, true)); -- tp->shutdown(cx); -- } --} -- --#endif /* JS_THREADSAFE */ -diff -ruN src/shell/jsworkers.h src.new/shell/jsworkers.h ---- shell/jsworkers.h 2011-04-01 06:08:36.000000000 +1100 -+++ shell/jsworkers.h 1970-01-01 10:00:00.000000000 +1000 -@@ -1,93 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- -- * vim: set ts=8 sw=4 et tw=99: -- * -- * ***** BEGIN LICENSE BLOCK ***** -- * Version: MPL 1.1/GPL 2.0/LGPL 2.1 -- * -- * The contents of this file are subject to the Mozilla Public License Version -- * 1.1 (the "License"); you may not use this file except in compliance with -- * the License. You may obtain a copy of the License at -- * http://www.mozilla.org/MPL/ -- * -- * Software distributed under the License is distributed on an "AS IS" basis, -- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -- * for the specific language governing rights and limitations under the -- * License. -- * -- * The Original Code is JavaScript shell workers. -- * -- * The Initial Developer of the Original Code is -- * Mozilla Corporation. -- * Portions created by the Initial Developer are Copyright (C) 2010 -- * the Initial Developer. All Rights Reserved. -- * -- * Contributor(s): -- * Jason Orendorff <jorendorff@mozilla.com> -- * -- * Alternatively, the contents of this file may be used under the terms of -- * either of the GNU General Public License Version 2 or later (the "GPL"), -- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -- * in which case the provisions of the GPL or the LGPL are applicable instead -- * of those above. If you wish to allow use of your version of this file only -- * under the terms of either the GPL or the LGPL, and not to allow others to -- * use your version of this file under the terms of the MPL, indicate your -- * decision by deleting the provisions above and replace them with the notice -- * and other provisions required by the GPL or the LGPL. If you do not delete -- * the provisions above, a recipient may use your version of this file under -- * the terms of any one of the MPL, the GPL or the LGPL. -- * -- * ***** END LICENSE BLOCK ***** */ -- --#ifndef jsworkers_h___ --#define jsworkers_h___ -- --#ifdef JS_THREADSAFE -- --#include "jsapi.h" -- --/* -- * Workers for the JS shell. -- * -- * Note: The real implementation of DOM Workers is in dom/src/threads. -- */ --namespace js { -- namespace workers { -- class ThreadPool; -- -- class WorkerHooks { -- public: -- virtual JSObject *newGlobalObject(JSContext *cx) = 0; -- virtual ~WorkerHooks() {} -- }; -- -- /* -- * Initialize workers. This defines the Worker constructor on global. -- * Requires request. rootp must point to a GC root. -- * -- * On success, *rootp receives a pointer to an object, and init returns -- * a non-null value. The caller must keep the object rooted and must -- * pass it to js::workers::finish later. -- */ -- ThreadPool *init(JSContext *cx, WorkerHooks *hooks, JSObject *global, JSObject **rootp); -- -- /* Asynchronously signal for all workers to terminate. -- * -- * Call this before calling finish() to shut down without waiting for -- * all messages to be proceesed. -- */ -- void terminateAll(JSRuntime *rt, ThreadPool *tp); -- -- /* -- * Finish running any workers, shut down the thread pool, and free all -- * resources associated with workers. The application must call this -- * before shutting down the runtime, and not during GC. -- * -- * Requires request. -- */ -- void finish(JSContext *cx, ThreadPool *tp); -- } --} -- --#endif /* JS_THREADSAFE */ -- --#endif /* jsworkers_h___ */ -diff -ruN src/tests/browser.js src.new/tests/browser.js ---- tests/browser.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/browser.js 2013-03-23 22:03:56.716635673 +1100 -@@ -767,17 +767,6 @@ - document.write(s); - } - --var JSTest = { -- waitForExplicitFinish: function () { -- gDelayTestDriverEnd = true; -- }, -- -- testFinished: function () { -- gDelayTestDriverEnd = false; -- jsTestDriverEnd(); -- } --}; -- - function jsTestDriverEnd() - { - // gDelayTestDriverEnd is used to -diff -ruN src/tests/js1_8_5/extensions/jstests.list src.new/tests/js1_8_5/extensions/jstests.list ---- tests/js1_8_5/extensions/jstests.list 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/jstests.list 2013-03-23 22:29:16.973264001 +1100 -@@ -1,13 +1,6 @@ - url-prefix ../../jsreftest.html?test=js1_8_5/extensions/ - script typedarray.js - script typedarray-prototype.js --skip-if(!xulRuntime.shell) script worker-error.js # these tests sometimes hang in browser, bug 559954, bug 562333 --skip-if(!xulRuntime.shell) script worker-error-propagation.js --skip-if(!xulRuntime.shell) script worker-fib.js --skip-if(!xulRuntime.shell) script worker-init.js --skip-if(!xulRuntime.shell) script worker-simple.js --skip-if(!xulRuntime.shell) script worker-terminate.js --skip-if(!xulRuntime.shell) script worker-timeout.js - script scripted-proxies.js - script array-length-protochange.js - script parseInt-octal.js -diff -ruN src/tests/js1_8_5/extensions/worker-error-child.js src.new/tests/js1_8_5/extensions/worker-error-child.js ---- tests/js1_8_5/extensions/worker-error-child.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-error-child.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,9 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ --function onmessage(event) { -- throw new Error("fail"); --} -diff -ruN src/tests/js1_8_5/extensions/worker-error-propagation-child.js src.new/tests/js1_8_5/extensions/worker-error-propagation-child.js ---- tests/js1_8_5/extensions/worker-error-propagation-child.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-error-propagation-child.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,16 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --function onmessage(event) { -- var n = +event.data; -- if (n == 0) -- throw new Error("boom"); -- var w = new Worker(workerDir + "worker-error-propagation-child.js"); -- w.onmessage = function (event) { postMessage(event.data); }; -- // No w.onerror here. We are testing error propagation when it is absent. -- w.postMessage(n - 1 + ""); --} -diff -ruN src/tests/js1_8_5/extensions/worker-error-propagation.js src.new/tests/js1_8_5/extensions/worker-error-propagation.js ---- tests/js1_8_5/extensions/worker-error-propagation.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-error-propagation.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,20 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --if (typeof Worker != 'undefined') { -- JSTest.waitForExplicitFinish(); -- var w = Worker(workerDir + "worker-error-propagation-child.js"); -- var errors = 0; -- w.onmessage = function () { throw new Error("no reply expected"); }; -- w.onerror = function (event) { -- reportCompare("string", typeof event.message, "typeof event.message"); -- JSTest.testFinished(); -- }; -- w.postMessage("5"); --} else { -- reportCompare(0, 0, " PASSED! Test skipped. Shell workers required."); --} -diff -ruN src/tests/js1_8_5/extensions/worker-error.js src.new/tests/js1_8_5/extensions/worker-error.js ---- tests/js1_8_5/extensions/worker-error.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-error.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,21 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --if (typeof Worker != 'undefined') { -- JSTest.waitForExplicitFinish(); -- -- // The script throws new Error("fail") on first message. -- var w = Worker(workerDir + "worker-error-child.js"); -- var a = []; -- w.onerror = function (event) { -- reportCompare("fail", event.message, "worker-error"); -- JSTest.testFinished(); -- }; -- w.postMessage("hello"); --} else { -- reportCompare(0, 0, "Test skipped. Shell workers required."); --} -diff -ruN src/tests/js1_8_5/extensions/worker-fib-child.js src.new/tests/js1_8_5/extensions/worker-fib-child.js ---- tests/js1_8_5/extensions/worker-fib-child.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-fib-child.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,27 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --function onmessage(event) { -- var a = event.data.split(/\t/); -- var n = Number(a[0]); -- var workerDir = a[1]; -- -- if (n <= 1) { -- postMessage("" + n); -- } else { -- var w1 = new Worker(workerDir + "worker-fib-child.js"), -- w2 = new Worker(workerDir + "worker-fib-child.js"); -- var a = []; -- w1.onmessage = w2.onmessage = function(event) { -- a.push(+event.data); -- if (a.length == 2) -- postMessage(a[0] + a[1] + ""); -- }; -- w1.postMessage(n - 1 + "\t" + workerDir); -- w2.postMessage(n - 2 + "\t" + workerDir); -- } --} -diff -ruN src/tests/js1_8_5/extensions/worker-fib.js src.new/tests/js1_8_5/extensions/worker-fib.js ---- tests/js1_8_5/extensions/worker-fib.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-fib.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,18 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --if (typeof Worker != 'undefined') { -- JSTest.waitForExplicitFinish(); -- var w = Worker(workerDir + "worker-fib-child.js"); -- w.onmessage = function (event) { -- reportCompare("55", event.data, "worker-fib"); -- JSTest.testFinished(); -- }; -- w.postMessage("10\t" + workerDir); // 0 1 1 2 3 5 8 13 21 34 55 --} else { -- reportCompare(0, 0, "Test skipped. Shell workers required."); --} -diff -ruN src/tests/js1_8_5/extensions/worker-init-child.js src.new/tests/js1_8_5/extensions/worker-init-child.js ---- tests/js1_8_5/extensions/worker-init-child.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-init-child.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,8 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ --postMessage('do your worst'); --for (;;) ; -diff -ruN src/tests/js1_8_5/extensions/worker-init.js src.new/tests/js1_8_5/extensions/worker-init.js ---- tests/js1_8_5/extensions/worker-init.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-init.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,19 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --if (typeof Worker != 'undefined') { -- JSTest.waitForExplicitFinish(); -- // Messages sent during initialization are a corner case, but in any case -- // they should be delivered (no waiting until initialization is complete). -- var w = new Worker(workerDir + "worker-init-child.js"); // posts a message, then loops forever -- w.onmessage = function (event) { -- reportCompare(0, 0, "worker-init"); -- JSTest.testFinished(); -- }; --} else { -- reportCompare(0, 0, "Test skipped. Shell workers required."); --} -diff -ruN src/tests/js1_8_5/extensions/worker-simple-child.js src.new/tests/js1_8_5/extensions/worker-simple-child.js ---- tests/js1_8_5/extensions/worker-simple-child.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-simple-child.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,8 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --onmessage = function (event) { postMessage(event.data); }; -diff -ruN src/tests/js1_8_5/extensions/worker-simple.js src.new/tests/js1_8_5/extensions/worker-simple.js ---- tests/js1_8_5/extensions/worker-simple.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-simple.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,20 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --if (typeof Worker != 'undefined') { -- JSTest.waitForExplicitFinish(); -- var w = new Worker(workerDir + "worker-simple-child.js"); -- var a = []; -- w.onmessage = function (event) { -- a.push(event.data); -- reportCompare(0, 0, "worker-simple"); -- JSTest.testFinished(); -- }; -- w.postMessage("hello"); --} else { -- reportCompare(0, 0, "Test skipped. Shell workers required."); --} -diff -ruN src/tests/js1_8_5/extensions/worker-terminate-child.js src.new/tests/js1_8_5/extensions/worker-terminate-child.js ---- tests/js1_8_5/extensions/worker-terminate-child.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-terminate-child.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,13 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --onmessage = function (event) { -- var workerDir = event.message; -- var child = new Worker(workerDir + 'worker-terminate-iloop.js'); // loops forever -- child.terminate(); -- postMessage("killed"); --}; -diff -ruN src/tests/js1_8_5/extensions/worker-terminate-iloop.js src.new/tests/js1_8_5/extensions/worker-terminate-iloop.js ---- tests/js1_8_5/extensions/worker-terminate-iloop.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-terminate-iloop.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,9 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --for (;;) -- ; -diff -ruN src/tests/js1_8_5/extensions/worker-terminate.js src.new/tests/js1_8_5/extensions/worker-terminate.js ---- tests/js1_8_5/extensions/worker-terminate.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-terminate.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,37 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff <jorendorff@mozilla.com> -- */ -- --if (typeof Worker != 'undefined') { -- JSTest.waitForExplicitFinish(); -- -- // This tests that a parent worker can terminate a child. We run the test -- // several times serially. If terminate() doesn't work, the runaway Workers -- // will soon outnumber the number of threads in the thread pool, and we -- // will deadlock. -- var i = 0; -- -- function next() { -- if (++i == 10) { -- reportCompare(0, 0, "worker-terminate"); -- JSTest.testFinished(); -- return; -- } -- -- var w = new Worker(workerDir + "worker-terminate-child.js"); -- w.onmessage = function (event) { -- reportCompare("killed", event.data, "killed runaway worker #" + i); -- next(); -- }; -- w.onerror = function (event) { -- reportCompare(0, 1, "Got error: " + event.message); -- }; -- w.postMessage(workerDir); -- } -- next(); --} else { -- reportCompare(0, 0, "Test skipped. Shell workers required."); --} -diff -ruN src/tests/js1_8_5/extensions/worker-timeout-child.js src.new/tests/js1_8_5/extensions/worker-timeout-child.js ---- tests/js1_8_5/extensions/worker-timeout-child.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-timeout-child.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,9 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff -- */ -- --for (;;) -- ; -diff -ruN src/tests/js1_8_5/extensions/worker-timeout.js src.new/tests/js1_8_5/extensions/worker-timeout.js ---- tests/js1_8_5/extensions/worker-timeout.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/js1_8_5/extensions/worker-timeout.js 1970-01-01 10:00:00.000000000 +1000 -@@ -1,18 +0,0 @@ --/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ --/* -- * Any copyright is dedicated to the Public Domain. -- * http://creativecommons.org/licenses/publicdomain/ -- * Contributor: Jason Orendorff -- */ -- --if (typeof timeout == 'function' && typeof Worker != 'undefined') { -- // We don't actually ever call JSTest.testFinished(); instead we -- // time out and exit the shell with exit code 6. -- JSTest.waitForExplicitFinish(); -- expectExitCode(6); -- timeout(1.0); -- for (var i = 0; i < 5; i++) -- new Worker(workerDir + "worker-timeout-child.js"); // just loops forever --} else { -- reportCompare(0, 0, "Test skipped. Shell workers and timeout required."); --} -diff -ruN src/tests/shell.js src.new/tests/shell.js ---- tests/shell.js 2011-04-01 06:08:36.000000000 +1100 -+++ tests/shell.js 2013-03-23 22:07:41.387249919 +1100 -@@ -833,18 +833,6 @@ - } - } - --var JSTest = { -- waitForExplicitFinish: function () { -- gDelayTestDriverEnd = true; -- }, -- -- testFinished: function () { -- gDelayTestDriverEnd = false; -- jsTestDriverEnd(); -- quit(); -- } --}; -- - function jsTestDriverEnd() - { - // gDelayTestDriverEnd is used to |