Bug 1260910 - introduce 'wait' and 'wake'. r=bbouvier
authorLars T Hansen <lhansen@mozilla.com>
Sat, 02 Apr 2016 09:17:20 -0700
changeset 291448 63bdfecc99f4
parent 291447 859f435f2ca0
child 291449 fd3ca174abe0
push id74572
push userlhansen@mozilla.com
push dateSun, 03 Apr 2016 13:49:04 +0000
treeherdermozilla-inbound@fd3ca174abe0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1260910
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1260910 - introduce 'wait' and 'wake'. r=bbouvier
js/src/builtin/AtomicsObject.cpp
js/src/builtin/AtomicsObject.h
js/src/jit-test/tests/atomics/basic-tests.js
js/src/tests/shell/futex-apis.js
js/src/tests/shell/futex.js
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -743,17 +743,17 @@ class AutoUnlockFutexAPI
     ~AutoUnlockFutexAPI() {
         FutexRuntime::lock();
     }
 };
 
 } // namespace js
 
 bool
-js::atomics_futexWait(JSContext* cx, unsigned argc, Value* vp)
+js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     HandleValue objv = args.get(0);
     HandleValue idxv = args.get(1);
     HandleValue valv = args.get(2);
     HandleValue timeoutv = args.get(3);
     MutableHandleValue r = args.rval();
 
@@ -821,17 +821,17 @@ js::atomics_futexWait(JSContext* cx, uns
         w.back->lower_pri = w.lower_pri;
         if (sarb->waiters() == &w)
             sarb->setWaiters(w.lower_pri);
     }
     return retval;
 }
 
 bool
