Line data Source code
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 0 : SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, bool preparedForAsmJS)
57 0 : : refcount_(1),
58 : length(length),
59 : preparedForAsmJS(preparedForAsmJS),
60 0 : waiters_(nullptr)
61 : {
62 0 : MOZ_ASSERT(buffer == dataPointerShared());
63 0 : }
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 0 : FutexWaiter* waiters() const {
71 0 : return waiters_;
72 : }
73 :
74 : // This may be called from multiple threads. The caller must take
75 : // care of mutual exclusion.
76 0 : void setWaiters(FutexWaiter* waiters) {
77 0 : waiters_ = waiters;
78 0 : }
79 :
80 0 : SharedMem<uint8_t*> dataPointerShared() const {
81 0 : uint8_t* ptr = reinterpret_cast<uint8_t*>(const_cast<SharedArrayRawBuffer*>(this));
82 0 : return SharedMem<uint8_t*>::shared(ptr + sizeof(SharedArrayRawBuffer));
83 : }
84 :
85 0 : uint32_t byteLength() const {
86 0 : return length;
87 : }
88 :
89 0 : bool isPreparedForAsmJS() const {
90 0 : return preparedForAsmJS;
91 : }
92 :
93 0 : uint32_t refcount() const { return refcount_; }
94 :
95 : MOZ_MUST_USE bool addReference();
96 : void dropReference();
97 :
98 : static int32_t liveBuffers();
99 : };
100 :
101 : /*
102 : * SharedArrayBufferObject
103 : *
104 : * When transferred to a WebWorker, the buffer is not detached on the
105 : * parent side, and both child and parent reference the same buffer.
106 : *
107 : * The underlying memory is memory-mapped and reference counted
108 : * (across workers and/or processes). The SharedArrayBuffer object
109 : * has a finalizer that decrements the refcount, the last one to leave
110 : * (globally) unmaps the memory. The sender ups the refcount before
111 : * transmitting the memory to another worker.
112 : *
113 : * SharedArrayBufferObject (or really the underlying memory) /is
114 : * racy/: more than one worker can access the memory at the same time.
115 : *
116 : * A TypedArrayObject (a view) references a SharedArrayBuffer
117 : * and keeps it alive. The SharedArrayBuffer does /not/ reference its
118 : * views.
119 : */
120 : class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
121 : {
122 : static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
123 :
124 : public:
125 : // RAWBUF_SLOT holds a pointer (as "private" data) to the
126 : // SharedArrayRawBuffer object, which is manually managed storage.
127 : static const uint8_t RAWBUF_SLOT = 0;
128 :
129 : static const uint8_t RESERVED_SLOTS = 1;
130 :
131 : static const Class class_;
132 : static const Class protoClass_;
133 :
134 : static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
135 :
136 : static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
137 :
138 : // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
139 : static SharedArrayBufferObject* New(JSContext* cx,
140 : uint32_t length,
141 : HandleObject proto = nullptr);
142 :
143 : // Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
144 : static SharedArrayBufferObject* New(JSContext* cx,
145 : SharedArrayRawBuffer* buffer,
146 : HandleObject proto = nullptr);
147 :
148 : static void Finalize(FreeOp* fop, JSObject* obj);
149 :
150 : static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
151 : JS::ClassInfo* info);
152 :
153 : static void copyData(Handle<SharedArrayBufferObject*> toBuffer, uint32_t toIndex,
154 : Handle<SharedArrayBufferObject*> fromBuffer, uint32_t fromIndex,
155 : uint32_t count);
156 :
157 : SharedArrayRawBuffer* rawBufferObject() const;
158 :
159 : // Invariant: This method does not cause GC and can be called
160 : // without anchoring the object it is called on.
161 0 : uintptr_t globalID() const {
162 : // The buffer address is good enough as an ID provided the memory is not shared
163 : // between processes or, if it is, it is mapped to the same address in every
164 : // process. (At the moment, shared memory cannot be shared between processes.)
165 0 : return dataPointerShared().asValue();
166 : }
167 :
168 0 : uint32_t byteLength() const {
169 0 : return rawBufferObject()->byteLength();
170 : }
171 0 : bool isPreparedForAsmJS() const {
172 0 : return rawBufferObject()->isPreparedForAsmJS();
173 : }
174 :
175 0 : SharedMem<uint8_t*> dataPointerShared() const {
176 0 : return rawBufferObject()->dataPointerShared();
177 : }
178 :
179 : private:
180 : void acceptRawBuffer(SharedArrayRawBuffer* buffer);
181 : void dropRawBuffer();
182 : };
183 :
184 : bool IsSharedArrayBuffer(HandleValue v);
185 : bool IsSharedArrayBuffer(HandleObject o);
186 : bool IsSharedArrayBuffer(JSObject* o);
187 :
188 : SharedArrayBufferObject& AsSharedArrayBuffer(HandleObject o);
189 :
190 : } // namespace js
191 :
192 : #endif // vm_SharedArrayObject_h
|