Bug 1260910 - introduce 'wait' and 'wake'. r=bbouvier
authorLars T Hansen <lhansen@mozilla.com>
Sat, 02 Apr 2016 09:17:20 -0700
changeset 291511 63bdfecc99f488142d1601f381f6241fd22ddb92
parent 291510 859f435f2ca001acc659cf47a2068fc94287e84a
child 291512 fd3ca174abe074fbde07dd3fb7efe1d5f5da477a
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1260910
milestone48.0a1
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: