blob: 5bfc1ef3cc0b576d2c8726ae4c8a57ac238f32a1 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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;
uint32_t length;
// A list of structures representing tasks waiting on some
// location within this buffer.
FutexWaiter* waiters_;
protected:
SharedArrayRawBuffer(uint8_t* buffer, uint32_t length)
: refcount(1),
length(length),
waiters_(nullptr)
{
MOZ_ASSERT(buffer == dataPointerShared());
}
public:
static SharedArrayRawBuffer* New(JSContext* cx, 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
// 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;
}
void addReference();
void dropReference();
};
/*
* SharedArrayBufferObject
*
* When transferred to a WebWorker, the buffer is not neutered 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);
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 const Class protoClass;
static const JSFunctionSpec jsfuncs[];
static const JSFunctionSpec jsstaticfuncs[];
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
static bool fun_isView(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);
// Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
static SharedArrayBufferObject* New(JSContext* cx, SharedArrayRawBuffer* buffer);
static void Finalize(FreeOp* fop, JSObject* obj);
static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf,
JS::ClassInfo* info);
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();
}
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