1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 2 * vim: set ts=8 sts=4 et sw=4 tw=99: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_SharedArrayObject_h 8 #define vm_SharedArrayObject_h 9 10 #include "mozilla/Atomics.h" 11 12 #include "jsapi.h" 13 #include "jsobj.h" 14 #include "jstypes.h" 15 16 #include "gc/Barrier.h" 17 #include "vm/ArrayBufferObject.h" 18 19 typedef struct JSProperty JSProperty; 20 21 namespace js { 22 23 class FutexWaiter; 24 25 /* 26 * SharedArrayRawBuffer 27 * 28 * A bookkeeping object always stored immediately before the raw buffer. 29 * The buffer itself is mmap()'d and refcounted. 30 * SharedArrayBufferObjects and AsmJS code may hold references. 31 * 32 * |<------ sizeof ------>|<- length ->| 33 * 34 * | waste | SharedArrayRawBuffer | data array | waste | 35 * 36 * Observe that if we want to map the data array on a specific address, such 37 * as absolute zero (bug 1056027), then the SharedArrayRawBuffer cannot be 38 * prefixed to the data array, it has to be a separate object, also in 39 * shared memory. (That would get rid of ~4KB of waste, as well.) Very little 40 * else would have to change throughout the engine, the SARB would point to 41 * the data array using a constant pointer, instead of computing its 42 * address. 43 */ 44 class SharedArrayRawBuffer 45 { 46 private: 47 mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount_; 48 uint32_t length; 49 bool preparedForAsmJS; 50 51 // A list of structures representing tasks waiting on some 52 // location within this buffer. 53 FutexWaiter* waiters_; 54 55 protected: 56 SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, bool preparedForAsmJS) 57 : refcount_(1), 58 length(length), 59 preparedForAsmJS(preparedForAsmJS), 60 waiters_(nullptr) 61 { 62 MOZ_ASSERT(buffer == dataPointerShared()); 63 } 64 65 public: 66 static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length); 67 68 // This may be called from multiple threads. The caller must take 69 // care of mutual exclusion. 70 FutexWaiter* waiters() const { 71 return waiters_; 72 } 73 74 // This may be called from multiple threads. The caller must take 75 // care of mutual exclusion. 76 void setWaiters(FutexWaiter* waiters) { 77 waiters_ = waiters; 78 } 79 80 SharedMem<uint8_t*> dataPointerShared() const { 81 uint8_t* ptr = reinterpret_cast<uint8_t*>(const_cast<SharedArrayRawBuffer*>(this)); 82 return SharedMem<uint8_t*>::shared(ptr + sizeof(SharedArrayRawBuffer)); 83 } 84 85 uint32_t byteLength() const { 86 return length; 87 } 88 89 bool isPreparedForAsmJS() const { 90 return preparedForAsmJS; 91 } 92 93 uint32_t refcount() const { return refcount_; } 94 95 void addReference(); 96 void dropReference(); 97 }; 98 99 /* 100 * SharedArrayBufferObject 101 * 102 * When transferred to a WebWorker, the buffer is not detached on the 103 * parent side, and both child and parent reference the same buffer. 104 * 105 * The underlying memory is memory-mapped and reference counted 106 * (across workers and/or processes). The SharedArrayBuffer object 107 * has a finalizer that decrements the refcount, the last one to leave 108 * (globally) unmaps the memory. The sender ups the refcount before 109 * transmitting the memory to another worker. 110 * 111 * SharedArrayBufferObject (or really the underlying memory) /is 112 * racy/: more than one worker can access the memory at the same time. 113 * 114 * A TypedArrayObject (a view) references a SharedArrayBuffer 115 * and keeps it alive. The SharedArrayBuffer does /not/ reference its 116 * views. 117 */ 118 class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared 119 { 120 static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args); 121 122 public: 123 // RAWBUF_SLOT holds a pointer (as "private" data) to the 124 // SharedArrayRawBuffer object, which is manually managed storage. 125 static const uint8_t RAWBUF_SLOT = 0; 126 127 static const uint8_t RESERVED_SLOTS = 1; 128 129 static const Class class_; 130 131 static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp); 132 133 static bool class_constructor(JSContext* cx, unsigned argc, Value* vp); 134 135 // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer. 136 static SharedArrayBufferObject* New(JSContext* cx, 137 uint32_t length, 138 HandleObject proto = nullptr); 139 140 // Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer. 141 static SharedArrayBufferObject* New(JSContext* cx, 142 SharedArrayRawBuffer* buffer, 143 HandleObject proto = nullptr); 144 145 static void Finalize(FreeOp* fop, JSObject* obj); 146 147 static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf, 148 JS::ClassInfo* info); 149 150 static void copyData(Handle<SharedArrayBufferObject*> toBuffer, 151 Handle<SharedArrayBufferObject*> fromBuffer, 152 uint32_t fromIndex, uint32_t count); 153 154 SharedArrayRawBuffer* rawBufferObject() const; 155 156 // Invariant: This method does not cause GC and can be called 157 // without anchoring the object it is called on. 158 uintptr_t globalID() const { 159 // The buffer address is good enough as an ID provided the memory is not shared 160 // between processes or, if it is, it is mapped to the same address in every 161 // process. (At the moment, shared memory cannot be shared between processes.) 162 return dataPointerShared().asValue(); 163 } 164 165 uint32_t byteLength() const { 166 return rawBufferObject()->byteLength(); 167 } 168 bool isPreparedForAsmJS() const { 169 return rawBufferObject()->isPreparedForAsmJS(); 170 } 171 172 SharedMem<uint8_t*> dataPointerShared() const { 173 return rawBufferObject()->dataPointerShared(); 174 } 175 176 private: 177 void acceptRawBuffer(SharedArrayRawBuffer* buffer); 178 void dropRawBuffer(); 179 }; 180 181 bool IsSharedArrayBuffer(HandleValue v); 182 bool IsSharedArrayBuffer(HandleObject o); 183 bool IsSharedArrayBuffer(JSObject* o); 184 185 SharedArrayBufferObject& AsSharedArrayBuffer(HandleObject o); 186 187 } // namespace js 188 189 #endif // vm_SharedArrayObject_h 190