mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 05:38:39 +00:00
234 lines
7.9 KiB
C++
234 lines
7.9 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef vm_SharedArrayObject_h
|
|
#define vm_SharedArrayObject_h
|
|
|
|
#include "mozilla/Atomics.h"
|
|
|
|
#include "jsapi.h"
|
|
#include "jsobj.h"
|
|
#include "jstypes.h"
|
|
|
|
#include "gc/Barrier.h"
|
|
#include "vm/ArrayBufferObject.h"
|
|
|
|
typedef struct JSProperty JSProperty;
|
|
|
|
namespace js {
|
|
|
|
class FutexWaiter;
|
|
|
|
/*
|
|
* SharedArrayRawBuffer
|
|
*
|
|
* A bookkeeping object always stored immediately before the raw buffer.
|
|
* The buffer itself is mmap()'d and refcounted.
|
|
* SharedArrayBufferObjects and AsmJS code may hold references.
|
|
*
|
|
* |<------ sizeof ------>|<- length ->|
|
|
*
|
|
* | waste | SharedArrayRawBuffer | data array | waste |
|
|
*
|
|
* Observe that if we want to map the data array on a specific address, such
|
|
* as absolute zero (bug 1056027), then the SharedArrayRawBuffer cannot be
|
|
* prefixed to the data array, it has to be a separate object, also in
|
|
* shared memory. (That would get rid of ~4KB of waste, as well.) Very little
|
|
* 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_;
|
|
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> length;
|
|
uint32_t maxLength;
|
|
bool growable;
|
|
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, uint32_t maxLength, bool growable,
|
|
bool preparedForAsmJS)
|
|
: refcount_(1),
|
|
length(length),
|
|
maxLength(maxLength),
|
|
growable(growable),
|
|
preparedForAsmJS(preparedForAsmJS),
|
|
waiters_(nullptr)
|
|
{
|
|
MOZ_ASSERT(buffer == dataPointerShared());
|
|
}
|
|
|
|
public:
|
|
static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length, uint32_t maxLength,
|
|
bool growable);
|
|
static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length) {
|
|
return New(cx, length, length, false);
|
|
}
|
|
|
|
// 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
|
|
// care of mutual exclusion.
|
|
void setWaiters(FutexWaiter* waiters) {
|
|
waiters_ = waiters;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
uint32_t maxByteLength() const {
|
|
return growable ? maxLength : byteLength();
|
|
}
|
|
|
|
uint32_t allocatedByteLength() const {
|
|
return growable ? maxLength : byteLength();
|
|
}
|
|
|
|
bool isGrowable() const {
|
|
return growable;
|
|
}
|
|
|
|
[[nodiscard]] bool growTo(uint32_t newLength);
|
|
|
|
bool isPreparedForAsmJS() const {
|
|
return preparedForAsmJS;
|
|
}
|
|
|
|
uint32_t refcount() const { return refcount_; }
|
|
|
|
MOZ_MUST_USE bool addReference();
|
|
void dropReference();
|
|
};
|
|
|
|
/*
|
|
* SharedArrayBufferObject
|
|
*
|
|
* When transferred to a WebWorker, the buffer is not detached on the
|
|
* parent side, and both child and parent reference the same buffer.
|
|
*
|
|
* The underlying memory is memory-mapped and reference counted
|
|
* (across workers and/or processes). The SharedArrayBuffer object
|
|
* has a finalizer that decrements the refcount, the last one to leave
|
|
* (globally) unmaps the memory. The sender ups the refcount before
|
|
* transmitting the memory to another worker.
|
|
*
|
|
* SharedArrayBufferObject (or really the underlying memory) /is
|
|
* racy/: more than one worker can access the memory at the same time.
|
|
*
|
|
* A TypedArrayObject (a view) references a SharedArrayBuffer
|
|
* and keeps it alive. The SharedArrayBuffer does /not/ reference its
|
|
* views.
|
|
*/
|
|
class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared
|
|
{
|
|
static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
|
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
|
|
static bool growableGetterImpl(JSContext* cx, const CallArgs& args);
|
|
static bool fun_grow_impl(JSContext* cx, const CallArgs& args);
|
|
|
|
public:
|
|
// RAWBUF_SLOT holds a pointer (as "private" data) to the
|
|
// SharedArrayRawBuffer object, which is manually managed storage.
|
|
static const uint8_t RAWBUF_SLOT = 0;
|
|
|
|
static const uint8_t RESERVED_SLOTS = 1;
|
|
|
|
static const Class class_;
|
|
|
|
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool growableGetter(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool fun_grow(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
static bool class_constructor(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
// Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
|
|
static SharedArrayBufferObject* New(JSContext* cx,
|
|
uint32_t length,
|
|
uint32_t maxLength,
|
|
bool growable,
|
|
HandleObject proto = nullptr);
|
|
static SharedArrayBufferObject* New(JSContext* cx,
|
|
uint32_t length,
|
|
HandleObject proto = nullptr) {
|
|
return New(cx, length, length, false, proto);
|
|
}
|
|
|
|
// Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
|
|
static SharedArrayBufferObject* New(JSContext* cx,
|
|
SharedArrayRawBuffer* buffer,
|
|
HandleObject proto = nullptr);
|
|
|
|
static void Finalize(FreeOp* fop, JSObject* obj);
|
|
|
|
static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
|
|
JS::ClassInfo* info);
|
|
|
|
static void copyData(Handle<SharedArrayBufferObject*> toBuffer, uint32_t toIndex,
|
|
Handle<SharedArrayBufferObject*> fromBuffer, uint32_t fromIndex,
|
|
uint32_t count);
|
|
|
|
SharedArrayRawBuffer* rawBufferObject() const;
|
|
|
|
// Invariant: This method does not cause GC and can be called
|
|
// without anchoring the object it is called on.
|
|
uintptr_t globalID() const {
|
|
// The buffer address is good enough as an ID provided the memory is not shared
|
|
// between processes or, if it is, it is mapped to the same address in every
|
|
// process. (At the moment, shared memory cannot be shared between processes.)
|
|
return dataPointerShared().asValue();
|
|
}
|
|
|
|
uint32_t byteLength() const {
|
|
return rawBufferObject()->byteLength();
|
|
}
|
|
uint32_t maxByteLength() const {
|
|
return rawBufferObject()->maxByteLength();
|
|
}
|
|
bool isGrowable() const {
|
|
return rawBufferObject()->isGrowable();
|
|
}
|
|
[[nodiscard]] bool growTo(uint32_t newLength) {
|
|
return rawBufferObject()->growTo(newLength);
|
|
}
|
|
bool isPreparedForAsmJS() const {
|
|
return rawBufferObject()->isPreparedForAsmJS();
|
|
}
|
|
|
|
SharedMem<uint8_t*> dataPointerShared() const {
|
|
return rawBufferObject()->dataPointerShared();
|
|
}
|
|
|
|
private:
|
|
void acceptRawBuffer(SharedArrayRawBuffer* buffer);
|
|
void dropRawBuffer();
|
|
};
|
|
|
|
bool IsSharedArrayBuffer(HandleValue v);
|
|
bool IsSharedArrayBuffer(HandleObject o);
|
|
bool IsSharedArrayBuffer(JSObject* o);
|
|
|
|
SharedArrayBufferObject& AsSharedArrayBuffer(HandleObject o);
|
|
|
|
} // namespace js
|
|
|
|
#endif // vm_SharedArrayObject_h
|