-js::atomics_futexWake(JSContext* cx, unsigned argc, Value* vp)
+js::atomics_wake(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     HandleValue objv = args.get(0);
     HandleValue idxv = args.get(1);
     HandleValue countv = args.get(2);
     MutableHandleValue r = args.rval();
 
     Rooted<TypedArrayObject*> view(cx, nullptr);
@@ -1025,20 +1025,20 @@ js::FutexRuntime::wait(JSContext* cx, do
             // The interrupt handler may reenter the engine.  In that case
             // there are two complications:
             //
             // - The waiting thread is not actually waiting on the
             //   condition variable so we have to record that it
             //   should be woken when the interrupt handler returns.
             //   To that end, we flag the thread as interrupted around
             //   the interrupt and check state_ when the interrupt
-            //   handler returns.  A futexWake() call that reaches the
+            //   handler returns.  A wake() call that reaches the
             //   runtime during the interrupt sets state_ to Woken.
             //
-            // - It is in principle possible for futexWait() to be
+            // - It is in principle possible for wait() to be
             //   reentered on the same thread/runtime and waiting on the
             //   same location and to yet again be interrupted and enter
             //   the interrupt handler.  In this case, it is important
             //   that when another agent wakes waiters, all waiters using
             //   the same runtime on the same location are woken in LIFO
             //   order; FIFO may be the required order, but FIFO would
             //   fail to wake up the innermost call.  Interrupts are
             //   outside any spec anyway.  Also, several such suspended
@@ -1104,18 +1104,20 @@ const JSFunctionSpec AtomicsMethods[] = 
     JS_INLINABLE_FN("store",              atomics_store,              3,0, AtomicsStore),
     JS_INLINABLE_FN("exchange",           atomics_exchange,           3,0, AtomicsExchange),
     JS_INLINABLE_FN("add",                atomics_add,                3,0, AtomicsAdd),
     JS_INLINABLE_FN("sub",                atomics_sub,                3,0, AtomicsSub),
     JS_INLINABLE_FN("and",                atomics_and,                3,0, AtomicsAnd),
     JS_INLINABLE_FN("or",                 atomics_or,                 3,0, AtomicsOr),
     JS_INLINABLE_FN("xor",                atomics_xor,                3,0, AtomicsXor),
     JS_INLINABLE_FN("isLockFree",         atomics_isLockFree,         1,0, AtomicsIsLockFree),
-    JS_FN("futexWait",                    atomics_futexWait,          4,0),
-    JS_FN("futexWake",                    atomics_futexWake,          3,0),
+    JS_FN("wait",                         atomics_wait,               4,0),
+    JS_FN("futexWait",                    atomics_wait,               4,0),
+    JS_FN("wake",                         atomics_wake,               3,0),
+    JS_FN("futexWake",                    atomics_wake,               3,0),
     JS_FS_END
 };
 
 static const JSConstDoubleSpec AtomicsConstants[] = {
     {"OK",       AtomicsObject::FutexOK},
     {"TIMEDOUT", AtomicsObject::FutexTimedout},
     {"NOTEQUAL", AtomicsObject::FutexNotequal},
     {0,          0}
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -14,19 +14,17 @@ namespace js {
 
 class AtomicsObject : public JSObject
 {
   public:
     static const Class class_;
     static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
     static bool toString(JSContext* cx, unsigned int argc, Value* vp);
 
-    // Defined return values for futexWait.
-    // The error values must be negative because APIs such as futexWaitOrRequeue
-    // return a value that is either the number of tasks woken or an error code.
+    // Result codes for Atomics.wait().
     enum FutexWaitResult : int32_t {
         FutexOK = 0,
         FutexNotequal = -1,
         FutexTimedout = -2
     };
 };
 
 bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
@@ -34,18 +32,18 @@ bool atomics_exchange(JSContext* cx, uns
 bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
 bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
-bool atomics_futexWait(JSContext* cx, unsigned argc, Value* vp);
-bool atomics_futexWake(JSContext* cx, unsigned argc, Value* vp);
+bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
+bool atomics_wake(JSContext* cx, unsigned argc, Value* vp);
 
 /* asm.js callouts */
 int32_t atomics_add_asm_callout(int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_sub_asm_callout(int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_and_asm_callout(int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_or_asm_callout(int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_xor_asm_callout(int32_t vt, int32_t offset, int32_t value);
 int32_t atomics_cmpxchg_asm_callout(int32_t vt, int32_t offset, int32_t oldval, int32_t newval);
@@ -74,40 +72,40 @@ public:
     //
     // The futex lock must be held around this call.
     //
     // The timeout is the number of milliseconds, with fractional
     // times allowed; specify positive infinity for an indefinite wait.
     //
     // wait() will not wake up spuriously.  It will return true and
     // set *result to a return code appropriate for
-    // Atomics.futexWait() on success, and return false on error.
+    // Atomics.wait() on success, and return false on error.
     bool wait(JSContext* cx, double timeout, AtomicsObject::FutexWaitResult* result);
 
     // Wake the thread represented by this Runtime.
     //
     // The futex lock must be held around this call.  (The sleeping
-    // thread will not wake up until the caller of futexWake()
+    // thread will not wake up until the caller of Atomics.wake()
     // releases the lock.)
     //
     // If the thread is not waiting then this method does nothing.
     //
-    // If the thread is waiting in a call to futexWait() and the
-    // reason is WakeExplicit then the futexWait() call will return
+    // If the thread is waiting in a call to wait() and the
+    // reason is WakeExplicit then the wait() call will return
     // with Woken.
     //
-    // If the thread is waiting in a call to futexWait() and the
-    // reason is WakeForJSInterrupt then the futexWait() will return
+    // If the thread is waiting in a call to wait() and the
+    // reason is WakeForJSInterrupt then the wait() will return
     // with WaitingNotifiedForInterrupt; in the latter case the caller
-    // of futexWait() must handle the interrupt.
+    // of wait() must handle the interrupt.
     void wake(WakeReason reason);
 
     bool isWaiting();
 
-    // If canWait() returns false (the default) then futexWait is disabled
+    // If canWait() returns false (the default) then wait() is disabled
     // on the runtime to which the FutexRuntime belongs.
     bool canWait() {
         return canWait_;
     }
 
     void setCanWait(bool flag) {
         canWait_ = flag;
     }
--- a/js/src/jit-test/tests/atomics/basic-tests.js
+++ b/js/src/jit-test/tests/atomics/basic-tests.js
@@ -1,14 +1,14 @@
 // Basic functional tests for the Atomics primitives.
 //
 // These do not test atomicity, just that calling and coercions and
 // indexing and exception behavior all work right.
 //
-// These do not test the futex operations.
+// These do not test the wait/wake operations.
 
 load(libdir + "asserts.js");
 
 var DEBUG = false;		// Set to true for useful printouts
 
 function dprint(...xs) {
     if (!DEBUG)
 	return;
--- a/js/src/tests/shell/futex-apis.js
+++ b/js/src/tests/shell/futex-apis.js
@@ -5,17 +5,17 @@
  * http://creativecommons.org/licenses/publicdomain/
  */
 
 if (!(this.SharedArrayBuffer && this.Atomics)) {
     reportCompare(true,true);
     quit(0);
 }
 
-// Checks for parameter validation of futex API.  ALl of these test
+// Checks for parameter validation of wait/wake API.  All of these test
 // cases should throw exceptions during parameter validation, before
 // we check whether any waiting should be done.
 
 let ab = new ArrayBuffer(16);
 let sab = new SharedArrayBuffer(16);
 
 //////////////////////////////////////////////////////////////////////
 //
@@ -52,45 +52,45 @@ let sab = new SharedArrayBuffer(16);
 		  Object,
 		  Int32Array,
 		  Date,
 		  Math,
 		  Atomics ];
 
     for ( let i=0 ; i < values.length ; i++ ) {
 	let view = values[i];
-	assertThrowsInstanceOf(() => Atomics.futexWait(view, 0, 0), TypeError);
-	assertThrowsInstanceOf(() => Atomics.futexWake(view, 0), TypeError);
+	assertThrowsInstanceOf(() => Atomics.wait(view, 0, 0), TypeError);
+	assertThrowsInstanceOf(() => Atomics.wake(view, 0), TypeError);
     }
 }
 
 // Check against TypedArray on non-shared memory cases.
 
 {
     let views = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array];
 
     for ( let View of views ) {
 	let view = new View(ab);
 
-	assertThrowsInstanceOf(() => Atomics.futexWait(view, 0, 0), TypeError);
-	assertThrowsInstanceOf(() => Atomics.futexWake(view, 0), TypeError);
+	assertThrowsInstanceOf(() => Atomics.wait(view, 0, 0), TypeError);
+	assertThrowsInstanceOf(() => Atomics.wake(view, 0), TypeError);
     }
 }
 
 // Check against TypedArray on shared memory, but wrong view type
 
 {
     let views = [Int8Array, Uint8Array, Int16Array, Uint16Array, Uint32Array,
 		 Uint8ClampedArray, Float32Array, Float64Array];
 
     for ( let View of views ) {
 	let view = new View(sab);
 
-	assertThrowsInstanceOf(() => Atomics.futexWait(view, 0, 0), TypeError);
-	assertThrowsInstanceOf(() => Atomics.futexWake(view, 0), TypeError);
+	assertThrowsInstanceOf(() => Atomics.wait(view, 0, 0), TypeError);
+	assertThrowsInstanceOf(() => Atomics.wake(view, 0), TypeError);
     }
 }
 
 //////////////////////////////////////////////////////////////////////
 //
 // The indices must be in the range of the array
 
 {
@@ -100,14 +100,14 @@ let sab = new SharedArrayBuffer(16);
 		    (view) => view.length,
 		    (view) => view.length*2,
 		    (view) => undefined,
 		    (view) => '3.5',
 		    (view) => { password: "qumquat" } ];
 
     for ( let iidx=0 ; iidx < indices.length ; iidx++ ) {
 	let Idx = indices[iidx](view);
-	assertThrowsInstanceOf(() => Atomics.futexWait(view, Idx, 10), RangeError);
-	assertThrowsInstanceOf(() => Atomics.futexWake(view, Idx), RangeError);
+	assertThrowsInstanceOf(() => Atomics.wait(view, Idx, 10), RangeError);
+	assertThrowsInstanceOf(() => Atomics.wake(view, Idx), RangeError);
     }
 }
 
 reportCompare(true,true);
--- a/js/src/tests/shell/futex.js
+++ b/js/src/tests/shell/futex.js
@@ -12,17 +12,17 @@ if (!(this.SharedArrayBuffer && this.get
 
 var DEBUG = false;
 
 function dprint(s) {
     if (DEBUG) print(s);
 }
 
 // Tests the SharedArrayBuffer mailbox in the shell.
-// Tests the futex functionality in the shell.
+// Tests the wait/wake functionality in the shell.
 
 var sab = new SharedArrayBuffer(12);
 var mem = new Int32Array(sab);
 
 // SharedArrayBuffer mailbox tests
 
 assertEq(getSharedArrayBuffer(), null); // Mbx starts empty
 
@@ -85,56 +85,56 @@ function dprint(s) {
 }
 assertEq(mem[0], 42);		// what was written in the main thread
 assertEq(mem[1], 37);		//   is read in the worker
 mem[1] = 1337;
 dprint("Sleeping for 2 seconds");
 sleep(2);
 dprint("Waking the main thread now");
 setSharedArrayBuffer(null);
-assertEq(Atomics.futexWake(mem, 0, 1), 1); // Can fail spuriously but very unlikely
+assertEq(Atomics.wake(mem, 0, 1), 1); // Can fail spuriously but very unlikely
 `);
 
 var then = Date.now();
-assertEq(Atomics.futexWait(mem, 0, 42), Atomics.OK);
+assertEq(Atomics.wait(mem, 0, 42), Atomics.OK);
 dprint("Woke up as I should have in " + (Date.now() - then)/1000 + "s");
 assertEq(mem[1], 1337); // what was written in the worker is read in the main thread
 assertEq(getSharedArrayBuffer(), null); // The worker's clearing of the mbx is visible
 
 ////////////////////////////////////////////////////////////
 
-// Test the default argument to futexWake()
+// Test the default argument to atomics.wake()
 
 setSharedArrayBuffer(mem.buffer);
 
 evalInWorker(`
 var mem = new Int32Array(getSharedArrayBuffer());
 sleep(2);				// Probably long enough to avoid a spurious error next
-assertEq(Atomics.futexWake(mem, 0), 1);	// Last argument to futexWake should default to +Infinity
+assertEq(Atomics.wake(mem, 0), 1);	// Last argument to wake should default to +Infinity
 `);
 
 var then = Date.now();
 dprint("Main thread waiting on wakeup (2s)");
-assertEq(Atomics.futexWait(mem, 0, 42), Atomics.OK);
+assertEq(Atomics.wait(mem, 0, 42), Atomics.OK);
 dprint("Woke up as I should have in " + (Date.now() - then)/1000 + "s");
 
 ////////////////////////////////////////////////////////////
 
 // A tricky case: while in the wait there will be an interrupt, and in
-// the interrupt handler we will execute a futexWait.  This is
+// the interrupt handler we will execute a wait.  This is
 // explicitly prohibited (for now), so there should be a catchable exception.
 
 timeout(2, function () {
     dprint("In the interrupt, starting inner wait with timeout 2s");
-    Atomics.futexWait(mem, 0, 42); // Should throw and propagate all the way out
+    Atomics.wait(mem, 0, 42); // Should throw and propagate all the way out
 });
 var exn = false;
 try {
     dprint("Starting outer wait");
-    assertEq(Atomics.futexWait(mem, 0, 42, 5000), Atomics.OK);
+    assertEq(Atomics.wait(mem, 0, 42, 5000), Atomics.OK);
 }
 catch (e) {
     dprint("Got the timeout exception!");
     exn = true;
 }
 finally {
     timeout(-1);
 }
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -647,17 +647,17 @@ JSRuntime::requestInterrupt(InterruptMod
     interrupt_ = true;
     jitStackLimit_ = UINTPTR_MAX;
 
     if (mode == JSRuntime::RequestInterruptUrgent) {
         // If this interrupt is urgent (slow script dialog and garbage
         // collection among others), take additional steps to
         // interrupt corner cases where the above fields are not
         // regularly polled.  Wake both ilooping JIT code and
-        // futexWait.
+        // Atomics.wait().
         fx.lock();
         if (fx.isWaiting())
             fx.wake(FutexRuntime::WakeForJSInterrupt);
         fx.unlock();
         InterruptRunningJitCode(this);
     }
 }
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -956,17 +956,17 @@ struct JSRuntime : public JS::shadow::Ru
     const JSLocaleCallbacks* localeCallbacks;
 
     /* Default locale for Internationalization API */
     char* defaultLocale;
 
     /* Default JSVersion. */
     JSVersion defaultVersion_;
 
-    /* Futex state, used by futexWait and futexWake on the Atomics object */
+    /* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics object */
     js::FutexRuntime fx;
 
   private:
     /* See comment for JS_AbortIfWrongThread in jsapi.h. */
     void* ownerThread_;
     size_t ownerThreadNative_;
     friend bool js::CurrentThreadCanAccessRuntime(JSRuntime* rt);
   public: