Bug 1389464 - Preparatory cleanup. r=luke
authorLars T Hansen <lhansen@mozilla.com>
Fri, 01 Sep 2017 14:03:36 +0200
changeset 437638 c8d3f0749e42b0f3891cd4d404f41f9640c7d2e5
parent 437637 38ba9478def1e3cf66f1971465c32cfc18850221
child 437639 d704d1e5b453f463329317dd36a3b3ad5b41ade0
push id117
push userfmarier@mozilla.com
push dateTue, 28 Nov 2017 20:17:16 +0000
reviewersluke
bugs1389464
milestone59.0a1
Bug 1389464 - Preparatory cleanup. r=luke
js/src/jit-test/lib/wasm.js
js/src/vm/ArrayBufferObject.cpp
js/src/vm/SharedArrayObject.cpp
js/src/vm/SharedArrayObject.h
js/src/wasm/WasmCode.h
js/src/wasm/WasmValidate.h
--- a/js/src/jit-test/lib/wasm.js
+++ b/js/src/jit-test/lib/wasm.js
@@ -1,13 +1,29 @@
 if (!wasmIsSupported())
     quit();
 
 load(libdir + "asserts.js");
 
+function hasWasmAtomics() {
+    try {
+	// Typically the parser will be in sync with the rest of wasm and
+	// parsing will throw if shared memory is not supported.
+        let bin = wasmTextToBinary(`(module (memory 1 1 shared)
+				     (func (result i32)
+				      (i32.atomic.load (i32.const 0)))
+				     (export "" 0))`);
+
+	// If parsing doesn't throw, let's check that the validator agrees.
+        return WebAssembly.validate(bin);
+    } catch (e) {
+        return false;
+    }
+}
+
 function wasmEvalText(str, imports) {
     let binary = wasmTextToBinary(str);
     let valid = WebAssembly.validate(binary);
 
     let m;
     try {
         m = new WebAssembly.Module(binary);
         assertEq(valid, true);
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -584,17 +584,17 @@ ArrayBufferObject::changeContents(JSCont
  *
  *  - length - the wasm-visible current length of the buffer. Accesses in the
  *    range [0, length] succeed. May only increase.
  *
  *  - boundsCheckLimit - when !WASM_HUGE_MEMORY, the size against which we
  *    perform bounds checks. It is always a constant offset smaller than
  *    mappedSize. Currently that constant offset is 64k (wasm::GuardSize).
  *
- *  - max - the optional declared limit on how much length can grow.
+ *  - maxSize - the optional declared limit on how much length can grow.
  *
  *  - mappedSize - the actual mmaped size. Access in the range
  *    [0, mappedSize] will either succeed, or be handled by the wasm signal
  *    handlers.
  *
  * The below diagram shows the layout of the wasm heap. The wasm-visible
  * portion of the heap starts at 0. There is one extra page prior to the
  * start of the wasm heap which contains the WasmArrayRawBuffer struct at
@@ -633,20 +633,19 @@ ArrayBufferObject::changeContents(JSCont
  * signal handlers to catch things that slip by bounds checks. Logically it has
  * two parts:
  *
  *  - from length to boundsCheckLimit - this part of the SLOP serves to catch
  *  accesses to memory we have reserved but not yet grown into. This allows us
  *  to grow memory up to max (when present) without having to patch/update the
  *  bounds checks.
  *
- *  - from boundsCheckLimit to mappedSize - (Note: In current patch 0) - this
- *  part of the SLOP allows us to bounds check against base pointers and fold
- *  some constant offsets inside loads. This enables better Bounds
- *  Check Elimination.
+ *  - from boundsCheckLimit to mappedSize - this part of the SLOP allows us to
+ *  bounds check against base pointers and fold some constant offsets inside
+ *  loads. This enables better Bounds Check Elimination.
  *
  */
 
 class js::WasmArrayRawBuffer
 {
     Maybe<uint32_t> maxSize_;
     size_t mappedSize_;
 
@@ -718,17 +717,17 @@ class js::WasmArrayRawBuffer
 
         if (!ExtendBufferMapping(dataPointer(), mappedSize_, newMappedSize))
             return false;
 
         mappedSize_ = newMappedSize;
         return true;
     }
 
-    // Try and grow the mapped region of memory. Does not changes current size.
+    // Try and grow the mapped region of memory. Does not change current size.
     // Does not move memory if no space to grow.
     void tryGrowMaxSizeInPlace(uint32_t deltaMaxSize) {
         CheckedInt<uint32_t> newMaxSize = maxSize_.value();
         newMaxSize += deltaMaxSize;
         MOZ_ASSERT(newMaxSize.isValid());
         MOZ_ASSERT(newMaxSize.value() % wasm::PageSize == 0);
 
         if (!extendMappedSize(newMaxSize.value()))
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -40,17 +40,17 @@ SharedArrayMappedSize(uint32_t allocSize
 
 static uint32_t
 SharedArrayAllocSize(uint32_t length)
 {
     return AlignBytes(length + gc::SystemPageSize(), gc::SystemPageSize());
 }
 
 SharedArrayRawBuffer*
-SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
+SharedArrayRawBuffer::New(uint32_t length)
 {
     // The value (uint32_t)-1 is used as a signal in various places,
     // so guard against it on principle.
     MOZ_ASSERT(length != (uint32_t)-1);
 
     // Add a page for the header and round to a page boundary.
     uint32_t allocSize = SharedArrayAllocSize(length);
     if (allocSize <= length)
@@ -64,56 +64,56 @@ SharedArrayRawBuffer::New(JSContext* cx,
     else
         p = MapBufferMemory(allocSize, allocSize);
     if (!p)
         return nullptr;
 
     uint8_t* buffer = reinterpret_cast<uint8_t*>(p) + gc::SystemPageSize();
     uint8_t* base = buffer - sizeof(SharedArrayRawBuffer);
     SharedArrayRawBuffer* rawbuf = new (base) SharedArrayRawBuffer(buffer, length, preparedForAsmJS);
-    MOZ_ASSERT(rawbuf->length == length); // Deallocation needs this
+    MOZ_ASSERT(rawbuf->length_ == length); // Deallocation needs this
     return rawbuf;
 }
 
 bool
 SharedArrayRawBuffer::addReference()
 {
-    MOZ_RELEASE_ASSERT(this->refcount_ > 0);
+    MOZ_RELEASE_ASSERT(refcount_ > 0);
 
     // Be careful never to overflow the refcount field.
     for (;;) {
-        uint32_t old_refcount = this->refcount_;
-        uint32_t new_refcount = old_refcount+1;
+        uint32_t old_refcount = refcount_;
+        uint32_t new_refcount = old_refcount + 1;
         if (new_refcount == 0)
             return false;
-        if (this->refcount_.compareExchange(old_refcount, new_refcount))
+        if (refcount_.compareExchange(old_refcount, new_refcount))
             return true;
     }
 }
 
 void
 SharedArrayRawBuffer::dropReference()
 {
     // Normally if the refcount is zero then the memory will have been unmapped
     // and this test may just crash, but if the memory has been retained for any
     // reason we will catch the underflow here.
-    MOZ_RELEASE_ASSERT(this->refcount_ > 0);
+    MOZ_RELEASE_ASSERT(refcount_ > 0);
 
     // Drop the reference to the buffer.
-    uint32_t refcount = --this->refcount_; // Atomic.
-    if (refcount)
+    uint32_t new_refcount = --refcount_; // Atomic.
+    if (new_refcount)
         return;
 
     // If this was the final reference, release the buffer.
-    SharedMem<uint8_t*> p = this->dataPointerShared() - gc::SystemPageSize();
+    SharedMem<uint8_t*> p = dataPointerShared() - gc::SystemPageSize();
     MOZ_ASSERT(p.asValue() % gc::SystemPageSize() == 0);
 
     uint8_t* address = p.unwrap(/*safe - only reference*/);
-    uint32_t allocSize = SharedArrayAllocSize(this->length);
-    if (this->preparedForAsmJS)
+    uint32_t allocSize = SharedArrayAllocSize(length_);
+    if (preparedForAsmJS_)
         UnmapBufferMemory(address, SharedArrayMappedSize(allocSize));
     else
         UnmapBufferMemory(address, allocSize);
 }
 
 
 MOZ_ALWAYS_INLINE bool
 SharedArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
@@ -165,21 +165,27 @@ SharedArrayBufferObject::class_construct
         return false;
     args.rval().setObject(*bufobj);
     return true;
 }
 
 SharedArrayBufferObject*
 SharedArrayBufferObject::New(JSContext* cx, uint32_t length, HandleObject proto)
 {
-    SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length);
+    SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(length);
     if (!buffer)
         return nullptr;
 
-    return New(cx, buffer, proto);
+    SharedArrayBufferObject* obj = New(cx, buffer, proto);
+    if (!obj) {
+        buffer->dropReference();
+        return nullptr;
+    }
+
+    return obj;
 }
 
 SharedArrayBufferObject*
 SharedArrayBufferObject::New(JSContext* cx, SharedArrayRawBuffer* buffer, HandleObject proto)
 {
     MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
 
     AutoSetNewObjectMetadata metadata(cx);
--- a/js/src/vm/SharedArrayObject.h
+++ b/js/src/vm/SharedArrayObject.h
@@ -40,35 +40,35 @@ class FutexWaiter;
  * else would have to change throughout the engine, the SARB would point to
  * the data array using a constant pointer, instead of computing its
  * address.
  */
 class SharedArrayRawBuffer
 {
   private:
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount_;
-    uint32_t length;
-    bool preparedForAsmJS;
+    uint32_t length_;
+    bool preparedForAsmJS_;
 
     // A list of structures representing tasks waiting on some
     // location within this buffer.
     FutexWaiter* waiters_;
 
   protected:
     SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, bool preparedForAsmJS)
       : refcount_(1),
-        length(length),
-        preparedForAsmJS(preparedForAsmJS),
+        length_(length),
+        preparedForAsmJS_(preparedForAsmJS),
         waiters_(nullptr)
     {
         MOZ_ASSERT(buffer == dataPointerShared());
     }
 
   public:
-    static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length);
+    static SharedArrayRawBuffer* New(uint32_t length);
 
     // This may be called from multiple threads.  The caller must take
     // care of mutual exclusion.
     FutexWaiter* waiters() const {
         return waiters_;
     }
 
     // This may be called from multiple threads.  The caller must take
@@ -78,21 +78,21 @@ class SharedArrayRawBuffer
     }
 
     SharedMem<uint8_t*> dataPointerShared() const {
         uint8_t* ptr = reinterpret_cast<uint8_t*>(const_cast<SharedArrayRawBuffer*>(this));
         return SharedMem<uint8_t*>::shared(ptr + sizeof(SharedArrayRawBuffer));
     }
 
     uint32_t byteLength() const {
-        return length;
+        return length_;
     }
 
     bool isPreparedForAsmJS() const {
-        return preparedForAsmJS;
+        return preparedForAsmJS_;
     }
 
     uint32_t refcount() const { return refcount_; }
 
     MOZ_MUST_USE bool addReference();
     void dropReference();
 
     static int32_t liveBuffers();
@@ -182,11 +182,15 @@ private:
 };
 
 bool IsSharedArrayBuffer(HandleValue v);
 bool IsSharedArrayBuffer(HandleObject o);
 bool IsSharedArrayBuffer(JSObject* o);
 
 SharedArrayBufferObject& AsSharedArrayBuffer(HandleObject o);
 
+typedef Rooted<SharedArrayBufferObject*> RootedSharedArrayBufferObject;
+typedef Handle<SharedArrayBufferObject*> HandleSharedArrayBufferObject;
+typedef MutableHandle<SharedArrayBufferObject*> MutableHandleSharedArrayBufferObject;
+
 } // namespace js
 
 #endif // vm_SharedArrayObject_h
--- a/js/src/wasm/WasmCode.h
+++ b/js/src/wasm/WasmCode.h
@@ -268,22 +268,16 @@ typedef Vector<FuncImport, 0, SystemAllo
 
 enum class MemoryUsage
 {
     None = false,
     Unshared = 1,
     Shared = 2
 };
 
-static inline bool
-UsesMemory(MemoryUsage memoryUsage)
-{
-    return bool(memoryUsage);
-}
-
 // NameInBytecode represents a name that is embedded in the wasm bytecode.
 // The presence of NameInBytecode implies that bytecode has been kept.
 
 struct NameInBytecode
 {
     uint32_t offset;
     uint32_t length;
 
@@ -413,18 +407,18 @@ class Metadata : public ShareableBase<Me
     CacheableChars        filename;
 
     // Debug-enabled code is not serialized.
     bool                  debugEnabled;
     FuncArgTypesVector    debugFuncArgTypes;
     FuncReturnTypesVector debugFuncReturnTypes;
     ModuleHash            debugHash;
 
-    bool usesMemory() const { return UsesMemory(memoryUsage); }
-    bool hasSharedMemory() const { return memoryUsage == MemoryUsage::Shared; }
+    bool usesMemory() const { return memoryUsage != MemoryUsage::None; }
+    bool usesSharedMemory() const { return memoryUsage == MemoryUsage::Shared; }
 
     // AsmJSMetadata derives Metadata iff isAsmJS(). Mostly this distinction is
     // encapsulated within AsmJS.cpp, but the additional virtual functions allow
     // asm.js to override wasm behavior in the handful of cases that can't be
     // easily encapsulated by AsmJS.cpp.
 
     bool isAsmJS() const {
         return kind == ModuleKind::AsmJS;
--- a/js/src/wasm/WasmValidate.h
+++ b/js/src/wasm/WasmValidate.h
@@ -106,17 +106,20 @@ struct ModuleEnvironment
     }
     size_t numFuncImports() const {
         return funcImportGlobalDataOffsets.length();
     }
     size_t numFuncDefs() const {
         return funcSigs.length() - funcImportGlobalDataOffsets.length();
     }
     bool usesMemory() const {
-        return UsesMemory(memoryUsage);
+        return memoryUsage != MemoryUsage::None;
+    }
+    bool usesSharedMemory() const {
+        return memoryUsage == MemoryUsage::Shared;
     }
     bool isAsmJS() const {
         return kind == ModuleKind::AsmJS;
     }
     bool debugEnabled() const {
         return debug == DebugEnabled::True;
     }
     bool funcIsImport(uint32_t funcIndex) const {