View | Details | Raw Unified | Return to bug 223389 | Differences between
and this patch

Collapse All | Expand All

(-)Makefile (-11 / +10 lines)
Lines 2-11 Link Here
2
# $FreeBSD$
2
# $FreeBSD$
3
3
4
PORTNAME=		oolite
4
PORTNAME=		oolite
5
PORTVERSION=		1.84
5
PORTVERSION=		1.86
6
PORTREVISION=	5
7
CATEGORIES=		games gnustep
6
CATEGORIES=		games gnustep
8
MASTER_SITES=		https://github.com/OoliteProject/oolite/releases/download/1.84/
7
MASTER_SITES=		https://github.com/OoliteProject/oolite/releases/download/1.86/
9
DISTNAME=		${PORTNAME}-source-${PORTVERSION}
8
DISTNAME=		${PORTNAME}-source-${PORTVERSION}
10
DIST_SUBDIR=		oolite
9
DIST_SUBDIR=		oolite
11
10
Lines 50-63 Link Here
50
		share/applications/oolite.desktop \
49
		share/applications/oolite.desktop \
51
		share/pixmaps/oolite-icon.png
50
		share/pixmaps/oolite-icon.png
52
51
53
OPTIONS_DEFINE=	DOCS
52
OPTIONS_DEFINE=	DOCS OPTIMIZED_JS
53
OPTIONS_DEFAULT=	OPTIMIZED_JS
54
OPTIMIZED_JS_DESC=	Use extra compiler optimizations for JavaScript library
54
55
55
BROKEN_aarch64=		fails to configure: error: These compiler flags are invalid: -O
56
BROKEN_armv6=		fails to compile: your compiler does not follow the C++ specification for temporary object destruction order
57
BROKEN_armv7=		fails to compile: your compiler does not follow the C++ specification for temporary object destruction order
58
59
.include <bsd.port.pre.mk>
60
61
post-patch: .SILENT
56
post-patch: .SILENT
62
	${REINPLACE_CMD} -e 's/GNUSTEP_USER_ROOT/GNUSTEP_LOCAL_ROOT/ ; \
57
	${REINPLACE_CMD} -e 's/GNUSTEP_USER_ROOT/GNUSTEP_LOCAL_ROOT/ ; \
63
		s/sdl-config/$${SDL_CONFIG}/ ; \
58
		s/sdl-config/$${SDL_CONFIG}/ ; \
Lines 72-77 Link Here
72
	${REINPLACE_CMD} -e 's|oolite-saves|\.oolite-saves|' \
67
	${REINPLACE_CMD} -e 's|oolite-saves|\.oolite-saves|' \
73
		${WRKSRC}/src/Core/NSFileManagerOOExtensions.h
68
		${WRKSRC}/src/Core/NSFileManagerOOExtensions.h
74
69
70
post-patch-OPTIMIZED_JS-off:
71
	@${REINPLACE_CMD} -e 's|--disable-tests|& --disable-optimize|' \
72
		${WRKSRC}/libjs.make
73
75
do-install:
74
do-install:
76
	(cd ${RELEASEDIR} && ${COPYTREE_SHARE} "${PORTDATA}" ${STAGEDIR}${DATADIR})
75
	(cd ${RELEASEDIR} && ${COPYTREE_SHARE} "${PORTDATA}" ${STAGEDIR}${DATADIR})
77
	${INSTALL_SCRIPT} ${WRKDIR}/oolite ${STAGEDIR}${PREFIX}/bin
76
	${INSTALL_SCRIPT} ${WRKDIR}/oolite ${STAGEDIR}${PREFIX}/bin
Lines 82-85 Link Here
82
		${STAGEDIR}${PREFIX}/share/pixmaps
81
		${STAGEDIR}${PREFIX}/share/pixmaps
83
	(cd ${WRKSRC}/Doc && ${COPYTREE_SHARE} "${PORTDOCS}" ${STAGEDIR}${DOCSDIR})
82
	(cd ${WRKSRC}/Doc && ${COPYTREE_SHARE} "${PORTDOCS}" ${STAGEDIR}${DOCSDIR})
84
83
85
.include <bsd.port.post.mk>
84
.include <bsd.port.mk>
(-)distinfo (-3 / +3 lines)
Lines 1-3 Link Here
1
TIMESTAMP = 1468900340
1
TIMESTAMP = 1508936871
2
SHA256 (oolite/oolite-source-1.84.tar.bz2) = 2ea317dde0615969d1704ee19c8df1d52bee1c87762ebd1e466b5d34f3161e2c
2
SHA256 (oolite/oolite-source-1.86.tar.bz2) = 9f99c72f433fbbad972abdac5104775b29994d73c0b35f05130b31522b70ec9a
3
SIZE (oolite/oolite-source-1.84.tar.bz2) = 139707159
3
SIZE (oolite/oolite-source-1.86.tar.bz2) = 144561828
(-)files/patch-deps_mozilla-bug771281 (-1382 lines)
Lines 84-1471 Link Here
84
 #ifdef JSDEBUGGER
84
 #ifdef JSDEBUGGER
85
     if (jsdc) {
85
     if (jsdc) {
86
 #ifdef JSDEBUGGER_C_UI
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 00:00:00 UTC
89
+++ deps/mozilla/js/src/shell/jsworkers.cpp.rej
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 08:54:39 UTC
1374
+++ deps/mozilla/js/src/shell/jsworkers.h
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
87
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 08:54:39 UTC
88
--- deps.orig/mozilla/js/src/tests/browser.js	2014-06-30 08:54:39 UTC
1471
+++ deps/mozilla/js/src/tests/browser.js
89
+++ deps/mozilla/js/src/tests/browser.js
(-)files/patch-deps_mozilla_js_src_assembler_jit_ExecutableAllocator.h (+14 lines)
Line 0 Link Here
1
--- deps/mozilla/js/src/assembler/jit/ExecutableAllocator.h.orig	2014-05-17 17:57:43 UTC
2
+++ deps/mozilla/js/src/assembler/jit/ExecutableAllocator.h
3
@@ -391,6 +391,11 @@ public:
4
     {
5
         CacheRangeFlush(code, size, CACHE_SYNC_ALL);
6
     }
7
+#elif WTF_CPU_ARM_TRADITIONAL && WTF_PLATFORM_FREEBSD
8
+    static void cacheFlush(void* code, size_t size)
9
+    {
10
+	__clear_cache(code, reinterpret_cast<char*>(code) + size);
11
+    }
12
 #else
13
     #error "The cacheFlush support is missing on this platform."
14
 #endif
(-)files/patch-deps_mozilla_js_src_assembler_wtf_Platform.h (+18 lines)
Line 0 Link Here
1
--- deps/mozilla/js/src/assembler/wtf/Platform.h.orig	2014-05-17 17:57:43 UTC
2
+++ deps/mozilla/js/src/assembler/wtf/Platform.h
3
@@ -213,6 +213,7 @@
4
 #elif defined(__ARM_ARCH_6__) \
5
    || defined(__ARM_ARCH_6J__) \
6
    || defined(__ARM_ARCH_6K__) \
7
+   || defined(__ARM_ARCH_6KZ__) \
8
    || defined(__ARM_ARCH_6Z__) \
9
    || defined(__ARM_ARCH_6ZK__) \
10
    || defined(__ARM_ARCH_6T2__) \
11
@@ -243,6 +244,7 @@
12
 
13
 #elif defined(__ARM_ARCH_6J__) \
14
    || defined(__ARM_ARCH_6K__) \
15
+   || defined(__ARM_ARCH_6KZ__) \
16
    || defined(__ARM_ARCH_6Z__) \
17
    || defined(__ARM_ARCH_6ZK__) \
18
    || defined(__ARM_ARCH_6M__)
(-)files/patch-deps_mozilla_js_src_configure (-2 / +35 lines)
Lines 1-6 Link Here
1
--- deps/mozilla/js/src/configure.orig	2014-06-30 08:54:39 UTC
1
--- deps/mozilla/js/src/configure.orig	2014-05-17 17:57:43 UTC
2
+++ deps/mozilla/js/src/configure
2
+++ deps/mozilla/js/src/configure
3
@@ -9547,7 +9547,8 @@
3
@@ -9547,7 +9547,8 @@ fi
4
 
4
 
5
 echo "$ac_t""$ac_cv_have_visibility_builtin_bug" 1>&6
5
 echo "$ac_t""$ac_cv_have_visibility_builtin_bug" 1>&6
6
         if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \
6
         if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \
Lines 10-12 Link Here
10
           VISIBILITY_FLAGS='-I$(DIST)/system_wrappers_js -include $(topsrcdir)/config/gcc_hidden.h'
10
           VISIBILITY_FLAGS='-I$(DIST)/system_wrappers_js -include $(topsrcdir)/config/gcc_hidden.h'
11
           WRAP_SYSTEM_INCLUDES=1
11
           WRAP_SYSTEM_INCLUDES=1
12
           STL_FLAGS='-I$(DIST)/stl_wrappers'
12
           STL_FLAGS='-I$(DIST)/stl_wrappers'
13
@@ -13364,6 +13365,9 @@ fi
14
 # Individual module options
15
 
16
 case "$target_cpu" in
17
+  armv6*)
18
+    MOZ_ARM_ARCH=armv6
19
+  ;;
20
   arm*)
21
     MOZ_ARM_ARCH=armv7
22
   ;;
23
@@ -13438,6 +13442,13 @@ EOF
24
   esac
25
 else
26
   case "$target_cpu" in
27
+    armv6*)
28
+      if test "$GNU_CC"; then
29
+        CFLAGS="$CFLAGS"
30
+        CXXFLAGS="$CXXFLAGS"
31
+        ASFLAGS="$ASFLAGS"
32
+      fi
33
+      ;;
34
     arm*)
35
       if test "$GNU_CC"; then
36
         CFLAGS="$CFLAGS -march=armv5te -mthumb-interwork -msoft-float"
37
@@ -13517,7 +13528,7 @@ rm -f conftest*
38
 fi
39
 
40
 if test -z "$MOZ_OPTIMIZE_FLAGS"; then
41
-	MOZ_OPTIMIZE_FLAGS="-O"
42
+	MOZ_OPTIMIZE_FLAGS="-O2"
43
 fi
44
 
45
 # Check whether --enable-optimize or --disable-optimize was given.
(-)files/patch-deps_mozilla_js_src_configure.in (-2 / +35 lines)
Lines 1-6 Link Here
1
--- deps/mozilla/js/src/configure.in.orig	2014-06-30 08:54:39 UTC
1
--- deps/mozilla/js/src/configure.in.orig	2014-05-17 17:57:43 UTC
2
+++ deps/mozilla/js/src/configure.in
2
+++ deps/mozilla/js/src/configure.in
3
@@ -3378,7 +3378,8 @@
3
@@ -3378,7 +3378,8 @@ EOF
4
                        rm -f conftest.{c,S}
4
                        rm -f conftest.{c,S}
5
                        ])
5
                        ])
6
         if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \
6
         if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \
Lines 10-12 Link Here
10
           VISIBILITY_FLAGS='-I$(DIST)/system_wrappers_js -include $(topsrcdir)/config/gcc_hidden.h'
10
           VISIBILITY_FLAGS='-I$(DIST)/system_wrappers_js -include $(topsrcdir)/config/gcc_hidden.h'
11
           WRAP_SYSTEM_INCLUDES=1
11
           WRAP_SYSTEM_INCLUDES=1
12
           STL_FLAGS='-I$(DIST)/stl_wrappers'
12
           STL_FLAGS='-I$(DIST)/stl_wrappers'
13
@@ -4656,6 +4657,9 @@ MOZ_ARG_HEADER(Individual module options
14
 
15
 dnl Setup default CPU arch for arm target
16
 case "$target_cpu" in
17
+  armv6*)
18
+    MOZ_ARM_ARCH=armv6
19
+  ;;
20
   arm*)
21
     MOZ_ARM_ARCH=armv7
22
   ;;
23
@@ -4716,6 +4720,13 @@ elif test "$MOZ_ARM_ARCH" = "armv7"; the
24
   esac
25
 else
26
   case "$target_cpu" in
27
+    armv6*)
28
+      if test "$GNU_CC"; then
29
+        CFLAGS="$CFLAGS"
30
+        CXXFLAGS="$CXXFLAGS"
31
+        ASFLAGS="$ASFLAGS"
32
+      fi
33
+      ;;
34
     arm*)
35
       if test "$GNU_CC"; then
36
         CFLAGS="$CFLAGS -march=armv5te -mthumb-interwork -msoft-float"
37
@@ -4788,7 +4799,7 @@ dnl ====================================
38
 dnl = Enable code optimization. ON by default.
39
 dnl ========================================================
40
 if test -z "$MOZ_OPTIMIZE_FLAGS"; then
41
-	MOZ_OPTIMIZE_FLAGS="-O"
42
+	MOZ_OPTIMIZE_FLAGS="-O2"
43
 fi
44
 
45
 MOZ_ARG_ENABLE_STRING(optimize,
(-)files/patch-deps_mozilla_js_src_nanojit_CodeAlloc.cpp (+10 lines)
Line 0 Link Here
1
--- deps/mozilla/js/src/nanojit/CodeAlloc.cpp.orig	2014-05-17 17:57:43 UTC
2
+++ deps/mozilla/js/src/nanojit/CodeAlloc.cpp
3
@@ -261,7 +261,6 @@ namespace nanojit
4
 #endif
5
 
6
 #if defined(AVMPLUS_UNIX) && defined(NANOJIT_ARM)
7
-#include <asm/unistd.h>
8
 extern "C" void __clear_cache(char *BEG, char *END);
9
 #endif
10
 
(-)files/patch-deps_mozilla_js_src_nanojit_njcpudetect.h (+11 lines)
Line 0 Link Here
1
--- deps/mozilla/js/src/nanojit/njcpudetect.h.orig	2014-05-17 17:57:43 UTC
2
+++ deps/mozilla/js/src/nanojit/njcpudetect.h
3
@@ -77,6 +77,8 @@
4
 #elif   defined(__ARM_ARCH_6__) || \
5
         defined(__ARM_ARCH_6J__) || \
6
         defined(__ARM_ARCH_6T2__) || \
7
+        defined(__ARM_ARCH_6K__) || \
8
+        defined(__ARM_ARCH_6KZ__) || \
9
         defined(__ARM_ARCH_6Z__) || \
10
         defined(__ARM_ARCH_6ZK__) || \
11
         defined(__ARM_ARCH_6M__) || \

Return to bug 223389