Line 0
Link Here
|
|
|
1 |
diff -ruN deps.orig/mozilla/js/src/shell/Makefile.in deps/mozilla/js/src/shell/Makefile.in |
2 |
--- deps.orig/mozilla/js/src/shell/Makefile.in 2014-06-30 12:54:39.000000000 +0400 |
3 |
+++ deps/mozilla/js/src/shell/Makefile.in 2014-09-23 07:59:03.000000000 +0400 |
4 |
@@ -47,7 +47,6 @@ |
5 |
PROGRAM = js$(BIN_SUFFIX) |
6 |
CPPSRCS = \ |
7 |
js.cpp \ |
8 |
- jsworkers.cpp \ |
9 |
$(NULL) |
10 |
|
11 |
DEFINES += -DEXPORT_JS_API |
12 |
diff -ruN deps.orig/mozilla/js/src/shell/js.cpp deps/mozilla/js/src/shell/js.cpp |
13 |
--- deps.orig/mozilla/js/src/shell/js.cpp 2014-06-30 12:54:39.000000000 +0400 |
14 |
+++ deps/mozilla/js/src/shell/js.cpp 2014-09-23 07:59:03.000000000 +0400 |
15 |
@@ -91,8 +91,6 @@ |
16 |
#endif /* JSDEBUGGER_C_UI */ |
17 |
#endif /* JSDEBUGGER */ |
18 |
|
19 |
-#include "jsworkers.h" |
20 |
- |
21 |
#include "jsinterpinlines.h" |
22 |
#include "jsobjinlines.h" |
23 |
#include "jsscriptinlines.h" |
24 |
@@ -194,10 +192,6 @@ |
25 |
JSBool gQuitting = JS_FALSE; |
26 |
FILE *gErrFile = NULL; |
27 |
FILE *gOutFile = NULL; |
28 |
-#ifdef JS_THREADSAFE |
29 |
-JSObject *gWorkers = NULL; |
30 |
-js::workers::ThreadPool *gWorkerThreadPool = NULL; |
31 |
-#endif |
32 |
|
33 |
static JSBool reportWarnings = JS_TRUE; |
34 |
static JSBool compileOnly = JS_FALSE; |
35 |
@@ -1324,10 +1318,6 @@ |
36 |
JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "/ i", &gExitCode); |
37 |
|
38 |
gQuitting = JS_TRUE; |
39 |
-#ifdef JS_THREADSAFE |
40 |
- if (gWorkerThreadPool) |
41 |
- js::workers::terminateAll(JS_GetRuntime(cx), gWorkerThreadPool); |
42 |
-#endif |
43 |
return JS_FALSE; |
44 |
} |
45 |
|
46 |
@@ -4164,10 +4154,6 @@ |
47 |
gCanceled = true; |
48 |
if (gExitCode == 0) |
49 |
gExitCode = EXITCODE_TIMEOUT; |
50 |
-#ifdef JS_THREADSAFE |
51 |
- if (gWorkerThreadPool) |
52 |
- js::workers::terminateAll(rt, gWorkerThreadPool); |
53 |
-#endif |
54 |
JS_TriggerAllOperationCallbacks(rt); |
55 |
|
56 |
static const char msg[] = "Script runs for too long, terminating.\n"; |
57 |
@@ -5695,29 +5681,8 @@ |
58 |
#endif /* JSDEBUGGER_C_UI */ |
59 |
#endif /* JSDEBUGGER */ |
60 |
|
61 |
-#ifdef JS_THREADSAFE |
62 |
- class ShellWorkerHooks : public js::workers::WorkerHooks { |
63 |
- public: |
64 |
- JSObject *newGlobalObject(JSContext *cx) { |
65 |
- return NewGlobalObject(cx, NEW_COMPARTMENT); |
66 |
- } |
67 |
- }; |
68 |
- ShellWorkerHooks hooks; |
69 |
- if (!JS_AddNamedObjectRoot(cx, &gWorkers, "Workers") || |
70 |
- (gWorkerThreadPool = js::workers::init(cx, &hooks, glob, &gWorkers)) == NULL) { |
71 |
- return 1; |
72 |
- } |
73 |
-#endif |
74 |
- |
75 |
int result = ProcessArgs(cx, glob, argv, argc); |
76 |
|
77 |
-#ifdef JS_THREADSAFE |
78 |
- js::workers::finish(cx, gWorkerThreadPool); |
79 |
- JS_RemoveObjectRoot(cx, &gWorkers); |
80 |
- if (result == 0) |
81 |
- result = gExitCode; |
82 |
-#endif |
83 |
- |
84 |
#ifdef JSDEBUGGER |
85 |
if (jsdc) { |
86 |
#ifdef JSDEBUGGER_C_UI |
87 |
diff -ruN deps.orig/mozilla/js/src/shell/jsworkers.cpp.rej deps/mozilla/js/src/shell/jsworkers.cpp.rej |
88 |
--- deps.orig/mozilla/js/src/shell/jsworkers.cpp.rej 1970-01-01 03:00:00.000000000 +0300 |
89 |
+++ deps/mozilla/js/src/shell/jsworkers.cpp.rej 2014-09-23 07:59:03.000000000 +0400 |
90 |
@@ -0,0 +1,1281 @@ |
91 |
+@@ -1,1280 +0,0 @@ |
92 |
+-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
93 |
+- * vim: set ts=8 sw=4 et tw=99: |
94 |
+- * |
95 |
+- * ***** BEGIN LICENSE BLOCK ***** |
96 |
+- * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
97 |
+- * |
98 |
+- * The contents of this file are subject to the Mozilla Public License Version |
99 |
+- * 1.1 (the "License"); you may not use this file except in compliance with |
100 |
+- * the License. You may obtain a copy of the License at |
101 |
+- * http://www.mozilla.org/MPL/ |
102 |
+- * |
103 |
+- * Software distributed under the License is distributed on an "AS IS" basis, |
104 |
+- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
105 |
+- * for the specific language governing rights and limitations under the |
106 |
+- * License. |
107 |
+- * |
108 |
+- * The Original Code is JavaScript shell workers. |
109 |
+- * |
110 |
+- * The Initial Developer of the Original Code is |
111 |
+- * Mozilla Corporation. |
112 |
+- * Portions created by the Initial Developer are Copyright (C) 2010 |
113 |
+- * the Initial Developer. All Rights Reserved. |
114 |
+- * |
115 |
+- * Contributor(s): |
116 |
+- * Jason Orendorff <jorendorff@mozilla.com> |
117 |
+- * |
118 |
+- * Alternatively, the contents of this file may be used under the terms of |
119 |
+- * either of the GNU General Public License Version 2 or later (the "GPL"), |
120 |
+- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
121 |
+- * in which case the provisions of the GPL or the LGPL are applicable instead |
122 |
+- * of those above. If you wish to allow use of your version of this file only |
123 |
+- * under the terms of either the GPL or the LGPL, and not to allow others to |
124 |
+- * use your version of this file under the terms of the MPL, indicate your |
125 |
+- * decision by deleting the provisions above and replace them with the notice |
126 |
+- * and other provisions required by the GPL or the LGPL. If you do not delete |
127 |
+- * the provisions above, a recipient may use your version of this file under |
128 |
+- * the terms of any one of the MPL, the GPL or the LGPL. |
129 |
+- * |
130 |
+- * ***** END LICENSE BLOCK ***** */ |
131 |
+- |
132 |
+-#ifdef JS_THREADSAFE |
133 |
+- |
134 |
+-#include <algorithm> |
135 |
+-#include <string.h> |
136 |
+-#include "prthread.h" |
137 |
+-#include "prlock.h" |
138 |
+-#include "prcvar.h" |
139 |
+-#include "jsapi.h" |
140 |
+-#include "jscntxt.h" |
141 |
+-#include "jshashtable.h" |
142 |
+-#include "jsstdint.h" |
143 |
+-#include "jslock.h" |
144 |
+-#include "jsvector.h" |
145 |
+-#include "jsworkers.h" |
146 |
+- |
147 |
+-extern size_t gMaxStackSize; |
148 |
+- |
149 |
+-/* |
150 |
+- * JavaScript shell workers. |
151 |
+- * |
152 |
+- * == Object lifetime rules == |
153 |
+- * |
154 |
+- * - The ThreadPool lasts from init() to finish(). |
155 |
+- * |
156 |
+- * - The ThreadPool owns the MainQueue and the WorkerQueue. Those live from |
157 |
+- * the time the first Worker is created until finish(). |
158 |
+- * |
159 |
+- * - Each JS Worker object has the same lifetime as the corresponding C++ |
160 |
+- * Worker object. A Worker is live if (a) the Worker JSObject is still |
161 |
+- * live; (b) the Worker has an incoming event pending or running; (c) it |
162 |
+- * has sent an outgoing event to its parent that is still pending; or (d) |
163 |
+- * it has any live child Workers. |
164 |
+- * |
165 |
+- * - finish() continues to wait for events until all threads are idle. |
166 |
+- * |
167 |
+- * Event objects, however, are basically C++-only. The JS Event objects are |
168 |
+- * just plain old JSObjects. They don't keep anything alive. |
169 |
+- * |
170 |
+- * == Locking scheme == |
171 |
+- * |
172 |
+- * When mixing mutexes and the JSAPI request model, there are two choices: |
173 |
+- * |
174 |
+- * - Always nest the mutexes in requests. Since threads in requests are not |
175 |
+- * supposed to block, this means the mutexes must be only briefly held. |
176 |
+- * |
177 |
+- * - Never nest the mutexes in requests. Since this allows threads to race |
178 |
+- * with the GC, trace() methods must go through the mutexes just like |
179 |
+- * everyone else. |
180 |
+- * |
181 |
+- * This code uses the latter approach for all locks. |
182 |
+- * |
183 |
+- * In one case, a thread holding a Worker's mutex can acquire the mutex of one |
184 |
+- * of its child Workers. See Worker::terminateSelf. (This can't deadlock because |
185 |
+- * the parent-child relationship is a partial order.) |
186 |
+- */ |
187 |
+- |
188 |
+-namespace js { |
189 |
+-namespace workers { |
190 |
+- |
191 |
+-template <class T, class AllocPolicy> |
192 |
+-class Queue { |
193 |
+- private: |
194 |
+- typedef Vector<T, 4, AllocPolicy> Vec; |
195 |
+- Vec v1; |
196 |
+- Vec v2; |
197 |
+- Vec *front; |
198 |
+- Vec *back; |
199 |
+- |
200 |
+- // Queue is not copyable. |
201 |
+- Queue(const Queue &); |
202 |
+- Queue & operator=(const Queue &); |
203 |
+- |
204 |
+- public: |
205 |
+- Queue() : front(&v1), back(&v2) {} |
206 |
+- bool push(T t) { return back->append(t); } |
207 |
+- bool empty() { return front->empty() && back->empty(); } |
208 |
+- |
209 |
+- T pop() { |
210 |
+- if (front->empty()) { |
211 |
+- std::reverse(back->begin(), back->end()); |
212 |
+- Vec *tmp = front; |
213 |
+- front = back; |
214 |
+- back = tmp; |
215 |
+- } |
216 |
+- T item = front->back(); |
217 |
+- front->popBack(); |
218 |
+- return item; |
219 |
+- } |
220 |
+- |
221 |
+- void clear() { |
222 |
+- v1.clear(); |
223 |
+- v2.clear(); |
224 |
+- } |
225 |
+- |
226 |
+- void trace(JSTracer *trc) { |
227 |
+- for (T *p = v1.begin(); p != v1.end(); p++) |
228 |
+- (*p)->trace(trc); |
229 |
+- for (T *p = v2.begin(); p != v2.end(); p++) |
230 |
+- (*p)->trace(trc); |
231 |
+- } |
232 |
+-}; |
233 |
+- |
234 |
+-class Event; |
235 |
+-class ThreadPool; |
236 |
+-class Worker; |
237 |
+- |
238 |
+-class WorkerParent { |
239 |
+- protected: |
240 |
+- typedef HashSet<Worker *, DefaultHasher<Worker *>, SystemAllocPolicy> ChildSet; |
241 |
+- ChildSet children; |
242 |
+- |
243 |
+- bool initWorkerParent() { return children.init(8); } |
244 |
+- |
245 |
+- public: |
246 |
+- virtual JSLock *getLock() = 0; |
247 |
+- virtual ThreadPool *getThreadPool() = 0; |
248 |
+- virtual bool post(Event *item) = 0; // false on OOM or queue closed |
249 |
+- virtual void trace(JSTracer *trc) = 0; |
250 |
+- |
251 |
+- bool addChild(Worker *w) { |
252 |
+- AutoLock hold(getLock()); |
253 |
+- return children.put(w) != NULL; |
254 |
+- } |
255 |
+- |
256 |
+- // This must be called only from GC or when all threads are shut down. It |
257 |
+- // does not bother with locking. |
258 |
+- void removeChild(Worker *w) { |
259 |
+- ChildSet::Ptr p = children.lookup(w); |
260 |
+- JS_ASSERT(p); |
261 |
+- children.remove(p); |
262 |
+- } |
263 |
+- |
264 |
+- void disposeChildren(); |
265 |
+-}; |
266 |
+- |
267 |
+-template <class T> |
268 |
+-class ThreadSafeQueue |
269 |
+-{ |
270 |
+- protected: |
271 |
+- Queue<T, SystemAllocPolicy> queue; |
272 |
+- JSLock *lock; |
273 |
+- PRCondVar *condvar; |
274 |
+- bool closed; |
275 |
+- |
276 |
+- private: |
277 |
+- Vector<T, 8, SystemAllocPolicy> busy; |
278 |
+- |
279 |
+- protected: |
280 |
+- ThreadSafeQueue() : lock(NULL), condvar(NULL), closed(false) {} |
281 |
+- |
282 |
+- ~ThreadSafeQueue() { |
283 |
+- if (condvar) |
284 |
+- JS_DESTROY_CONDVAR(condvar); |
285 |
+- if (lock) |
286 |
+- JS_DESTROY_LOCK(lock); |
287 |
+- } |
288 |
+- |
289 |
+- // Called by take() with the lock held. |
290 |
+- virtual bool shouldStop() { return closed; } |
291 |
+- |
292 |
+- public: |
293 |
+- bool initThreadSafeQueue() { |
294 |
+- JS_ASSERT(!lock); |
295 |
+- JS_ASSERT(!condvar); |
296 |
+- return (lock = JS_NEW_LOCK()) && (condvar = JS_NEW_CONDVAR(lock)); |
297 |
+- } |
298 |
+- |
299 |
+- bool post(T t) { |
300 |
+- AutoLock hold(lock); |
301 |
+- if (closed) |
302 |
+- return false; |
303 |
+- if (queue.empty()) |
304 |
+- JS_NOTIFY_ALL_CONDVAR(condvar); |
305 |
+- return queue.push(t); |
306 |
+- } |
307 |
+- |
308 |
+- void close() { |
309 |
+- AutoLock hold(lock); |
310 |
+- closed = true; |
311 |
+- queue.clear(); |
312 |
+- JS_NOTIFY_ALL_CONDVAR(condvar); |
313 |
+- } |
314 |
+- |
315 |
+- // The caller must hold the lock. |
316 |
+- bool take(T *t) { |
317 |
+- while (queue.empty()) { |
318 |
+- if (shouldStop()) |
319 |
+- return false; |
320 |
+- JS_WAIT_CONDVAR(condvar, JS_NO_TIMEOUT); |
321 |
+- } |
322 |
+- *t = queue.pop(); |
323 |
+- busy.append(*t); |
324 |
+- return true; |
325 |
+- } |
326 |
+- |
327 |
+- // The caller must hold the lock. |
328 |
+- void drop(T item) { |
329 |
+- for (T *p = busy.begin(); p != busy.end(); p++) { |
330 |
+- if (*p == item) { |
331 |
+- *p = busy.back(); |
332 |
+- busy.popBack(); |
333 |
+- return; |
334 |
+- } |
335 |
+- } |
336 |
+- JS_NOT_REACHED("removeBusy"); |
337 |
+- } |
338 |
+- |
339 |
+- bool lockedIsIdle() { return busy.empty() && queue.empty(); } |
340 |
+- |
341 |
+- bool isIdle() { |
342 |
+- AutoLock hold(lock); |
343 |
+- return lockedIsIdle(); |
344 |
+- } |
345 |
+- |
346 |
+- void wake() { |
347 |
+- AutoLock hold(lock); |
348 |
+- JS_NOTIFY_ALL_CONDVAR(condvar); |
349 |
+- } |
350 |
+- |
351 |
+- void trace(JSTracer *trc) { |
352 |
+- AutoLock hold(lock); |
353 |
+- for (T *p = busy.begin(); p != busy.end(); p++) |
354 |
+- (*p)->trace(trc); |
355 |
+- queue.trace(trc); |
356 |
+- } |
357 |
+-}; |
358 |
+- |
359 |
+-class MainQueue; |
360 |
+- |
361 |
+-class Event |
362 |
+-{ |
363 |
+- protected: |
364 |
+- virtual ~Event() { JS_ASSERT(!data); } |
365 |
+- |
366 |
+- WorkerParent *recipient; |
367 |
+- Worker *child; |
368 |
+- uint64 *data; |
369 |
+- size_t nbytes; |
370 |
+- |
371 |
+- public: |
372 |
+- enum Result { fail = JS_FALSE, ok = JS_TRUE, forwardToParent }; |
373 |
+- |
374 |
+- virtual void destroy(JSContext *cx) { |
375 |
+- JS_free(cx, data); |
376 |
+-#ifdef DEBUG |
377 |
+- data = NULL; |
378 |
+-#endif |
379 |
+- delete this; |
380 |
+- } |
381 |
+- |
382 |
+- void setChildAndRecipient(Worker *aChild, WorkerParent *aRecipient) { |
383 |
+- child = aChild; |
384 |
+- recipient = aRecipient; |
385 |
+- } |
386 |
+- |
387 |
+- bool deserializeData(JSContext *cx, jsval *vp) { |
388 |
+- return !!JS_ReadStructuredClone(cx, data, nbytes, JS_STRUCTURED_CLONE_VERSION, vp, |
389 |
+- NULL, NULL); |
390 |
+- } |
391 |
+- |
392 |
+- virtual Result process(JSContext *cx) = 0; |
393 |
+- |
394 |
+- inline void trace(JSTracer *trc); |
395 |
+- |
396 |
+- template <class EventType> |
397 |
+- static EventType *createEvent(JSContext *cx, WorkerParent *recipient, Worker *child, |
398 |
+- jsval v) |
399 |
+- { |
400 |
+- uint64 *data; |
401 |
+- size_t nbytes; |
402 |
+- if (!JS_WriteStructuredClone(cx, v, &data, &nbytes, NULL, NULL)) |
403 |
+- return NULL; |
404 |
+- |
405 |
+- EventType *event = new EventType; |
406 |
+- if (!event) { |
407 |
+- JS_ReportOutOfMemory(cx); |
408 |
+- return NULL; |
409 |
+- } |
410 |
+- event->recipient = recipient; |
411 |
+- event->child = child; |
412 |
+- event->data = data; |
413 |
+- event->nbytes = nbytes; |
414 |
+- return event; |
415 |
+- } |
416 |
+- |
417 |
+- Result dispatch(JSContext *cx, JSObject *thisobj, const char *dataPropName, |
418 |
+- const char *methodName, Result noHandler) |
419 |
+- { |
420 |
+- if (!data) |
421 |
+- return fail; |
422 |
+- |
423 |
+- JSBool found; |
424 |
+- if (!JS_HasProperty(cx, thisobj, methodName, &found)) |
425 |
+- return fail; |
426 |
+- if (!found) |
427 |
+- return noHandler; |
428 |
+- |
429 |
+- // Create event object. |
430 |
+- jsval v; |
431 |
+- if (!deserializeData(cx, &v)) |
432 |
+- return fail; |
433 |
+- JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL); |
434 |
+- if (!obj || !JS_DefineProperty(cx, obj, dataPropName, v, NULL, NULL, 0)) |
435 |
+- return fail; |
436 |
+- |
437 |
+- // Call event handler. |
438 |
+- jsval argv[1] = { OBJECT_TO_JSVAL(obj) }; |
439 |
+- jsval rval = JSVAL_VOID; |
440 |
+- return Result(JS_CallFunctionName(cx, thisobj, methodName, 1, argv, &rval)); |
441 |
+- } |
442 |
+-}; |
443 |
+- |
444 |
+-typedef ThreadSafeQueue<Event *> EventQueue; |
445 |
+- |
446 |
+-class MainQueue : public EventQueue, public WorkerParent |
447 |
+-{ |
448 |
+- private: |
449 |
+- ThreadPool *threadPool; |
450 |
+- |
451 |
+- public: |
452 |
+- explicit MainQueue(ThreadPool *tp) : threadPool(tp) {} |
453 |
+- |
454 |
+- ~MainQueue() { |
455 |
+- JS_ASSERT(queue.empty()); |
456 |
+- } |
457 |
+- |
458 |
+- bool init() { return initThreadSafeQueue() && initWorkerParent(); } |
459 |
+- |
460 |
+- void destroy(JSContext *cx) { |
461 |
+- while (!queue.empty()) |
462 |
+- queue.pop()->destroy(cx); |
463 |
+- delete this; |
464 |
+- } |
465 |
+- |
466 |
+- virtual JSLock *getLock() { return lock; } |
467 |
+- virtual ThreadPool *getThreadPool() { return threadPool; } |
468 |
+- |
469 |
+- protected: |
470 |
+- virtual bool shouldStop(); |
471 |
+- |
472 |
+- public: |
473 |
+- virtual bool post(Event *event) { return EventQueue::post(event); } |
474 |
+- |
475 |
+- virtual void trace(JSTracer *trc); |
476 |
+- |
477 |
+- void traceChildren(JSTracer *trc) { EventQueue::trace(trc); } |
478 |
+- |
479 |
+- JSBool mainThreadWork(JSContext *cx, bool continueOnError) { |
480 |
+- JSAutoSuspendRequest suspend(cx); |
481 |
+- AutoLock hold(lock); |
482 |
+- |
483 |
+- Event *event; |
484 |
+- while (take(&event)) { |
485 |
+- JS_RELEASE_LOCK(lock); |
486 |
+- Event::Result result; |
487 |
+- { |
488 |
+- JSAutoRequest req(cx); |
489 |
+- result = event->process(cx); |
490 |
+- if (result == Event::forwardToParent) { |
491 |
+- // FIXME - pointlessly truncates the string to 8 bits |
492 |
+- jsval data; |
493 |
+- JSAutoByteString bytes; |
494 |
+- if (event->deserializeData(cx, &data) && |
495 |
+- JSVAL_IS_STRING(data) && |
496 |
+- bytes.encode(cx, JSVAL_TO_STRING(data))) { |
497 |
+- JS_ReportError(cx, "%s", bytes.ptr()); |
498 |
+- } else { |
499 |
+- JS_ReportOutOfMemory(cx); |
500 |
+- } |
501 |
+- result = Event::fail; |
502 |
+- } |
503 |
+- if (result == Event::fail && continueOnError) { |
504 |
+- if (JS_IsExceptionPending(cx) && !JS_ReportPendingException(cx)) |
505 |
+- JS_ClearPendingException(cx); |
506 |
+- result = Event::ok; |
507 |
+- } |
508 |
+- } |
509 |
+- JS_ACQUIRE_LOCK(lock); |
510 |
+- drop(event); |
511 |
+- event->destroy(cx); |
512 |
+- if (result != Event::ok) |
513 |
+- return false; |
514 |
+- } |
515 |
+- return true; |
516 |
+- } |
517 |
+-}; |
518 |
+- |
519 |
+-/* |
520 |
+- * A queue of workers. |
521 |
+- * |
522 |
+- * We keep a queue of workers with pending events, rather than a queue of |
523 |
+- * events, so that two threads won't try to run a Worker at the same time. |
524 |
+- */ |
525 |
+-class WorkerQueue : public ThreadSafeQueue<Worker *> |
526 |
+-{ |
527 |
+- private: |
528 |
+- MainQueue *main; |
529 |
+- |
530 |
+- public: |
531 |
+- explicit WorkerQueue(MainQueue *main) : main(main) {} |
532 |
+- |
533 |
+- void work(); |
534 |
+-}; |
535 |
+- |
536 |
+-/* The top-level object that owns everything else. */ |
537 |
+-class ThreadPool |
538 |
+-{ |
539 |
+- private: |
540 |
+- enum { threadCount = 6 }; |
541 |
+- |
542 |
+- JSObject *obj; |
543 |
+- WorkerHooks *hooks; |
544 |
+- MainQueue *mq; |
545 |
+- WorkerQueue *wq; |
546 |
+- PRThread *threads[threadCount]; |
547 |
+- int32_t terminating; |
548 |
+- |
549 |
+- static JSClass jsClass; |
550 |
+- |
551 |
+- static void start(void* arg) { |
552 |
+- ((WorkerQueue *) arg)->work(); |
553 |
+- } |
554 |
+- |
555 |
+- explicit ThreadPool(WorkerHooks *hooks) : hooks(hooks), mq(NULL), wq(NULL), terminating(0) { |
556 |
+- for (int i = 0; i < threadCount; i++) |
557 |
+- threads[i] = NULL; |
558 |
+- } |
559 |
+- |
560 |
+- public: |
561 |
+- ~ThreadPool() { |
562 |
+- JS_ASSERT(!mq); |
563 |
+- JS_ASSERT(!wq); |
564 |
+- JS_ASSERT(!threads[0]); |
565 |
+- } |
566 |
+- |
567 |
+- static ThreadPool *create(JSContext *cx, WorkerHooks *hooks) { |
568 |
+- ThreadPool *tp = new ThreadPool(hooks); |
569 |
+- if (!tp) { |
570 |
+- JS_ReportOutOfMemory(cx); |
571 |
+- return NULL; |
572 |
+- } |
573 |
+- |
574 |
+- JSObject *obj = JS_NewObject(cx, &jsClass, NULL, NULL); |
575 |
+- if (!obj || !JS_SetPrivate(cx, obj, tp)) { |
576 |
+- delete tp; |
577 |
+- return NULL; |
578 |
+- } |
579 |
+- tp->obj = obj; |
580 |
+- return tp; |
581 |
+- } |
582 |
+- |
583 |
+- JSObject *asObject() { return obj; } |
584 |
+- WorkerHooks *getHooks() { return hooks; } |
585 |
+- WorkerQueue *getWorkerQueue() { return wq; } |
586 |
+- MainQueue *getMainQueue() { return mq; } |
587 |
+- bool isTerminating() { return terminating != 0; } |
588 |
+- |
589 |
+- /* |
590 |
+- * Main thread only. Requires request (to prevent GC, which could see the |
591 |
+- * object in an inconsistent state). |
592 |
+- */ |
593 |
+- bool start(JSContext *cx) { |
594 |
+- JS_ASSERT(!mq && !wq); |
595 |
+- mq = new MainQueue(this); |
596 |
+- if (!mq || !mq->init()) { |
597 |
+- mq->destroy(cx); |
598 |
+- mq = NULL; |
599 |
+- return false; |
600 |
+- } |
601 |
+- wq = new WorkerQueue(mq); |
602 |
+- if (!wq || !wq->initThreadSafeQueue()) { |
603 |
+- delete wq; |
604 |
+- wq = NULL; |
605 |
+- mq->destroy(cx); |
606 |
+- mq = NULL; |
607 |
+- return false; |
608 |
+- } |
609 |
+- JSAutoSuspendRequest suspend(cx); |
610 |
+- bool ok = true; |
611 |
+- for (int i = 0; i < threadCount; i++) { |
612 |
+- threads[i] = PR_CreateThread(PR_USER_THREAD, start, wq, PR_PRIORITY_NORMAL, |
613 |
+- PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0); |
614 |
+- if (!threads[i]) { |
615 |
+- shutdown(cx); |
616 |
+- ok = false; |
617 |
+- break; |
618 |
+- } |
619 |
+- } |
620 |
+- return ok; |
621 |
+- } |
622 |
+- |
623 |
+- void terminateAll(JSRuntime *rt) { |
624 |
+- // See comment about JS_ATOMIC_SET in the implementation of |
625 |
+- // JS_TriggerOperationCallback. |
626 |
+- JS_ATOMIC_SET(&terminating, 1); |
627 |
+- JS_TriggerAllOperationCallbacks(rt); |
628 |
+- } |
629 |
+- |
630 |
+- /* This context is used only to free memory. */ |
631 |
+- void shutdown(JSContext *cx) { |
632 |
+- wq->close(); |
633 |
+- for (int i = 0; i < threadCount; i++) { |
634 |
+- if (threads[i]) { |
635 |
+- PR_JoinThread(threads[i]); |
636 |
+- threads[i] = NULL; |
637 |
+- } |
638 |
+- } |
639 |
+- |
640 |
+- delete wq; |
641 |
+- wq = NULL; |
642 |
+- |
643 |
+- mq->disposeChildren(); |
644 |
+- mq->destroy(cx); |
645 |
+- mq = NULL; |
646 |
+- terminating = 0; |
647 |
+- } |
648 |
+- |
649 |
+- private: |
650 |
+- static void jsTraceThreadPool(JSTracer *trc, JSObject *obj) { |
651 |
+- ThreadPool *tp = unwrap(trc->context, obj); |
652 |
+- if (tp->mq) { |
653 |
+- tp->mq->traceChildren(trc); |
654 |
+- tp->wq->trace(trc); |
655 |
+- } |
656 |
+- } |
657 |
+- |
658 |
+- |
659 |
+- static void jsFinalize(JSContext *cx, JSObject *obj) { |
660 |
+- if (ThreadPool *tp = unwrap(cx, obj)) |
661 |
+- delete tp; |
662 |
+- } |
663 |
+- |
664 |
+- public: |
665 |
+- static ThreadPool *unwrap(JSContext *cx, JSObject *obj) { |
666 |
+- JS_ASSERT(JS_GET_CLASS(cx, obj) == &jsClass); |
667 |
+- return (ThreadPool *) JS_GetPrivate(cx, obj); |
668 |
+- } |
669 |
+-}; |
670 |
+- |
671 |
+-/* |
672 |
+- * A Worker is always in one of 4 states, except when it is being initialized |
673 |
+- * or destroyed, or its lock is held: |
674 |
+- * - idle (!terminated && current == NULL && events.empty()) |
675 |
+- * - enqueued (!terminated && current == NULL && !events.empty()) |
676 |
+- * - busy (!terminated && current != NULL) |
677 |
+- * - terminated (terminated && current == NULL && events.empty()) |
678 |
+- * |
679 |
+- * Separately, there is a terminateFlag that other threads can set |
680 |
+- * asynchronously to tell the Worker to terminate. |
681 |
+- */ |
682 |
+-class Worker : public WorkerParent |
683 |
+-{ |
684 |
+- private: |
685 |
+- ThreadPool *threadPool; |
686 |
+- WorkerParent *parent; |
687 |
+- JSObject *object; // Worker object exposed to parent |
688 |
+- JSContext *context; |
689 |
+- JSLock *lock; |
690 |
+- Queue<Event *, SystemAllocPolicy> events; // owning pointers to pending events |
691 |
+- Event *current; |
692 |
+- bool terminated; |
693 |
+- int32_t terminateFlag; |
694 |
+- |
695 |
+- static JSClass jsWorkerClass; |
696 |
+- |
697 |
+- Worker() |
698 |
+- : threadPool(NULL), parent(NULL), object(NULL), |
699 |
+- context(NULL), lock(NULL), current(NULL), terminated(false), terminateFlag(0) {} |
700 |
+- |
701 |
+- bool init(JSContext *parentcx, WorkerParent *parent, JSObject *obj) { |
702 |
+- JS_ASSERT(!threadPool && !this->parent && !object && !lock); |
703 |
+- |
704 |
+- if (!initWorkerParent() || !parent->addChild(this)) |
705 |
+- return false; |
706 |
+- threadPool = parent->getThreadPool(); |
707 |
+- this->parent = parent; |
708 |
+- this->object = obj; |
709 |
+- lock = JS_NEW_LOCK(); |
710 |
+- return lock && |
711 |
+- createContext(parentcx, parent) && |
712 |
+- JS_SetPrivate(parentcx, obj, this); |
713 |
+- } |
714 |
+- |
715 |
+- bool createContext(JSContext *parentcx, WorkerParent *parent) { |
716 |
+- JSRuntime *rt = JS_GetRuntime(parentcx); |
717 |
+- context = JS_NewContext(rt, 8192); |
718 |
+- if (!context) |
719 |
+- return false; |
720 |
+- |
721 |
+- // The Worker has a strong reference to the global; see jsTraceWorker. |
722 |
+- // JSOPTION_UNROOTED_GLOBAL ensures that when the worker becomes |
723 |
+- // unreachable, it and its global object can be collected. Otherwise |
724 |
+- // the cx->globalObject root would keep them both alive forever. |
725 |
+- JS_SetOptions(context, JS_GetOptions(parentcx) | JSOPTION_UNROOTED_GLOBAL | |
726 |
+- JSOPTION_DONT_REPORT_UNCAUGHT); |
727 |
+- JS_SetVersion(context, JS_GetVersion(parentcx)); |
728 |
+- JS_SetContextPrivate(context, this); |
729 |
+- JS_SetOperationCallback(context, jsOperationCallback); |
730 |
+- JS_BeginRequest(context); |
731 |
+- |
732 |
+- JSObject *global = threadPool->getHooks()->newGlobalObject(context); |
733 |
+- JSObject *post, *proto, *ctor; |
734 |
+- if (!global) |
735 |
+- goto bad; |
736 |
+- JS_SetGlobalObject(context, global); |
737 |
+- |
738 |
+- // Because the Worker is completely isolated from the rest of the |
739 |
+- // runtime, and because any pending events on a Worker keep the Worker |
740 |
+- // alive, this postMessage function cannot be called after the Worker |
741 |
+- // is collected. Therefore it's safe to stash a pointer (a weak |
742 |
+- // reference) to the C++ Worker object in the reserved slot. |
743 |
+- post = JS_GetFunctionObject(JS_DefineFunction(context, global, "postMessage", |
744 |
+- (JSNative) jsPostMessageToParent, 1, 0)); |
745 |
+- if (!post || !JS_SetReservedSlot(context, post, 0, PRIVATE_TO_JSVAL(this))) |
746 |
+- goto bad; |
747 |
+- |
748 |
+- proto = JS_InitClass(context, global, NULL, &jsWorkerClass, jsConstruct, 1, |
749 |
+- NULL, jsMethods, NULL, NULL); |
750 |
+- if (!proto) |
751 |
+- goto bad; |
752 |
+- |
753 |
+- ctor = JS_GetConstructor(context, proto); |
754 |
+- if (!ctor || !JS_SetReservedSlot(context, ctor, 0, PRIVATE_TO_JSVAL(this))) |
755 |
+- goto bad; |
756 |
+- |
757 |
+- JS_EndRequest(context); |
758 |
+- JS_ClearContextThread(context); |
759 |
+- return true; |
760 |
+- |
761 |
+- bad: |
762 |
+- JS_EndRequest(context); |
763 |
+- JS_DestroyContext(context); |
764 |
+- context = NULL; |
765 |
+- return false; |
766 |
+- } |
767 |
+- |
768 |
+- static void jsTraceWorker(JSTracer *trc, JSObject *obj) { |
769 |
+- JS_ASSERT(JS_GET_CLASS(trc->context, obj) == &jsWorkerClass); |
770 |
+- if (Worker *w = (Worker *) JS_GetPrivate(trc->context, obj)) { |
771 |
+- w->parent->trace(trc); |
772 |
+- w->events.trace(trc); |
773 |
+- if (w->current) |
774 |
+- w->current->trace(trc); |
775 |
+- JS_CALL_OBJECT_TRACER(trc, JS_GetGlobalObject(w->context), "Worker global"); |
776 |
+- } |
777 |
+- } |
778 |
+- |
779 |
+- static void jsFinalize(JSContext *cx, JSObject *obj) { |
780 |
+- JS_ASSERT(JS_GET_CLASS(cx, obj) == &jsWorkerClass); |
781 |
+- if (Worker *w = (Worker *) JS_GetPrivate(cx, obj)) |
782 |
+- delete w; |
783 |
+- } |
784 |
+- |
785 |
+- static JSBool jsOperationCallback(JSContext *cx) { |
786 |
+- Worker *w = (Worker *) JS_GetContextPrivate(cx); |
787 |
+- JSAutoSuspendRequest suspend(cx); // avoid nesting w->lock in a request |
788 |
+- return !w->checkTermination(); |
789 |
+- } |
790 |
+- |
791 |
+- static JSBool jsResolveGlobal(JSContext *cx, JSObject *obj, jsid id, uintN flags, |
792 |
+- JSObject **objp) |
793 |
+- { |
794 |
+- JSBool resolved; |
795 |
+- |
796 |
+- if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) |
797 |
+- return false; |
798 |
+- if (resolved) |
799 |
+- *objp = obj; |
800 |
+- |
801 |
+- return true; |
802 |
+- } |
803 |
+- |
804 |
+- static JSBool jsPostMessageToParent(JSContext *cx, uintN argc, jsval *vp); |
805 |
+- static JSBool jsPostMessageToChild(JSContext *cx, uintN argc, jsval *vp); |
806 |
+- static JSBool jsTerminate(JSContext *cx, uintN argc, jsval *vp); |
807 |
+- |
808 |
+- bool checkTermination() { |
809 |
+- AutoLock hold(lock); |
810 |
+- return lockedCheckTermination(); |
811 |
+- } |
812 |
+- |
813 |
+- bool lockedCheckTermination() { |
814 |
+- if (terminateFlag || threadPool->isTerminating()) { |
815 |
+- terminateSelf(); |
816 |
+- terminateFlag = 0; |
817 |
+- } |
818 |
+- return terminated; |
819 |
+- } |
820 |
+- |
821 |
+- // Caller must hold the lock. |
822 |
+- void terminateSelf() { |
823 |
+- terminated = true; |
824 |
+- while (!events.empty()) |
825 |
+- events.pop()->destroy(context); |
826 |
+- |
827 |
+- // Tell the children to shut down too. An arbitrarily silly amount of |
828 |
+- // processing could happen before the whole tree is terminated; but |
829 |
+- // this way we don't have to worry about blowing the C stack. |
830 |
+- for (ChildSet::Enum e(children); !e.empty(); e.popFront()) |
831 |
+- e.front()->setTerminateFlag(); // note: nesting locks here |
832 |
+- } |
833 |
+- |
834 |
+- public: |
835 |
+- ~Worker() { |
836 |
+- if (parent) |
837 |
+- parent->removeChild(this); |
838 |
+- dispose(); |
839 |
+- } |
840 |
+- |
841 |
+- void dispose() { |
842 |
+- JS_ASSERT(!current); |
843 |
+- while (!events.empty()) |
844 |
+- events.pop()->destroy(context); |
845 |
+- if (lock) { |
846 |
+- JS_DESTROY_LOCK(lock); |
847 |
+- lock = NULL; |
848 |
+- } |
849 |
+- if (context) { |
850 |
+- JS_SetContextThread(context); |
851 |
+- JS_DestroyContextNoGC(context); |
852 |
+- context = NULL; |
853 |
+- } |
854 |
+- object = NULL; |
855 |
+- |
856 |
+- // Do not call parent->removeChild(). This is called either from |
857 |
+- // ~Worker, which calls it for us; or from parent->disposeChildren or |
858 |
+- // Worker::create, which require that it not be called. |
859 |
+- parent = NULL; |
860 |
+- disposeChildren(); |
861 |
+- } |
862 |
+- |
863 |
+- static Worker *create(JSContext *parentcx, WorkerParent *parent, |
864 |
+- JSString *scriptName, JSObject *obj); |
865 |
+- |
866 |
+- JSObject *asObject() { return object; } |
867 |
+- |
868 |
+- JSObject *getGlobal() { return JS_GetGlobalObject(context); } |
869 |
+- |
870 |
+- WorkerParent *getParent() { return parent; } |
871 |
+- |
872 |
+- virtual JSLock *getLock() { return lock; } |
873 |
+- |
874 |
+- virtual ThreadPool *getThreadPool() { return threadPool; } |
875 |
+- |
876 |
+- bool post(Event *event) { |
877 |
+- AutoLock hold(lock); |
878 |
+- if (terminated) |
879 |
+- return false; |
880 |
+- if (!current && events.empty() && !threadPool->getWorkerQueue()->post(this)) |
881 |
+- return false; |
882 |
+- return events.push(event); |
883 |
+- } |
884 |
+- |
885 |
+- void setTerminateFlag() { |
886 |
+- AutoLock hold(lock); |
887 |
+- terminateFlag = true; |
888 |
+- if (current) |
889 |
+- JS_TriggerOperationCallback(context); |
890 |
+- } |
891 |
+- |
892 |
+- void processOneEvent(); |
893 |
+- |
894 |
+- /* Trace method to be called from C++. */ |
895 |
+- void trace(JSTracer *trc) { |
896 |
+- // Just mark the JSObject. If we haven't already been marked, |
897 |
+- // jsTraceWorker will be called, at which point we'll trace referents. |
898 |
+- JS_CALL_OBJECT_TRACER(trc, object, "queued Worker"); |
899 |
+- } |
900 |
+- |
901 |
+- static bool getWorkerParentFromConstructor(JSContext *cx, JSObject *ctor, WorkerParent **p) { |
902 |
+- jsval v; |
903 |
+- if (!JS_GetReservedSlot(cx, ctor, 0, &v)) |
904 |
+- return false; |
905 |
+- if (JSVAL_IS_VOID(v)) { |
906 |
+- // This means ctor is the root Worker constructor (created in |
907 |
+- // Worker::initWorkers as opposed to Worker::createContext, which sets up |
908 |
+- // Worker sandboxes) and nothing is initialized yet. |
909 |
+- if (!JS_GetReservedSlot(cx, ctor, 1, &v)) |
910 |
+- return false; |
911 |
+- ThreadPool *threadPool = (ThreadPool *) JSVAL_TO_PRIVATE(v); |
912 |
+- if (!threadPool->start(cx)) |
913 |
+- return false; |
914 |
+- WorkerParent *parent = threadPool->getMainQueue(); |
915 |
+- if (!JS_SetReservedSlot(cx, ctor, 0, PRIVATE_TO_JSVAL(parent))) { |
916 |
+- threadPool->shutdown(cx); |
917 |
+- return false; |
918 |
+- } |
919 |
+- *p = parent; |
920 |
+- return true; |
921 |
+- } |
922 |
+- *p = (WorkerParent *) JSVAL_TO_PRIVATE(v); |
923 |
+- return true; |
924 |
+- } |
925 |
+- |
926 |
+- static JSBool jsConstruct(JSContext *cx, uintN argc, jsval *vp) { |
927 |
+- WorkerParent *parent; |
928 |
+- if (!getWorkerParentFromConstructor(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), &parent)) |
929 |
+- return false; |
930 |
+- |
931 |
+- |
932 |
+- JSString *scriptName = JS_ValueToString(cx, argc ? JS_ARGV(cx, vp)[0] : JSVAL_VOID); |
933 |
+- if (!scriptName) |
934 |
+- return false; |
935 |
+- |
936 |
+- JSObject *obj = JS_NewObject(cx, &jsWorkerClass, NULL, NULL); |
937 |
+- if (!obj || !create(cx, parent, scriptName, obj)) |
938 |
+- return false; |
939 |
+- JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj)); |
940 |
+- return true; |
941 |
+- } |
942 |
+- |
943 |
+- static JSFunctionSpec jsMethods[3]; |
944 |
+- static JSFunctionSpec jsStaticMethod[2]; |
945 |
+- |
946 |
+- static ThreadPool *initWorkers(JSContext *cx, WorkerHooks *hooks, JSObject *global, |
947 |
+- JSObject **objp) { |
948 |
+- // Create the ThreadPool object and its JSObject wrapper. |
949 |
+- ThreadPool *threadPool = ThreadPool::create(cx, hooks); |
950 |
+- if (!threadPool) |
951 |
+- return NULL; |
952 |
+- |
953 |
+- // Root the ThreadPool JSObject early. |
954 |
+- *objp = threadPool->asObject(); |
955 |
+- |
956 |
+- // Create the Worker constructor. |
957 |
+- JSObject *proto = JS_InitClass(cx, global, NULL, &jsWorkerClass, |
958 |
+- jsConstruct, 1, |
959 |
+- NULL, jsMethods, NULL, NULL); |
960 |
+- if (!proto) |
961 |
+- return NULL; |
962 |
+- |
963 |
+- // Stash a pointer to the ThreadPool in constructor reserved slot 1. |
964 |
+- // It will be used later when lazily creating the MainQueue. |
965 |
+- JSObject *ctor = JS_GetConstructor(cx, proto); |
966 |
+- if (!JS_SetReservedSlot(cx, ctor, 1, PRIVATE_TO_JSVAL(threadPool))) |
967 |
+- return NULL; |
968 |
+- |
969 |
+- return threadPool; |
970 |
+- } |
971 |
+-}; |
972 |
+- |
973 |
+-class InitEvent : public Event |
974 |
+-{ |
975 |
+- public: |
976 |
+- static InitEvent *create(JSContext *cx, Worker *worker, JSString *scriptName) { |
977 |
+- return createEvent<InitEvent>(cx, worker, worker, STRING_TO_JSVAL(scriptName)); |
978 |
+- } |
979 |
+- |
980 |
+- Result process(JSContext *cx) { |
981 |
+- jsval s; |
982 |
+- if (!deserializeData(cx, &s)) |
983 |
+- return fail; |
984 |
+- JS_ASSERT(JSVAL_IS_STRING(s)); |
985 |
+- JSAutoByteString filename(cx, JSVAL_TO_STRING(s)); |
986 |
+- if (!filename) |
987 |
+- return fail; |
988 |
+- |
989 |
+- JSObject *scriptObj = JS_CompileFile(cx, child->getGlobal(), filename.ptr()); |
990 |
+- if (!scriptObj) |
991 |
+- return fail; |
992 |
+- |
993 |
+- AutoValueRooter rval(cx); |
994 |
+- JSBool ok = JS_ExecuteScript(cx, child->getGlobal(), scriptObj, Jsvalify(rval.addr())); |
995 |
+- return Result(ok); |
996 |
+- } |
997 |
+-}; |
998 |
+- |
999 |
+-class DownMessageEvent : public Event |
1000 |
+-{ |
1001 |
+- public: |
1002 |
+- static DownMessageEvent *create(JSContext *cx, Worker *child, jsval data) { |
1003 |
+- return createEvent<DownMessageEvent>(cx, child, child, data); |
1004 |
+- } |
1005 |
+- |
1006 |
+- Result process(JSContext *cx) { |
1007 |
+- return dispatch(cx, child->getGlobal(), "data", "onmessage", ok); |
1008 |
+- } |
1009 |
+-}; |
1010 |
+- |
1011 |
+-class UpMessageEvent : public Event |
1012 |
+-{ |
1013 |
+- public: |
1014 |
+- static UpMessageEvent *create(JSContext *cx, Worker *child, jsval data) { |
1015 |
+- return createEvent<UpMessageEvent>(cx, child->getParent(), child, data); |
1016 |
+- } |
1017 |
+- |
1018 |
+- Result process(JSContext *cx) { |
1019 |
+- return dispatch(cx, child->asObject(), "data", "onmessage", ok); |
1020 |
+- } |
1021 |
+-}; |
1022 |
+- |
1023 |
+-class ErrorEvent : public Event |
1024 |
+-{ |
1025 |
+- public: |
1026 |
+- static ErrorEvent *create(JSContext *cx, Worker *child) { |
1027 |
+- JSString *data = NULL; |
1028 |
+- jsval exc; |
1029 |
+- if (JS_GetPendingException(cx, &exc)) { |
1030 |
+- AutoValueRooter tvr(cx, Valueify(exc)); |
1031 |
+- JS_ClearPendingException(cx); |
1032 |
+- |
1033 |
+- // Determine what error message to put in the error event. |
1034 |
+- // If exc.message is a string, use that; otherwise use String(exc). |
1035 |
+- // (This is a little different from what web workers do.) |
1036 |
+- if (JSVAL_IS_OBJECT(exc)) { |
1037 |
+- jsval msg; |
1038 |
+- if (!JS_GetProperty(cx, JSVAL_TO_OBJECT(exc), "message", &msg)) |
1039 |
+- JS_ClearPendingException(cx); |
1040 |
+- else if (JSVAL_IS_STRING(msg)) |
1041 |
+- data = JSVAL_TO_STRING(msg); |
1042 |
+- } |
1043 |
+- if (!data) { |
1044 |
+- data = JS_ValueToString(cx, exc); |
1045 |
+- if (!data) |
1046 |
+- return NULL; |
1047 |
+- } |
1048 |
+- } |
1049 |
+- return createEvent<ErrorEvent>(cx, child->getParent(), child, |
1050 |
+- data ? STRING_TO_JSVAL(data) : JSVAL_VOID); |
1051 |
+- } |
1052 |
+- |
1053 |
+- Result process(JSContext *cx) { |
1054 |
+- return dispatch(cx, child->asObject(), "message", "onerror", forwardToParent); |
1055 |
+- } |
1056 |
+-}; |
1057 |
+- |
1058 |
+-} /* namespace workers */ |
1059 |
+-} /* namespace js */ |
1060 |
+- |
1061 |
+-using namespace js::workers; |
1062 |
+- |
1063 |
+-void |
1064 |
+-WorkerParent::disposeChildren() |
1065 |
+-{ |
1066 |
+- for (ChildSet::Enum e(children); !e.empty(); e.popFront()) { |
1067 |
+- e.front()->dispose(); |
1068 |
+- e.removeFront(); |
1069 |
+- } |
1070 |
+-} |
1071 |
+- |
1072 |
+-bool |
1073 |
+-MainQueue::shouldStop() |
1074 |
+-{ |
1075 |
+- // Note: This deliberately nests WorkerQueue::lock in MainQueue::lock. |
1076 |
+- // Releasing MainQueue::lock would risk a race -- isIdle() could return |
1077 |
+- // false, but the workers could become idle before we reacquire |
1078 |
+- // MainQueue::lock and go to sleep, and we would wait on the condvar |
1079 |
+- // forever. |
1080 |
+- return closed || threadPool->getWorkerQueue()->isIdle(); |
1081 |
+-} |
1082 |
+- |
1083 |
+-void |
1084 |
+-MainQueue::trace(JSTracer *trc) |
1085 |
+-{ |
1086 |
+- JS_CALL_OBJECT_TRACER(trc, threadPool->asObject(), "MainQueue"); |
1087 |
+-} |
1088 |
+- |
1089 |
+-void |
1090 |
+-WorkerQueue::work() { |
1091 |
+- AutoLock hold(lock); |
1092 |
+- |
1093 |
+- Worker *w; |
1094 |
+- while (take(&w)) { // can block outside the mutex |
1095 |
+- JS_RELEASE_LOCK(lock); |
1096 |
+- w->processOneEvent(); // enters request on w->context |
1097 |
+- JS_ACQUIRE_LOCK(lock); |
1098 |
+- drop(w); |
1099 |
+- |
1100 |
+- if (lockedIsIdle()) { |
1101 |
+- JS_RELEASE_LOCK(lock); |
1102 |
+- main->wake(); |
1103 |
+- JS_ACQUIRE_LOCK(lock); |
1104 |
+- } |
1105 |
+- } |
1106 |
+-} |
1107 |
+- |
1108 |
+-const bool mswin = |
1109 |
+-#ifdef XP_WIN |
1110 |
+- true |
1111 |
+-#else |
1112 |
+- false |
1113 |
+-#endif |
1114 |
+- ; |
1115 |
+- |
1116 |
+-template <class Ch> bool |
1117 |
+-IsAbsolute(const Ch *filename) |
1118 |
+-{ |
1119 |
+- return filename[0] == '/' || |
1120 |
+- (mswin && (filename[0] == '\\' || (filename[0] != '\0' && filename[1] == ':'))); |
1121 |
+-} |
1122 |
+- |
1123 |
+-// Note: base is a filename, not a directory name. |
1124 |
+-static JSString * |
1125 |
+-ResolveRelativePath(JSContext *cx, const char *base, JSString *filename) |
1126 |
+-{ |
1127 |
+- size_t fileLen = JS_GetStringLength(filename); |
1128 |
+- const jschar *fileChars = JS_GetStringCharsZ(cx, filename); |
1129 |
+- if (!fileChars) |
1130 |
+- return NULL; |
1131 |
+- |
1132 |
+- if (IsAbsolute(fileChars)) |
1133 |
+- return filename; |
1134 |
+- |
1135 |
+- // Strip off the filename part of base. |
1136 |
+- size_t dirLen = -1; |
1137 |
+- for (size_t i = 0; base[i]; i++) { |
1138 |
+- if (base[i] == '/' || (mswin && base[i] == '\\')) |
1139 |
+- dirLen = i; |
1140 |
+- } |
1141 |
+- |
1142 |
+- // If base is relative and contains no directories, use filename unchanged. |
1143 |
+- if (!IsAbsolute(base) && dirLen == (size_t) -1) |
1144 |
+- return filename; |
1145 |
+- |
1146 |
+- // Otherwise return base[:dirLen + 1] + filename. |
1147 |
+- js::Vector<jschar, 0, js::ContextAllocPolicy> result(cx); |
1148 |
+- size_t nchars; |
1149 |
+- if (!JS_DecodeBytes(cx, base, dirLen + 1, NULL, &nchars)) |
1150 |
+- return NULL; |
1151 |
+- if (!result.reserve(dirLen + 1 + fileLen)) { |
1152 |
+- JS_ReportOutOfMemory(cx); |
1153 |
+- return NULL; |
1154 |
+- } |
1155 |
+- JS_ALWAYS_TRUE(result.resize(dirLen + 1)); |
1156 |
+- if (!JS_DecodeBytes(cx, base, dirLen + 1, result.begin(), &nchars)) |
1157 |
+- return NULL; |
1158 |
+- JS_ALWAYS_TRUE(result.append(fileChars, fileLen)); |
1159 |
+- return JS_NewUCStringCopyN(cx, result.begin(), result.length()); |
1160 |
+-} |
1161 |
+- |
1162 |
+-Worker * |
1163 |
+-Worker::create(JSContext *parentcx, WorkerParent *parent, JSString *scriptName, JSObject *obj) |
1164 |
+-{ |
1165 |
+- Worker *w = new Worker(); |
1166 |
+- if (!w || !w->init(parentcx, parent, obj)) { |
1167 |
+- delete w; |
1168 |
+- return NULL; |
1169 |
+- } |
1170 |
+- |
1171 |
+- JSStackFrame *frame = JS_GetScriptedCaller(parentcx, NULL); |
1172 |
+- const char *base = JS_GetScriptFilename(parentcx, JS_GetFrameScript(parentcx, frame)); |
1173 |
+- JSString *scriptPath = ResolveRelativePath(parentcx, base, scriptName); |
1174 |
+- if (!scriptPath) |
1175 |
+- return NULL; |
1176 |
+- |
1177 |
+- // Post an InitEvent to run the initialization script. |
1178 |
+- Event *event = InitEvent::create(parentcx, w, scriptPath); |
1179 |
+- if (!event) |
1180 |
+- return NULL; |
1181 |
+- if (!w->events.push(event) || !w->threadPool->getWorkerQueue()->post(w)) { |
1182 |
+- event->destroy(parentcx); |
1183 |
+- JS_ReportOutOfMemory(parentcx); |
1184 |
+- w->dispose(); |
1185 |
+- return NULL; |
1186 |
+- } |
1187 |
+- return w; |
1188 |
+-} |
1189 |
+- |
1190 |
+-void |
1191 |
+-Worker::processOneEvent() |
1192 |
+-{ |
1193 |
+- Event *event; |
1194 |
+- { |
1195 |
+- AutoLock hold1(lock); |
1196 |
+- if (lockedCheckTermination() || events.empty()) |
1197 |
+- return; |
1198 |
+- |
1199 |
+- event = current = events.pop(); |
1200 |
+- } |
1201 |
+- |
1202 |
+- JS_SetContextThread(context); |
1203 |
+- JS_SetNativeStackQuota(context, gMaxStackSize); |
1204 |
+- |
1205 |
+- Event::Result result; |
1206 |
+- { |
1207 |
+- JSAutoRequest req(context); |
1208 |
+- result = event->process(context); |
1209 |
+- } |
1210 |
+- |
1211 |
+- // Note: we have to leave the above request before calling parent->post or |
1212 |
+- // checkTermination, both of which acquire locks. |
1213 |
+- if (result == Event::forwardToParent) { |
1214 |
+- event->setChildAndRecipient(this, parent); |
1215 |
+- if (parent->post(event)) { |
1216 |
+- event = NULL; // to prevent it from being deleted below |
1217 |
+- } else { |
1218 |
+- JS_ReportOutOfMemory(context); |
1219 |
+- result = Event::fail; |
1220 |
+- } |
1221 |
+- } |
1222 |
+- if (result == Event::fail && !checkTermination()) { |
1223 |
+- JSAutoRequest req(context); |
1224 |
+- Event *err = ErrorEvent::create(context, this); |
1225 |
+- if (err && !parent->post(err)) { |
1226 |
+- JS_ReportOutOfMemory(context); |
1227 |
+- err->destroy(context); |
1228 |
+- err = NULL; |
1229 |
+- } |
1230 |
+- if (!err) { |
1231 |
+- // FIXME - out of memory, probably should panic |
1232 |
+- } |
1233 |
+- } |
1234 |
+- |
1235 |
+- if (event) |
1236 |
+- event->destroy(context); |
1237 |
+- JS_ClearContextThread(context); |
1238 |
+- |
1239 |
+- { |
1240 |
+- AutoLock hold2(lock); |
1241 |
+- current = NULL; |
1242 |
+- if (!lockedCheckTermination() && !events.empty()) { |
1243 |
+- // Re-enqueue this worker. OOM here effectively kills the worker. |
1244 |
+- if (!threadPool->getWorkerQueue()->post(this)) |
1245 |
+- JS_ReportOutOfMemory(context); |
1246 |
+- } |
1247 |
+- } |
1248 |
+-} |
1249 |
+- |
1250 |
+-JSBool |
1251 |
+-Worker::jsPostMessageToParent(JSContext *cx, uintN argc, jsval *vp) |
1252 |
+-{ |
1253 |
+- jsval workerval; |
1254 |
+- if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)), 0, &workerval)) |
1255 |
+- return false; |
1256 |
+- Worker *w = (Worker *) JSVAL_TO_PRIVATE(workerval); |
1257 |
+- |
1258 |
+- { |
1259 |
+- JSAutoSuspendRequest suspend(cx); // avoid nesting w->lock in a request |
1260 |
+- if (w->checkTermination()) |
1261 |
+- return false; |
1262 |
+- } |
1263 |
+- |
1264 |
+- jsval data = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID; |
1265 |
+- Event *event = UpMessageEvent::create(cx, w, data); |
1266 |
+- if (!event) |
1267 |
+- return false; |
1268 |
+- if (!w->parent->post(event)) { |
1269 |
+- event->destroy(cx); |
1270 |
+- JS_ReportOutOfMemory(cx); |
1271 |
+- return false; |
1272 |
+- } |
1273 |
+- JS_SET_RVAL(cx, vp, JSVAL_VOID); |
1274 |
+- return true; |
1275 |
+-} |
1276 |
+- |
1277 |
+-JSBool |
1278 |
+-Worker::jsPostMessageToChild(JSContext *cx, uintN argc, jsval *vp) |
1279 |
+-{ |
1280 |
+- JSObject *workerobj = JS_THIS_OBJECT(cx, vp); |
1281 |
+- if (!workerobj) |
1282 |
+- return false; |
1283 |
+- Worker *w = (Worker *) JS_GetInstancePrivate(cx, workerobj, &jsWorkerClass, JS_ARGV(cx, vp)); |
1284 |
+- if (!w) { |
1285 |
+- if (!JS_IsExceptionPending(cx)) |
1286 |
+- JS_ReportError(cx, "Worker was shut down"); |
1287 |
+- return false; |
1288 |
+- } |
1289 |
+- |
1290 |
+- jsval data = argc > 0 ? JS_ARGV(cx, vp)[0] : JSVAL_VOID; |
1291 |
+- Event *event = DownMessageEvent::create(cx, w, data); |
1292 |
+- if (!event) |
1293 |
+- return false; |
1294 |
+- if (!w->post(event)) { |
1295 |
+- JS_ReportOutOfMemory(cx); |
1296 |
+- return false; |
1297 |
+- } |
1298 |
+- JS_SET_RVAL(cx, vp, JSVAL_VOID); |
1299 |
+- return true; |
1300 |
+-} |
1301 |
+- |
1302 |
+-JSBool |
1303 |
+-Worker::jsTerminate(JSContext *cx, uintN argc, jsval *vp) |
1304 |
+-{ |
1305 |
+- JS_SET_RVAL(cx, vp, JSVAL_VOID); |
1306 |
+- |
1307 |
+- JSObject *workerobj = JS_THIS_OBJECT(cx, vp); |
1308 |
+- if (!workerobj) |
1309 |
+- return false; |
1310 |
+- Worker *w = (Worker *) JS_GetInstancePrivate(cx, workerobj, &jsWorkerClass, JS_ARGV(cx, vp)); |
1311 |
+- if (!w) |
1312 |
+- return !JS_IsExceptionPending(cx); // ok to terminate twice |
1313 |
+- |
1314 |
+- JSAutoSuspendRequest suspend(cx); |
1315 |
+- w->setTerminateFlag(); |
1316 |
+- return true; |
1317 |
+-} |
1318 |
+- |
1319 |
+-void |
1320 |
+-Event::trace(JSTracer *trc) |
1321 |
+-{ |
1322 |
+- if (recipient) |
1323 |
+- recipient->trace(trc); |
1324 |
+- if (child) |
1325 |
+- JS_CALL_OBJECT_TRACER(trc, child->asObject(), "worker"); |
1326 |
+-} |
1327 |
+- |
1328 |
+-JSClass ThreadPool::jsClass = { |
1329 |
+- "ThreadPool", JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE, |
1330 |
+- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, |
1331 |
+- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, jsFinalize, |
1332 |
+- NULL, NULL, NULL, NULL, |
1333 |
+- NULL, NULL, JS_CLASS_TRACE(jsTraceThreadPool), NULL |
1334 |
+-}; |
1335 |
+- |
1336 |
+-JSClass Worker::jsWorkerClass = { |
1337 |
+- "Worker", JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE, |
1338 |
+- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub, |
1339 |
+- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, jsFinalize, |
1340 |
+- NULL, NULL, NULL, NULL, |
1341 |
+- NULL, NULL, JS_CLASS_TRACE(jsTraceWorker), NULL |
1342 |
+-}; |
1343 |
+- |
1344 |
+-JSFunctionSpec Worker::jsMethods[3] = { |
1345 |
+- JS_FN("postMessage", Worker::jsPostMessageToChild, 1, 0), |
1346 |
+- JS_FN("terminate", Worker::jsTerminate, 0, 0), |
1347 |
+- JS_FS_END |
1348 |
+-}; |
1349 |
+- |
1350 |
+-ThreadPool * |
1351 |
+-js::workers::init(JSContext *cx, WorkerHooks *hooks, JSObject *global, JSObject **rootp) |
1352 |
+-{ |
1353 |
+- return Worker::initWorkers(cx, hooks, global, rootp); |
1354 |
+-} |
1355 |
+- |
1356 |
+-void |
1357 |
+-js::workers::terminateAll(JSRuntime *rt, ThreadPool *tp) |
1358 |
+-{ |
1359 |
+- tp->terminateAll(rt); |
1360 |
+-} |
1361 |
+- |
1362 |
+-void |
1363 |
+-js::workers::finish(JSContext *cx, ThreadPool *tp) |
1364 |
+-{ |
1365 |
+- if (MainQueue *mq = tp->getMainQueue()) { |
1366 |
+- JS_ALWAYS_TRUE(mq->mainThreadWork(cx, true)); |
1367 |
+- tp->shutdown(cx); |
1368 |
+- } |
1369 |
+-} |
1370 |
+- |
1371 |
+-#endif /* JS_THREADSAFE */ |
1372 |
diff -ruN deps.orig/mozilla/js/src/shell/jsworkers.h deps/mozilla/js/src/shell/jsworkers.h |
1373 |
--- deps.orig/mozilla/js/src/shell/jsworkers.h 2014-06-30 12:54:39.000000000 +0400 |
1374 |
+++ deps/mozilla/js/src/shell/jsworkers.h 2014-09-23 07:59:03.000000000 +0400 |
1375 |
@@ -1,93 +0,0 @@ |
1376 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
1377 |
- * vim: set ts=8 sw=4 et tw=99: |
1378 |
- * |
1379 |
- * ***** BEGIN LICENSE BLOCK ***** |
1380 |
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
1381 |
- * |
1382 |
- * The contents of this file are subject to the Mozilla Public License Version |
1383 |
- * 1.1 (the "License"); you may not use this file except in compliance with |
1384 |
- * the License. You may obtain a copy of the License at |
1385 |
- * http://www.mozilla.org/MPL/ |
1386 |
- * |
1387 |
- * Software distributed under the License is distributed on an "AS IS" basis, |
1388 |
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
1389 |
- * for the specific language governing rights and limitations under the |
1390 |
- * License. |
1391 |
- * |
1392 |
- * The Original Code is JavaScript shell workers. |
1393 |
- * |
1394 |
- * The Initial Developer of the Original Code is |
1395 |
- * Mozilla Corporation. |
1396 |
- * Portions created by the Initial Developer are Copyright (C) 2010 |
1397 |
- * the Initial Developer. All Rights Reserved. |
1398 |
- * |
1399 |
- * Contributor(s): |
1400 |
- * Jason Orendorff <jorendorff@mozilla.com> |
1401 |
- * |
1402 |
- * Alternatively, the contents of this file may be used under the terms of |
1403 |
- * either of the GNU General Public License Version 2 or later (the "GPL"), |
1404 |
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
1405 |
- * in which case the provisions of the GPL or the LGPL are applicable instead |
1406 |
- * of those above. If you wish to allow use of your version of this file only |
1407 |
- * under the terms of either the GPL or the LGPL, and not to allow others to |
1408 |
- * use your version of this file under the terms of the MPL, indicate your |
1409 |
- * decision by deleting the provisions above and replace them with the notice |
1410 |
- * and other provisions required by the GPL or the LGPL. If you do not delete |
1411 |
- * the provisions above, a recipient may use your version of this file under |
1412 |
- * the terms of any one of the MPL, the GPL or the LGPL. |
1413 |
- * |
1414 |
- * ***** END LICENSE BLOCK ***** */ |
1415 |
- |
1416 |
-#ifndef jsworkers_h___ |
1417 |
-#define jsworkers_h___ |
1418 |
- |
1419 |
-#ifdef JS_THREADSAFE |
1420 |
- |
1421 |
-#include "jsapi.h" |
1422 |
- |
1423 |
-/* |
1424 |
- * Workers for the JS shell. |
1425 |
- * |
1426 |
- * Note: The real implementation of DOM Workers is in dom/src/threads. |
1427 |
- */ |
1428 |
-namespace js { |
1429 |
- namespace workers { |
1430 |
- class ThreadPool; |
1431 |
- |
1432 |
- class WorkerHooks { |
1433 |
- public: |
1434 |
- virtual JSObject *newGlobalObject(JSContext *cx) = 0; |
1435 |
- virtual ~WorkerHooks() {} |
1436 |
- }; |
1437 |
- |
1438 |
- /* |
1439 |
- * Initialize workers. This defines the Worker constructor on global. |
1440 |
- * Requires request. rootp must point to a GC root. |
1441 |
- * |
1442 |
- * On success, *rootp receives a pointer to an object, and init returns |
1443 |
- * a non-null value. The caller must keep the object rooted and must |
1444 |
- * pass it to js::workers::finish later. |
1445 |
- */ |
1446 |
- ThreadPool *init(JSContext *cx, WorkerHooks *hooks, JSObject *global, JSObject **rootp); |
1447 |
- |
1448 |
- /* Asynchronously signal for all workers to terminate. |
1449 |
- * |
1450 |
- * Call this before calling finish() to shut down without waiting for |
1451 |
- * all messages to be proceesed. |
1452 |
- */ |
1453 |
- void terminateAll(JSRuntime *rt, ThreadPool *tp); |
1454 |
- |
1455 |
- /* |
1456 |
- * Finish running any workers, shut down the thread pool, and free all |
1457 |
- * resources associated with workers. The application must call this |
1458 |
- * before shutting down the runtime, and not during GC. |
1459 |
- * |
1460 |
- * Requires request. |
1461 |
- */ |
1462 |
- void finish(JSContext *cx, ThreadPool *tp); |
1463 |
- } |
1464 |
-} |
1465 |
- |
1466 |
-#endif /* JS_THREADSAFE */ |
1467 |
- |
1468 |
-#endif /* jsworkers_h___ */ |
1469 |
diff -ruN deps.orig/mozilla/js/src/tests/browser.js deps/mozilla/js/src/tests/browser.js |
1470 |
--- deps.orig/mozilla/js/src/tests/browser.js 2014-06-30 12:54:39.000000000 +0400 |
1471 |
+++ deps/mozilla/js/src/tests/browser.js 2014-09-23 07:59:03.000000000 +0400 |
1472 |
@@ -767,17 +767,6 @@ |
1473 |
document.write(s); |
1474 |
} |
1475 |
|
1476 |
-var JSTest = { |
1477 |
- waitForExplicitFinish: function () { |
1478 |
- gDelayTestDriverEnd = true; |
1479 |
- }, |
1480 |
- |
1481 |
- testFinished: function () { |
1482 |
- gDelayTestDriverEnd = false; |
1483 |
- jsTestDriverEnd(); |
1484 |
- } |
1485 |
-}; |
1486 |
- |
1487 |
function jsTestDriverEnd() |
1488 |
{ |
1489 |
// gDelayTestDriverEnd is used to |
1490 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/jstests.list deps/mozilla/js/src/tests/js1_8_5/extensions/jstests.list |
1491 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/jstests.list 2014-06-30 12:54:39.000000000 +0400 |
1492 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/jstests.list 2014-09-23 07:59:03.000000000 +0400 |
1493 |
@@ -1,13 +1,6 @@ |
1494 |
url-prefix ../../jsreftest.html?test=js1_8_5/extensions/ |
1495 |
script typedarray.js |
1496 |
script typedarray-prototype.js |
1497 |
-skip-if(!xulRuntime.shell) script worker-error.js # these tests sometimes hang in browser, bug 559954, bug 562333 |
1498 |
-skip-if(!xulRuntime.shell) script worker-error-propagation.js |
1499 |
-skip-if(!xulRuntime.shell) script worker-fib.js |
1500 |
-skip-if(!xulRuntime.shell) script worker-init.js |
1501 |
-skip-if(!xulRuntime.shell) script worker-simple.js |
1502 |
-skip-if(!xulRuntime.shell) script worker-terminate.js |
1503 |
-skip-if(!xulRuntime.shell) script worker-timeout.js |
1504 |
script scripted-proxies.js |
1505 |
script array-length-protochange.js |
1506 |
script parseInt-octal.js |
1507 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error-child.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error-child.js |
1508 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error-child.js 2014-06-30 12:54:39.000000000 +0400 |
1509 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error-child.js 2014-09-23 07:59:03.000000000 +0400 |
1510 |
@@ -1,9 +0,0 @@ |
1511 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1512 |
-/* |
1513 |
- * Any copyright is dedicated to the Public Domain. |
1514 |
- * http://creativecommons.org/licenses/publicdomain/ |
1515 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1516 |
- */ |
1517 |
-function onmessage(event) { |
1518 |
- throw new Error("fail"); |
1519 |
-} |
1520 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation-child.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation-child.js |
1521 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation-child.js 2014-06-30 12:54:39.000000000 +0400 |
1522 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation-child.js 2014-09-23 07:59:03.000000000 +0400 |
1523 |
@@ -1,16 +0,0 @@ |
1524 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1525 |
-/* |
1526 |
- * Any copyright is dedicated to the Public Domain. |
1527 |
- * http://creativecommons.org/licenses/publicdomain/ |
1528 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1529 |
- */ |
1530 |
- |
1531 |
-function onmessage(event) { |
1532 |
- var n = +event.data; |
1533 |
- if (n == 0) |
1534 |
- throw new Error("boom"); |
1535 |
- var w = new Worker(workerDir + "worker-error-propagation-child.js"); |
1536 |
- w.onmessage = function (event) { postMessage(event.data); }; |
1537 |
- // No w.onerror here. We are testing error propagation when it is absent. |
1538 |
- w.postMessage(n - 1 + ""); |
1539 |
-} |
1540 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation.js |
1541 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation.js 2014-06-30 12:54:39.000000000 +0400 |
1542 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error-propagation.js 2014-09-23 07:59:03.000000000 +0400 |
1543 |
@@ -1,20 +0,0 @@ |
1544 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1545 |
-/* |
1546 |
- * Any copyright is dedicated to the Public Domain. |
1547 |
- * http://creativecommons.org/licenses/publicdomain/ |
1548 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1549 |
- */ |
1550 |
- |
1551 |
-if (typeof Worker != 'undefined') { |
1552 |
- JSTest.waitForExplicitFinish(); |
1553 |
- var w = Worker(workerDir + "worker-error-propagation-child.js"); |
1554 |
- var errors = 0; |
1555 |
- w.onmessage = function () { throw new Error("no reply expected"); }; |
1556 |
- w.onerror = function (event) { |
1557 |
- reportCompare("string", typeof event.message, "typeof event.message"); |
1558 |
- JSTest.testFinished(); |
1559 |
- }; |
1560 |
- w.postMessage("5"); |
1561 |
-} else { |
1562 |
- reportCompare(0, 0, " PASSED! Test skipped. Shell workers required."); |
1563 |
-} |
1564 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error.js |
1565 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-error.js 2014-06-30 12:54:39.000000000 +0400 |
1566 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-error.js 2014-09-23 07:59:03.000000000 +0400 |
1567 |
@@ -1,21 +0,0 @@ |
1568 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1569 |
-/* |
1570 |
- * Any copyright is dedicated to the Public Domain. |
1571 |
- * http://creativecommons.org/licenses/publicdomain/ |
1572 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1573 |
- */ |
1574 |
- |
1575 |
-if (typeof Worker != 'undefined') { |
1576 |
- JSTest.waitForExplicitFinish(); |
1577 |
- |
1578 |
- // The script throws new Error("fail") on first message. |
1579 |
- var w = Worker(workerDir + "worker-error-child.js"); |
1580 |
- var a = []; |
1581 |
- w.onerror = function (event) { |
1582 |
- reportCompare("fail", event.message, "worker-error"); |
1583 |
- JSTest.testFinished(); |
1584 |
- }; |
1585 |
- w.postMessage("hello"); |
1586 |
-} else { |
1587 |
- reportCompare(0, 0, "Test skipped. Shell workers required."); |
1588 |
-} |
1589 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-fib-child.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-fib-child.js |
1590 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-fib-child.js 2014-06-30 12:54:39.000000000 +0400 |
1591 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-fib-child.js 2014-09-23 07:59:03.000000000 +0400 |
1592 |
@@ -1,27 +0,0 @@ |
1593 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1594 |
-/* |
1595 |
- * Any copyright is dedicated to the Public Domain. |
1596 |
- * http://creativecommons.org/licenses/publicdomain/ |
1597 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1598 |
- */ |
1599 |
- |
1600 |
-function onmessage(event) { |
1601 |
- var a = event.data.split(/\t/); |
1602 |
- var n = Number(a[0]); |
1603 |
- var workerDir = a[1]; |
1604 |
- |
1605 |
- if (n <= 1) { |
1606 |
- postMessage("" + n); |
1607 |
- } else { |
1608 |
- var w1 = new Worker(workerDir + "worker-fib-child.js"), |
1609 |
- w2 = new Worker(workerDir + "worker-fib-child.js"); |
1610 |
- var a = []; |
1611 |
- w1.onmessage = w2.onmessage = function(event) { |
1612 |
- a.push(+event.data); |
1613 |
- if (a.length == 2) |
1614 |
- postMessage(a[0] + a[1] + ""); |
1615 |
- }; |
1616 |
- w1.postMessage(n - 1 + "\t" + workerDir); |
1617 |
- w2.postMessage(n - 2 + "\t" + workerDir); |
1618 |
- } |
1619 |
-} |
1620 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-fib.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-fib.js |
1621 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-fib.js 2014-06-30 12:54:39.000000000 +0400 |
1622 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-fib.js 2014-09-23 07:59:03.000000000 +0400 |
1623 |
@@ -1,18 +0,0 @@ |
1624 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1625 |
-/* |
1626 |
- * Any copyright is dedicated to the Public Domain. |
1627 |
- * http://creativecommons.org/licenses/publicdomain/ |
1628 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1629 |
- */ |
1630 |
- |
1631 |
-if (typeof Worker != 'undefined') { |
1632 |
- JSTest.waitForExplicitFinish(); |
1633 |
- var w = Worker(workerDir + "worker-fib-child.js"); |
1634 |
- w.onmessage = function (event) { |
1635 |
- reportCompare("55", event.data, "worker-fib"); |
1636 |
- JSTest.testFinished(); |
1637 |
- }; |
1638 |
- w.postMessage("10\t" + workerDir); // 0 1 1 2 3 5 8 13 21 34 55 |
1639 |
-} else { |
1640 |
- reportCompare(0, 0, "Test skipped. Shell workers required."); |
1641 |
-} |
1642 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-init-child.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-init-child.js |
1643 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-init-child.js 2014-06-30 12:54:39.000000000 +0400 |
1644 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-init-child.js 2014-09-23 07:59:03.000000000 +0400 |
1645 |
@@ -1,8 +0,0 @@ |
1646 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1647 |
-/* |
1648 |
- * Any copyright is dedicated to the Public Domain. |
1649 |
- * http://creativecommons.org/licenses/publicdomain/ |
1650 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1651 |
- */ |
1652 |
-postMessage('do your worst'); |
1653 |
-for (;;) ; |
1654 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-init.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-init.js |
1655 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-init.js 2014-06-30 12:54:39.000000000 +0400 |
1656 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-init.js 2014-09-23 07:59:03.000000000 +0400 |
1657 |
@@ -1,19 +0,0 @@ |
1658 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1659 |
-/* |
1660 |
- * Any copyright is dedicated to the Public Domain. |
1661 |
- * http://creativecommons.org/licenses/publicdomain/ |
1662 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1663 |
- */ |
1664 |
- |
1665 |
-if (typeof Worker != 'undefined') { |
1666 |
- JSTest.waitForExplicitFinish(); |
1667 |
- // Messages sent during initialization are a corner case, but in any case |
1668 |
- // they should be delivered (no waiting until initialization is complete). |
1669 |
- var w = new Worker(workerDir + "worker-init-child.js"); // posts a message, then loops forever |
1670 |
- w.onmessage = function (event) { |
1671 |
- reportCompare(0, 0, "worker-init"); |
1672 |
- JSTest.testFinished(); |
1673 |
- }; |
1674 |
-} else { |
1675 |
- reportCompare(0, 0, "Test skipped. Shell workers required."); |
1676 |
-} |
1677 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-simple-child.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-simple-child.js |
1678 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-simple-child.js 2014-06-30 12:54:39.000000000 +0400 |
1679 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-simple-child.js 2014-09-23 07:59:03.000000000 +0400 |
1680 |
@@ -1,8 +0,0 @@ |
1681 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1682 |
-/* |
1683 |
- * Any copyright is dedicated to the Public Domain. |
1684 |
- * http://creativecommons.org/licenses/publicdomain/ |
1685 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1686 |
- */ |
1687 |
- |
1688 |
-onmessage = function (event) { postMessage(event.data); }; |
1689 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-simple.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-simple.js |
1690 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-simple.js 2014-06-30 12:54:39.000000000 +0400 |
1691 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-simple.js 2014-09-23 07:59:03.000000000 +0400 |
1692 |
@@ -1,20 +0,0 @@ |
1693 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1694 |
-/* |
1695 |
- * Any copyright is dedicated to the Public Domain. |
1696 |
- * http://creativecommons.org/licenses/publicdomain/ |
1697 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1698 |
- */ |
1699 |
- |
1700 |
-if (typeof Worker != 'undefined') { |
1701 |
- JSTest.waitForExplicitFinish(); |
1702 |
- var w = new Worker(workerDir + "worker-simple-child.js"); |
1703 |
- var a = []; |
1704 |
- w.onmessage = function (event) { |
1705 |
- a.push(event.data); |
1706 |
- reportCompare(0, 0, "worker-simple"); |
1707 |
- JSTest.testFinished(); |
1708 |
- }; |
1709 |
- w.postMessage("hello"); |
1710 |
-} else { |
1711 |
- reportCompare(0, 0, "Test skipped. Shell workers required."); |
1712 |
-} |
1713 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-child.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-child.js |
1714 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-child.js 2014-06-30 12:54:39.000000000 +0400 |
1715 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-child.js 2014-09-23 07:59:03.000000000 +0400 |
1716 |
@@ -1,13 +0,0 @@ |
1717 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1718 |
-/* |
1719 |
- * Any copyright is dedicated to the Public Domain. |
1720 |
- * http://creativecommons.org/licenses/publicdomain/ |
1721 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1722 |
- */ |
1723 |
- |
1724 |
-onmessage = function (event) { |
1725 |
- var workerDir = event.message; |
1726 |
- var child = new Worker(workerDir + 'worker-terminate-iloop.js'); // loops forever |
1727 |
- child.terminate(); |
1728 |
- postMessage("killed"); |
1729 |
-}; |
1730 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-iloop.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-iloop.js |
1731 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-iloop.js 2014-06-30 12:54:39.000000000 +0400 |
1732 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate-iloop.js 2014-09-23 07:59:03.000000000 +0400 |
1733 |
@@ -1,9 +0,0 @@ |
1734 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1735 |
-/* |
1736 |
- * Any copyright is dedicated to the Public Domain. |
1737 |
- * http://creativecommons.org/licenses/publicdomain/ |
1738 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1739 |
- */ |
1740 |
- |
1741 |
-for (;;) |
1742 |
- ; |
1743 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate.js |
1744 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate.js 2014-06-30 12:54:39.000000000 +0400 |
1745 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-terminate.js 2014-09-23 07:59:03.000000000 +0400 |
1746 |
@@ -1,37 +0,0 @@ |
1747 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1748 |
-/* |
1749 |
- * Any copyright is dedicated to the Public Domain. |
1750 |
- * http://creativecommons.org/licenses/publicdomain/ |
1751 |
- * Contributor: Jason Orendorff <jorendorff@mozilla.com> |
1752 |
- */ |
1753 |
- |
1754 |
-if (typeof Worker != 'undefined') { |
1755 |
- JSTest.waitForExplicitFinish(); |
1756 |
- |
1757 |
- // This tests that a parent worker can terminate a child. We run the test |
1758 |
- // several times serially. If terminate() doesn't work, the runaway Workers |
1759 |
- // will soon outnumber the number of threads in the thread pool, and we |
1760 |
- // will deadlock. |
1761 |
- var i = 0; |
1762 |
- |
1763 |
- function next() { |
1764 |
- if (++i == 10) { |
1765 |
- reportCompare(0, 0, "worker-terminate"); |
1766 |
- JSTest.testFinished(); |
1767 |
- return; |
1768 |
- } |
1769 |
- |
1770 |
- var w = new Worker(workerDir + "worker-terminate-child.js"); |
1771 |
- w.onmessage = function (event) { |
1772 |
- reportCompare("killed", event.data, "killed runaway worker #" + i); |
1773 |
- next(); |
1774 |
- }; |
1775 |
- w.onerror = function (event) { |
1776 |
- reportCompare(0, 1, "Got error: " + event.message); |
1777 |
- }; |
1778 |
- w.postMessage(workerDir); |
1779 |
- } |
1780 |
- next(); |
1781 |
-} else { |
1782 |
- reportCompare(0, 0, "Test skipped. Shell workers required."); |
1783 |
-} |
1784 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout-child.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout-child.js |
1785 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout-child.js 2014-06-30 12:54:39.000000000 +0400 |
1786 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout-child.js 2014-09-23 07:59:03.000000000 +0400 |
1787 |
@@ -1,9 +0,0 @@ |
1788 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1789 |
-/* |
1790 |
- * Any copyright is dedicated to the Public Domain. |
1791 |
- * http://creativecommons.org/licenses/publicdomain/ |
1792 |
- * Contributor: Jason Orendorff |
1793 |
- */ |
1794 |
- |
1795 |
-for (;;) |
1796 |
- ; |
1797 |
diff -ruN deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout.js deps/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout.js |
1798 |
--- deps.orig/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout.js 2014-06-30 12:54:39.000000000 +0400 |
1799 |
+++ deps/mozilla/js/src/tests/js1_8_5/extensions/worker-timeout.js 2014-09-23 07:59:03.000000000 +0400 |
1800 |
@@ -1,18 +0,0 @@ |
1801 |
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
1802 |
-/* |
1803 |
- * Any copyright is dedicated to the Public Domain. |
1804 |
- * http://creativecommons.org/licenses/publicdomain/ |
1805 |
- * Contributor: Jason Orendorff |
1806 |
- */ |
1807 |
- |
1808 |
-if (typeof timeout == 'function' && typeof Worker != 'undefined') { |
1809 |
- // We don't actually ever call JSTest.testFinished(); instead we |
1810 |
- // time out and exit the shell with exit code 6. |
1811 |
- JSTest.waitForExplicitFinish(); |
1812 |
- expectExitCode(6); |
1813 |
- timeout(1.0); |
1814 |
- for (var i = 0; i < 5; i++) |
1815 |
- new Worker(workerDir + "worker-timeout-child.js"); // just loops forever |
1816 |
-} else { |
1817 |
- reportCompare(0, 0, "Test skipped. Shell workers and timeout required."); |
1818 |
-} |
1819 |
diff -ruN deps.orig/mozilla/js/src/tests/shell.js deps/mozilla/js/src/tests/shell.js |
1820 |
--- deps.orig/mozilla/js/src/tests/shell.js 2014-06-30 12:54:39.000000000 +0400 |
1821 |
+++ deps/mozilla/js/src/tests/shell.js 2014-09-23 07:59:03.000000000 +0400 |
1822 |
@@ -833,18 +833,6 @@ |
1823 |
} |
1824 |
} |
1825 |
|
1826 |
-var JSTest = { |
1827 |
- waitForExplicitFinish: function () { |
1828 |
- gDelayTestDriverEnd = true; |
1829 |
- }, |
1830 |
- |
1831 |
- testFinished: function () { |
1832 |
- gDelayTestDriverEnd = false; |
1833 |
- jsTestDriverEnd(); |
1834 |
- quit(); |
1835 |
- } |
1836 |
-}; |
1837 |
- |
1838 |
function jsTestDriverEnd() |
1839 |
{ |
1840 |
// gDelayTestDriverEnd is used to |