зеркало из https://github.com/mozilla/gecko-dev.git
Bug 933001 - Part 1/5 - Define SharedArrayBufferObject. r=sfink
This commit is contained in:
Родитель
7cb1860267
Коммит
ceed1869bc
|
@ -432,6 +432,7 @@ DeclMarkerImpl(JitCode, jit::JitCode)
|
|||
DeclMarkerImpl(Object, ArgumentsObject)
|
||||
DeclMarkerImpl(Object, ArrayBufferObject)
|
||||
DeclMarkerImpl(Object, ArrayBufferViewObject)
|
||||
DeclMarkerImpl(Object, SharedArrayBufferObject)
|
||||
DeclMarkerImpl(Object, DebugScopeObject)
|
||||
DeclMarkerImpl(Object, GlobalObject)
|
||||
DeclMarkerImpl(Object, JSObject)
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace js {
|
|||
class ArgumentsObject;
|
||||
class ArrayBufferObject;
|
||||
class ArrayBufferViewObject;
|
||||
class SharedArrayBufferObject;
|
||||
class BaseShape;
|
||||
class DebugScopeObject;
|
||||
struct GCMarker;
|
||||
|
@ -97,6 +98,7 @@ DeclMarker(JitCode, jit::JitCode)
|
|||
DeclMarker(Object, ArgumentsObject)
|
||||
DeclMarker(Object, ArrayBufferObject)
|
||||
DeclMarker(Object, ArrayBufferViewObject)
|
||||
DeclMarker(Object, SharedArrayBufferObject)
|
||||
DeclMarker(Object, DebugScopeObject)
|
||||
DeclMarker(Object, GlobalObject)
|
||||
DeclMarker(Object, JSObject)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "vm/ObjectImpl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -91,7 +92,29 @@ IsValidAsmJSHeapLength(uint32_t length);
|
|||
// byteLength portion of which is accessible) so that out-of-bounds accesses
|
||||
// (made using a uint32 index) are guaranteed to raise a SIGSEGV.
|
||||
static const size_t AsmJSBufferProtectedSize = 4 * 1024ULL * 1024ULL * 1024ULL;
|
||||
#endif
|
||||
|
||||
// To avoid dynamically checking bounds on each load/store, asm.js code relies
|
||||
// on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works
|
||||
// if we can guarantee that *any* out-of-bounds access generates a fault. This
|
||||
// isn't generally true since an out-of-bounds access could land on other
|
||||
// Mozilla data. To overcome this on x64, we reserve an entire 4GB space,
|
||||
// making only the range [0, byteLength) accessible, and use a 32-bit unsigned
|
||||
// index into this space. (x86 and ARM require different tricks.)
|
||||
//
|
||||
// One complication is that we need to put an ObjectElements struct immediately
|
||||
// before the data array (as required by the general JSObject data structure).
|
||||
// Thus, we must stick a page before the elements to hold ObjectElements.
|
||||
//
|
||||
// |<------------------------------ 4GB + 1 pages --------------------->|
|
||||
// |<--- sizeof --->|<------------------- 4GB ----------------->|
|
||||
//
|
||||
// | waste | ObjectElements | data array | inaccessible reserved memory |
|
||||
// ^ ^ ^
|
||||
// | \ /
|
||||
// obj->elements required to be page boundaries
|
||||
//
|
||||
static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
|
||||
#endif // JS_CODEGEN_X64
|
||||
|
||||
#ifdef JS_ION
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
#include "vm/RegExpStatics.h"
|
||||
#include "vm/Runtime.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/StopIterationObject.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace js {
|
|||
class ArgumentsObject;
|
||||
class ArrayBufferObject;
|
||||
class ArrayBufferViewObject;
|
||||
class SharedArrayBufferObject;
|
||||
class BaseShape;
|
||||
class DebugScopeObject;
|
||||
class GCHelperThread;
|
||||
|
@ -132,6 +133,7 @@ template <> struct MapTypeToTraceKind<JSFunction> { static const JSGCTrace
|
|||
template <> struct MapTypeToTraceKind<ArgumentsObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
|
||||
template <> struct MapTypeToTraceKind<ArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
|
||||
template <> struct MapTypeToTraceKind<ArrayBufferViewObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
|
||||
template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
|
||||
template <> struct MapTypeToTraceKind<DebugScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
|
||||
template <> struct MapTypeToTraceKind<GlobalObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
|
||||
template <> struct MapTypeToTraceKind<ScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "vm/ArrayObject.h"
|
||||
#include "vm/BooleanObject.h"
|
||||
#include "vm/NumberObject.h"
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/StringObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
||||
|
@ -305,6 +306,9 @@ GetClassForProtoKey(JSProtoKey key)
|
|||
case JSProto_ArrayBuffer:
|
||||
return &ArrayBufferObject::class_;
|
||||
|
||||
case JSProto_SharedArrayBuffer:
|
||||
return &SharedArrayBufferObject::class_;
|
||||
|
||||
case JSProto_DataView:
|
||||
return &DataViewObject::class_;
|
||||
|
||||
|
|
|
@ -1034,7 +1034,8 @@ ObjectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx)
|
|||
case ESClass_String: return obj->is<StringObject>();
|
||||
case ESClass_Boolean: return obj->is<BooleanObject>();
|
||||
case ESClass_RegExp: return obj->is<RegExpObject>();
|
||||
case ESClass_ArrayBuffer: return obj->is<ArrayBufferObject>();
|
||||
case ESClass_ArrayBuffer:
|
||||
return obj->is<ArrayBufferObject>() || obj->is<SharedArrayBufferObject>();
|
||||
case ESClass_Date: return obj->is<DateObject>();
|
||||
}
|
||||
MOZ_ASSUME_UNREACHABLE("bad classValue");
|
||||
|
|
|
@ -91,10 +91,11 @@
|
|||
real(Map, 33, js_InitMapClass, OCLASP(Map)) \
|
||||
real(Set, 34, js_InitSetClass, OCLASP(Set)) \
|
||||
real(DataView, 35, js_InitTypedArrayClasses, OCLASP(DataView)) \
|
||||
IF_INTL(real,imaginary) (Intl, 36, js_InitIntlClass, CLASP(Intl)) \
|
||||
IF_BDATA(real,imaginary)(TypedObject, 37, js_InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \
|
||||
imaginary(GeneratorFunction, 38, js_InitIteratorClasses, dummy) \
|
||||
IF_BDATA(real,imaginary)(SIMD, 39, js_InitSIMDClass, OCLASP(SIMD)) \
|
||||
real(SharedArrayBuffer, 36, js_InitSharedArrayBufferClass, &js::SharedArrayBufferObject::protoClass) \
|
||||
IF_INTL(real,imaginary) (Intl, 37, js_InitIntlClass, CLASP(Intl)) \
|
||||
IF_BDATA(real,imaginary)(TypedObject, 38, js_InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \
|
||||
imaginary(GeneratorFunction, 39, js_InitIteratorClasses, dummy) \
|
||||
IF_BDATA(real,imaginary)(SIMD, 40, js_InitSIMDClass, OCLASP(SIMD)) \
|
||||
|
||||
#define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)
|
||||
|
||||
|
|
|
@ -181,6 +181,7 @@ UNIFIED_SOURCES += [
|
|||
'vm/ScopeObject.cpp',
|
||||
'vm/SelfHosting.cpp',
|
||||
'vm/Shape.cpp',
|
||||
'vm/SharedArrayObject.cpp',
|
||||
'vm/SPSProfiler.cpp',
|
||||
'vm/Stack.cpp',
|
||||
'vm/String.cpp',
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
|
@ -171,6 +172,44 @@ const JSFunctionSpec ArrayBufferObject::jsstaticfuncs[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
bool
|
||||
js::IsArrayBuffer(HandleValue v)
|
||||
{
|
||||
return v.isObject() &&
|
||||
(v.toObject().is<ArrayBufferObject>() ||
|
||||
v.toObject().is<SharedArrayBufferObject>());
|
||||
}
|
||||
|
||||
bool
|
||||
js::IsArrayBuffer(HandleObject obj)
|
||||
{
|
||||
return obj->is<ArrayBufferObject>() || obj->is<SharedArrayBufferObject>();
|
||||
}
|
||||
|
||||
bool
|
||||
js::IsArrayBuffer(JSObject *obj)
|
||||
{
|
||||
return obj->is<ArrayBufferObject>() || obj->is<SharedArrayBufferObject>();
|
||||
}
|
||||
|
||||
ArrayBufferObject &
|
||||
js::AsArrayBuffer(HandleObject obj)
|
||||
{
|
||||
JS_ASSERT(IsArrayBuffer(obj));
|
||||
if (obj->is<SharedArrayBufferObject>())
|
||||
return obj->as<SharedArrayBufferObject>();
|
||||
return obj->as<ArrayBufferObject>();
|
||||
}
|
||||
|
||||
ArrayBufferObject &
|
||||
js::AsArrayBuffer(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(IsArrayBuffer(obj));
|
||||
if (obj->is<SharedArrayBufferObject>())
|
||||
return obj->as<SharedArrayBufferObject>();
|
||||
return obj->as<ArrayBufferObject>();
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
|
@ -383,10 +422,18 @@ ArrayBufferObject::neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer)
|
|||
return true;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
ArrayBufferObject::dataPointer() const {
|
||||
if (isSharedArrayBuffer())
|
||||
return (uint8_t *)this->as<SharedArrayBufferObject>().dataPointer();
|
||||
return (uint8_t *)elements;
|
||||
}
|
||||
|
||||
void
|
||||
ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
|
||||
{
|
||||
JS_ASSERT(!isAsmJSArrayBuffer());
|
||||
JS_ASSERT(!isSharedArrayBuffer());
|
||||
|
||||
// Grab out data before invalidating it.
|
||||
uint32_t byteLengthCopy = byteLength();
|
||||
|
@ -438,6 +485,8 @@ ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
|
|||
void
|
||||
ArrayBufferObject::neuter(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(!isSharedArrayBuffer());
|
||||
|
||||
JS_ASSERT(cx);
|
||||
if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
|
||||
ObjectElements *oldHeader = getElementsHeader();
|
||||
|
@ -456,6 +505,7 @@ ArrayBufferObject::neuter(JSContext *cx)
|
|||
/* static */ bool
|
||||
ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
|
||||
{
|
||||
JS_ASSERT(!buffer->isSharedArrayBuffer());
|
||||
if (buffer->hasDynamicElements())
|
||||
return true;
|
||||
|
||||
|
@ -470,31 +520,13 @@ ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buf
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(JS_ION) && defined(JS_CPU_X64)
|
||||
// To avoid dynamically checking bounds on each load/store, asm.js code relies
|
||||
// on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works
|
||||
// if we can guarantee that *any* out-of-bounds access generates a fault. This
|
||||
// isn't generally true since an out-of-bounds access could land on other
|
||||
// Mozilla data. To overcome this on x64, we reserve an entire 4GB space,
|
||||
// making only the range [0, byteLength) accessible, and use a 32-bit unsigned
|
||||
// index into this space. (x86 and ARM require different tricks.)
|
||||
//
|
||||
// One complication is that we need to put an ObjectElements struct immediately
|
||||
// before the data array (as required by the general JSObject data structure).
|
||||
// Thus, we must stick a page before the elements to hold ObjectElements.
|
||||
//
|
||||
// |<------------------------------ 4GB + 1 pages --------------------->|
|
||||
// |<--- sizeof --->|<------------------- 4GB ----------------->|
|
||||
//
|
||||
// | waste | ObjectElements | data array | inaccessible reserved memory |
|
||||
// ^ ^ ^
|
||||
// | \ /
|
||||
// obj->elements required to be page boundaries
|
||||
//
|
||||
#if defined(JS_CPU_X64)
|
||||
// Refer to comment above AsmJSMappedSize in AsmJS.h.
|
||||
JS_STATIC_ASSERT(sizeof(ObjectElements) < AsmJSPageSize);
|
||||
JS_STATIC_ASSERT(AsmJSAllocationGranularity == AsmJSPageSize);
|
||||
static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
|
||||
#endif
|
||||
|
||||
#if defined(JS_ION) && defined(JS_CPU_X64)
|
||||
bool
|
||||
ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
|
||||
{
|
||||
|
@ -659,14 +691,15 @@ ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, bool clear /* = true *
|
|||
JSRuntime *rt = obj->runtimeFromMainThread();
|
||||
rt->gcNursery.notifyNewElements(obj, header);
|
||||
#endif
|
||||
obj->initElementsHeader(obj->getElementsHeader(), nbytes);
|
||||
} else {
|
||||
// Elements header must be initialized before dataPointer() is callable.
|
||||
obj->setFixedElements();
|
||||
obj->initElementsHeader(obj->getElementsHeader(), nbytes);
|
||||
if (clear)
|
||||
memset(obj->dataPointer(), 0, nbytes);
|
||||
}
|
||||
|
||||
obj->initElementsHeader(obj->getElementsHeader(), nbytes);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -791,7 +824,7 @@ ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
|
|||
// multiple views are collected into a linked list during collection, and
|
||||
// then swept to prune out their dead views.
|
||||
|
||||
ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
|
||||
ArrayBufferObject &buffer = AsArrayBuffer(obj);
|
||||
ArrayBufferViewObject *viewsHead = GetViewList(&buffer);
|
||||
if (!viewsHead)
|
||||
return;
|
||||
|
@ -826,7 +859,7 @@ ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
|
|||
JS_ASSERT(obj->compartment() == firstView->compartment());
|
||||
ArrayBufferObject **bufList = &obj->compartment()->gcLiveArrayBuffers;
|
||||
firstView->setBufferLink(*bufList);
|
||||
*bufList = &obj->as<ArrayBufferObject>();
|
||||
*bufList = &AsArrayBuffer(obj);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
bool found = false;
|
||||
|
@ -1208,7 +1241,7 @@ ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
|
|||
/* Update obj's data slot if the array buffer moved. Note that during
|
||||
* initialization, bufSlot may still be JSVAL_VOID. */
|
||||
if (bufSlot.isObject()) {
|
||||
ArrayBufferObject &buf = bufSlot.toObject().as<ArrayBufferObject>();
|
||||
ArrayBufferObject &buf = AsArrayBuffer(&bufSlot.toObject());
|
||||
if (buf.getElementsHeader()->isNeuteredBuffer()) {
|
||||
// When a view is neutered, it is set to NULL
|
||||
JS_ASSERT(obj->getPrivate() == nullptr);
|
||||
|
@ -1257,7 +1290,7 @@ JS_FRIEND_API(uint32_t)
|
|||
JS_GetArrayBufferByteLength(JSObject *obj)
|
||||
{
|
||||
obj = CheckedUnwrap(obj);
|
||||
return obj ? obj->as<ArrayBufferObject>().byteLength() : 0;
|
||||
return obj ? AsArrayBuffer(obj).byteLength() : 0;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
|
@ -1266,7 +1299,7 @@ JS_GetArrayBufferData(JSObject *obj)
|
|||
obj = CheckedUnwrap(obj);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
return obj->as<ArrayBufferObject>().dataPointer();
|
||||
return AsArrayBuffer(obj).dataPointer();
|
||||
}
|
||||
|
||||
JS_FRIEND_API(uint8_t *)
|
||||
|
@ -1276,7 +1309,7 @@ JS_GetStableArrayBufferData(JSContext *cx, JSObject *obj)
|
|||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(obj));
|
||||
if (!ArrayBufferObject::ensureNonInline(cx, buffer))
|
||||
return nullptr;
|
||||
|
||||
|
@ -1430,11 +1463,11 @@ JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
|
|||
{
|
||||
if (!(obj = CheckedUnwrap(obj)))
|
||||
return nullptr;
|
||||
if (!obj->is<ArrayBufferObject>())
|
||||
if (!IsArrayBuffer(obj))
|
||||
return nullptr;
|
||||
|
||||
*length = obj->as<ArrayBufferObject>().byteLength();
|
||||
*data = obj->as<ArrayBufferObject>().dataPointer();
|
||||
*length = AsArrayBuffer(obj).byteLength();
|
||||
*data = AsArrayBuffer(obj).dataPointer();
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ class ArrayBufferViewObject;
|
|||
//
|
||||
// - JSObject
|
||||
// - ArrayBufferObject
|
||||
// - SharedArrayBufferObject
|
||||
// - ArrayBufferViewObject
|
||||
// - DataViewObject
|
||||
// - TypedArrayObject (declared in vm/TypedArrayObject.h)
|
||||
|
@ -185,9 +186,7 @@ class ArrayBufferObject : public JSObject
|
|||
*/
|
||||
static bool neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer);
|
||||
|
||||
inline uint8_t * dataPointer() const {
|
||||
return (uint8_t *) elements;
|
||||
}
|
||||
uint8_t * dataPointer() const;
|
||||
|
||||
/*
|
||||
* Discard the ArrayBuffer contents. For asm.js buffers, at least, should
|
||||
|
@ -203,6 +202,10 @@ class ArrayBufferObject : public JSObject
|
|||
return getClass() == &class_;
|
||||
}
|
||||
|
||||
bool isSharedArrayBuffer() const {
|
||||
return getElementsHeader()->isSharedArrayBuffer();
|
||||
}
|
||||
|
||||
bool isAsmJSArrayBuffer() const {
|
||||
return getElementsHeader()->isAsmJSArrayBuffer();
|
||||
}
|
||||
|
@ -292,11 +295,15 @@ InitArrayBufferViewDataPointer(ArrayBufferViewObject *obj, ArrayBufferObject *bu
|
|||
PostBarrierTypedArrayObject(obj);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
IsArrayBuffer(HandleValue v)
|
||||
{
|
||||
return v.isObject() && v.toObject().is<ArrayBufferObject>();
|
||||
}
|
||||
/*
|
||||
* Tests for either ArrayBufferObject or SharedArrayBufferObject.
|
||||
* For specific class testing, use e.g., obj->is<ArrayBufferObject>().
|
||||
*/
|
||||
bool IsArrayBuffer(HandleValue v);
|
||||
bool IsArrayBuffer(HandleObject obj);
|
||||
bool IsArrayBuffer(JSObject *obj);
|
||||
ArrayBufferObject &AsArrayBuffer(HandleObject obj);
|
||||
ArrayBufferObject &AsArrayBuffer(JSObject *obj);
|
||||
|
||||
inline void
|
||||
ArrayBufferViewObject::setBufferLink(ArrayBufferObject *buffer)
|
||||
|
|
|
@ -26,6 +26,9 @@ js_InitFunctionClass(JSContext *cx, js::HandleObject obj);
|
|||
extern JSObject *
|
||||
js_InitTypedArrayClasses(JSContext *cx, js::HandleObject obj);
|
||||
|
||||
extern JSObject *
|
||||
js_InitSharedArrayBufferClass(JSContext *cx, js::HandleObject obj);
|
||||
|
||||
namespace js {
|
||||
|
||||
class Debugger;
|
||||
|
@ -262,6 +265,9 @@ class GlobalObject : public JSObject
|
|||
bool arrayBufferClassInitialized() const {
|
||||
return classIsInitialized(JSProto_ArrayBuffer);
|
||||
}
|
||||
bool sharedArrayBufferClassInitialized() const {
|
||||
return classIsInitialized(JSProto_SharedArrayBuffer);
|
||||
}
|
||||
bool errorClassesInitialized() const {
|
||||
return classIsInitialized(JSProto_Error);
|
||||
}
|
||||
|
@ -388,6 +394,12 @@ class GlobalObject : public JSObject
|
|||
return &global->getPrototype(JSProto_ArrayBuffer).toObject();
|
||||
}
|
||||
|
||||
JSObject *getOrCreateSharedArrayBufferPrototype(JSContext *cx, Handle<GlobalObject*> global) {
|
||||
if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer))
|
||||
return nullptr;
|
||||
return &global->getPrototype(JSProto_SharedArrayBuffer).toObject();
|
||||
}
|
||||
|
||||
static JSObject *getOrCreateCustomErrorPrototype(JSContext *cx,
|
||||
Handle<GlobalObject*> global,
|
||||
JSExnType exnType)
|
||||
|
|
|
@ -533,7 +533,9 @@ DenseElementsHeader::defineElement(JSContext *cx, Handle<ObjectImpl*> obj, uint3
|
|||
JSObject *
|
||||
js::ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj)
|
||||
{
|
||||
MOZ_ASSERT(obj->hasClass(&ArrayBufferObject::class_));
|
||||
MOZ_ASSERT(obj->hasClass(&ArrayBufferObject::class_) ||
|
||||
obj->hasClass(&SharedArrayBufferObject::class_));
|
||||
|
||||
if (obj->getPrivate())
|
||||
return static_cast<JSObject *>(obj->getPrivate());
|
||||
JSObject *delegate = NewObjectWithGivenProto(cx, &JSObject::class_,
|
||||
|
|
|
@ -759,10 +759,11 @@ class ObjectElements
|
|||
CONVERT_DOUBLE_ELEMENTS = 0x1,
|
||||
ASMJS_ARRAY_BUFFER = 0x2,
|
||||
NEUTERED_BUFFER = 0x4,
|
||||
SHARED_ARRAY_BUFFER = 0x8,
|
||||
|
||||
// Present only if these elements correspond to an array with
|
||||
// non-writable length; never present for non-arrays.
|
||||
NONWRITABLE_ARRAY_LENGTH = 0x8
|
||||
NONWRITABLE_ARRAY_LENGTH = 0x10
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -771,6 +772,7 @@ class ObjectElements
|
|||
friend class ArrayObject;
|
||||
friend class ArrayBufferObject;
|
||||
friend class ArrayBufferViewObject;
|
||||
friend class SharedArrayBufferObject;
|
||||
friend class TypedArrayObject;
|
||||
friend class Nursery;
|
||||
|
||||
|
@ -830,6 +832,12 @@ class ObjectElements
|
|||
void setIsNeuteredBuffer() {
|
||||
flags |= NEUTERED_BUFFER;
|
||||
}
|
||||
bool isSharedArrayBuffer() const {
|
||||
return flags & SHARED_ARRAY_BUFFER;
|
||||
}
|
||||
void setIsSharedArrayBuffer() {
|
||||
flags |= SHARED_ARRAY_BUFFER;
|
||||
}
|
||||
bool hasNonwritableArrayLength() const {
|
||||
return flags & NONWRITABLE_ARRAY_LENGTH;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,387 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "vm/SharedArrayObject.h"
|
||||
|
||||
#include "jsprf.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
# include "jswin.h"
|
||||
#else
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "jit/AsmJS.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
using mozilla::IsNaN;
|
||||
using mozilla::PodCopy;
|
||||
|
||||
#define SHAREDARRAYBUFFER_RESERVED_SLOTS 15
|
||||
|
||||
/*
|
||||
* SharedArrayRawBuffer
|
||||
*/
|
||||
|
||||
static inline void *
|
||||
MapMemory(size_t length, bool commit)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
int prot = (commit ? MEM_COMMIT : MEM_RESERVE);
|
||||
int flags = (commit ? PAGE_READWRITE : PAGE_NOACCESS);
|
||||
return VirtualAlloc(nullptr, length, prot, flags);
|
||||
#else
|
||||
int prot = (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE);
|
||||
void *p = mmap(nullptr, length, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
if (p == MAP_FAILED)
|
||||
return nullptr;
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
UnmapMemory(void *addr, size_t len)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
VirtualFree(addr, 0, MEM_RELEASE);
|
||||
#else
|
||||
munmap(addr, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
MarkValidRegion(void *addr, size_t len)
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
if (!VirtualAlloc(addr, len, MEM_COMMIT, PAGE_READWRITE))
|
||||
return false;
|
||||
return true;
|
||||
#else
|
||||
if (mprotect(addr, len, PROT_READ | PROT_WRITE))
|
||||
return false;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
SharedArrayRawBuffer *
|
||||
SharedArrayRawBuffer::New(uint32_t length)
|
||||
{
|
||||
// Enforced by SharedArrayBufferObject constructor.
|
||||
JS_ASSERT(IsValidAsmJSHeapLength(length));
|
||||
|
||||
#ifdef JS_CPU_X64
|
||||
// Get the entire reserved region (with all pages inaccessible)
|
||||
void *p = MapMemory(AsmJSMappedSize, false);
|
||||
if (!p)
|
||||
return nullptr;
|
||||
|
||||
if (!MarkValidRegion(p, AsmJSPageSize + length)) {
|
||||
UnmapMemory(p, AsmJSMappedSize);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t *buffer = reinterpret_cast<uint8_t*>(p) + AsmJSPageSize;
|
||||
uint8_t *base = buffer - sizeof(SharedArrayRawBuffer);
|
||||
return new (base) SharedArrayRawBuffer(buffer, length);
|
||||
#else
|
||||
uint32_t allocSize = sizeof(SharedArrayRawBuffer) + length;
|
||||
if (allocSize <= length)
|
||||
return nullptr;
|
||||
|
||||
void *base = MapMemory(allocSize, true);
|
||||
if (!base)
|
||||
return nullptr;
|
||||
|
||||
uint8_t *buffer = reinterpret_cast<uint8_t*>(base) + sizeof(SharedArrayRawBuffer);
|
||||
return new (base) SharedArrayRawBuffer(buffer, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
SharedArrayRawBuffer::addReference()
|
||||
{
|
||||
JS_ASSERT(this->refcount > 0);
|
||||
++this->refcount; // Atomic.
|
||||
}
|
||||
|
||||
void
|
||||
SharedArrayRawBuffer::dropReference()
|
||||
{
|
||||
// Drop the reference to the buffer.
|
||||
uint32_t refcount = --this->refcount; // Atomic.
|
||||
|
||||
// If this was the final reference, release the buffer.
|
||||
if (refcount == 0) {
|
||||
#ifdef JS_CPU_X64
|
||||
uint8_t *p = this->dataPointer() - AsmJSPageSize;
|
||||
JS_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
|
||||
UnmapMemory(p, AsmJSMappedSize);
|
||||
#else
|
||||
uint8_t *p = (uint8_t *)this;
|
||||
UnmapMemory(p, this->length);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SharedArrayBufferObject
|
||||
*/
|
||||
bool
|
||||
js::IsSharedArrayBuffer(HandleValue v)
|
||||
{
|
||||
return v.isObject() && v.toObject().is<SharedArrayBufferObject>();
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
SharedArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
JS_ASSERT(IsSharedArrayBuffer(args.thisv()));
|
||||
args.rval().setInt32(args.thisv().toObject().as<SharedArrayBufferObject>().byteLength());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SharedArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsSharedArrayBuffer, byteLengthGetterImpl>(cx, args);
|
||||
}
|
||||
|
||||
bool
|
||||
SharedArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
int32_t length = 0;
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (argc > 0 && !ToInt32(cx, args[0], &length))
|
||||
return false;
|
||||
|
||||
if (length < 0) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *bufobj = New(cx, uint32_t(length));
|
||||
if (!bufobj)
|
||||
return false;
|
||||
args.rval().setObject(*bufobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
SharedArrayBufferObject::New(JSContext *cx, uint32_t length)
|
||||
{
|
||||
if (!IsValidAsmJSHeapLength(length)) {
|
||||
ScopedJSFreePtr<char> msg(
|
||||
JS_smprintf("SharedArrayBuffer byteLength 0x%x is not a valid length. The next valid "
|
||||
"length is 0x%x", length, RoundUpToNextValidAsmJSHeapLength(length)));
|
||||
JS_ReportError(cx, msg.get());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
JS_ASSERT(obj->getClass() == &class_);
|
||||
|
||||
Rooted<js::Shape*> empty(cx);
|
||||
empty = EmptyShape::getInitialShape(cx, &class_, obj->getProto(), obj->getParent(),
|
||||
obj->getMetadata(), gc::FINALIZE_OBJECT16_BACKGROUND);
|
||||
if (!empty)
|
||||
return nullptr;
|
||||
obj->setLastPropertyInfallible(empty);
|
||||
|
||||
obj->setFixedElements();
|
||||
obj->as<SharedArrayBufferObject>().initElementsHeader(obj->getElementsHeader(), length);
|
||||
obj->getElementsHeader()->setIsSharedArrayBuffer();
|
||||
|
||||
SharedArrayRawBuffer *buffer = SharedArrayRawBuffer::New(length);
|
||||
if (!buffer)
|
||||
return nullptr;
|
||||
obj->as<SharedArrayBufferObject>().acceptRawBuffer(buffer);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
SharedArrayBufferObject::New(JSContext *cx, SharedArrayRawBuffer *buffer)
|
||||
{
|
||||
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
JS_ASSERT(obj->getClass() == &class_);
|
||||
|
||||
Rooted<js::Shape*> empty(cx);
|
||||
empty = EmptyShape::getInitialShape(cx, &class_, obj->getProto(), obj->getParent(),
|
||||
obj->getMetadata(), gc::FINALIZE_OBJECT16_BACKGROUND);
|
||||
if (!empty)
|
||||
return nullptr;
|
||||
obj->setLastPropertyInfallible(empty);
|
||||
|
||||
obj->setFixedElements();
|
||||
obj->as<SharedArrayBufferObject>().initElementsHeader(obj->getElementsHeader(),
|
||||
buffer->byteLength());
|
||||
obj->getElementsHeader()->setIsSharedArrayBuffer();
|
||||
|
||||
obj->as<SharedArrayBufferObject>().acceptRawBuffer(buffer);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void
|
||||
SharedArrayBufferObject::acceptRawBuffer(SharedArrayRawBuffer *buffer)
|
||||
{
|
||||
setReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT, PrivateValue(buffer));
|
||||
}
|
||||
|
||||
void
|
||||
SharedArrayBufferObject::dropRawBuffer()
|
||||
{
|
||||
setReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT, UndefinedValue());
|
||||
}
|
||||
|
||||
SharedArrayRawBuffer *
|
||||
SharedArrayBufferObject::rawBufferObject() const
|
||||
{
|
||||
// RAWBUF_SLOT must be populated via acceptRawBuffer(),
|
||||
// and the raw buffer must not have been dropped.
|
||||
Value v = getReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT);
|
||||
return (SharedArrayRawBuffer *)v.toPrivate();
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
SharedArrayBufferObject::dataPointer() const
|
||||
{
|
||||
return rawBufferObject()->dataPointer();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SharedArrayBufferObject::byteLength() const
|
||||
{
|
||||
return rawBufferObject()->byteLength();
|
||||
}
|
||||
|
||||
void
|
||||
SharedArrayBufferObject::Finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
SharedArrayBufferObject &buf = obj->as<SharedArrayBufferObject>();
|
||||
|
||||
// Detect the case of failure during SharedArrayBufferObject creation,
|
||||
// which causes a SharedArrayRawBuffer to never be attached.
|
||||
Value v = buf.getReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT);
|
||||
if (!v.isUndefined()) {
|
||||
buf.rawBufferObject()->dropReference();
|
||||
buf.dropRawBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SharedArrayBufferObject
|
||||
*/
|
||||
|
||||
const Class SharedArrayBufferObject::protoClass = {
|
||||
"SharedArrayBufferPrototype",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(SHAREDARRAYBUFFER_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub
|
||||
};
|
||||
|
||||
const Class SharedArrayBufferObject::class_ = {
|
||||
"SharedArrayBuffer",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_IMPLEMENTS_BARRIERS |
|
||||
Class::NON_NATIVE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(SHAREDARRAYBUFFER_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
|
||||
JS_PropertyStub, /* addProperty */
|
||||
JS_DeletePropertyStub, /* delProperty */
|
||||
JS_PropertyStub, /* getProperty */
|
||||
JS_StrictPropertyStub, /* setProperty */
|
||||
JS_EnumerateStub,
|
||||
JS_ResolveStub,
|
||||
JS_ConvertStub,
|
||||
SharedArrayBufferObject::Finalize,
|
||||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
ArrayBufferObject::obj_trace,
|
||||
JS_NULL_CLASS_SPEC,
|
||||
JS_NULL_CLASS_EXT,
|
||||
{
|
||||
ArrayBufferObject::obj_lookupGeneric,
|
||||
ArrayBufferObject::obj_lookupProperty,
|
||||
ArrayBufferObject::obj_lookupElement,
|
||||
ArrayBufferObject::obj_lookupSpecial,
|
||||
ArrayBufferObject::obj_defineGeneric,
|
||||
ArrayBufferObject::obj_defineProperty,
|
||||
ArrayBufferObject::obj_defineElement,
|
||||
ArrayBufferObject::obj_defineSpecial,
|
||||
ArrayBufferObject::obj_getGeneric,
|
||||
ArrayBufferObject::obj_getProperty,
|
||||
ArrayBufferObject::obj_getElement,
|
||||
ArrayBufferObject::obj_getSpecial,
|
||||
ArrayBufferObject::obj_setGeneric,
|
||||
ArrayBufferObject::obj_setProperty,
|
||||
ArrayBufferObject::obj_setElement,
|
||||
ArrayBufferObject::obj_setSpecial,
|
||||
ArrayBufferObject::obj_getGenericAttributes,
|
||||
ArrayBufferObject::obj_setGenericAttributes,
|
||||
ArrayBufferObject::obj_deleteProperty,
|
||||
ArrayBufferObject::obj_deleteElement,
|
||||
ArrayBufferObject::obj_deleteSpecial,
|
||||
nullptr, nullptr, /* watch/unwatch */
|
||||
nullptr, /* slice */
|
||||
ArrayBufferObject::obj_enumerate,
|
||||
nullptr, /* thisObject */
|
||||
}
|
||||
};
|
||||
|
||||
JSObject *
|
||||
js_InitSharedArrayBufferClass(JSContext *cx, HandleObject obj)
|
||||
{
|
||||
JS_ASSERT(obj->isNative());
|
||||
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
|
||||
RootedObject proto(cx, global->createBlankPrototype(cx, &SharedArrayBufferObject::protoClass));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
RootedFunction ctor(cx, global->createConstructor(cx, SharedArrayBufferObject::class_constructor,
|
||||
cx->names().SharedArrayBuffer, 1));
|
||||
if (!ctor)
|
||||
return nullptr;
|
||||
|
||||
if (!LinkConstructorAndPrototype(cx, ctor, proto))
|
||||
return nullptr;
|
||||
|
||||
RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
|
||||
unsigned flags = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
|
||||
JSObject *getter = NewFunction(cx, NullPtr(), SharedArrayBufferObject::byteLengthGetter, 0,
|
||||
JSFunction::NATIVE_FUN, global, NullPtr());
|
||||
if (!getter)
|
||||
return nullptr;
|
||||
|
||||
RootedValue value(cx, UndefinedValue());
|
||||
if (!DefineNativeProperty(cx, proto, byteLengthId, value,
|
||||
JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, flags, 0, 0))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!DefineConstructorAndPrototype(cx, global, JSProto_SharedArrayBuffer, ctor, proto))
|
||||
return nullptr;
|
||||
return proto;
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/* -*- 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 {
|
||||
|
||||
/*
|
||||
* 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 |
|
||||
*/
|
||||
class SharedArrayRawBuffer
|
||||
{
|
||||
private:
|
||||
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount;
|
||||
uint32_t length;
|
||||
|
||||
protected:
|
||||
SharedArrayRawBuffer(uint8_t *buffer, uint32_t length)
|
||||
: refcount(1), length(length)
|
||||
{
|
||||
JS_ASSERT(buffer == dataPointer());
|
||||
}
|
||||
|
||||
public:
|
||||
static SharedArrayRawBuffer *New(uint32_t length);
|
||||
|
||||
inline uint8_t *dataPointer() const {
|
||||
return ((uint8_t *)this) + sizeof(SharedArrayRawBuffer);
|
||||
}
|
||||
|
||||
inline 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.
|
||||
*/
|
||||
class SharedArrayBufferObject : public ArrayBufferObject
|
||||
{
|
||||
static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
static const Class protoClass;
|
||||
|
||||
// Slot used for storing a pointer to the SharedArrayRawBuffer.
|
||||
// First two slots hold the ObjectElements.
|
||||
static const int32_t RAWBUF_SLOT = 2;
|
||||
|
||||
static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
// Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
|
||||
static JSObject *New(JSContext *cx, uint32_t length);
|
||||
|
||||
// Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
|
||||
static JSObject *New(JSContext *cx, SharedArrayRawBuffer *buffer);
|
||||
|
||||
static bool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
static void Finalize(FreeOp *fop, JSObject *obj);
|
||||
|
||||
void acceptRawBuffer(SharedArrayRawBuffer *buffer);
|
||||
void dropRawBuffer();
|
||||
|
||||
SharedArrayRawBuffer *rawBufferObject() const;
|
||||
uint8_t *dataPointer() const;
|
||||
uint32_t byteLength() const;
|
||||
};
|
||||
|
||||
bool
|
||||
IsSharedArrayBuffer(HandleValue v);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // vm_SharedArrayObject_h
|
|
@ -32,9 +32,11 @@
|
|||
#include "gc/Marking.h"
|
||||
#include "jit/AsmJS.h"
|
||||
#include "jit/AsmJSModule.h"
|
||||
#include "vm/ArrayBufferObject.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/NumericConversions.h"
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/WrapperObject.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
|
@ -109,6 +111,12 @@ TypedArrayObject::neuter(JSContext *cx)
|
|||
setPrivate(nullptr);
|
||||
}
|
||||
|
||||
ArrayBufferObject *
|
||||
TypedArrayObject::sharedBuffer() const
|
||||
{
|
||||
return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<SharedArrayBufferObject>();
|
||||
}
|
||||
|
||||
bool
|
||||
TypedArrayObject::obj_lookupGeneric(JSContext *cx, HandleObject tarray, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
|
@ -612,7 +620,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
|||
obj->setSlot(TYPE_SLOT, Int32Value(ArrayTypeID()));
|
||||
obj->setSlot(BUFFER_SLOT, ObjectValue(*bufobj));
|
||||
|
||||
Rooted<ArrayBufferObject *> buffer(cx, &bufobj->as<ArrayBufferObject>());
|
||||
Rooted<ArrayBufferObject *> buffer(cx, &AsArrayBuffer(bufobj));
|
||||
|
||||
InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
|
||||
obj->setSlot(LENGTH_SLOT, Int32Value(len));
|
||||
|
@ -701,8 +709,11 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
|||
* properties from the object, treating it as some sort of array.
|
||||
* Note that offset and length will be ignored
|
||||
*/
|
||||
if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>())
|
||||
if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>() &&
|
||||
!UncheckedUnwrap(dataObj)->is<SharedArrayBufferObject>())
|
||||
{
|
||||
return fromArray(cx, dataObj);
|
||||
}
|
||||
|
||||
/* (ArrayBuffer, [byteOffset, [length]]) */
|
||||
int32_t byteOffset = 0;
|
||||
|
@ -974,7 +985,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
|||
return nullptr; // must be arrayBuffer
|
||||
}
|
||||
|
||||
JS_ASSERT(bufobj->is<ArrayBufferObject>() || bufobj->is<ProxyObject>());
|
||||
JS_ASSERT(IsArrayBuffer(bufobj) || bufobj->is<ProxyObject>());
|
||||
if (bufobj->is<ProxyObject>()) {
|
||||
/*
|
||||
* Normally, NonGenericMethodGuard handles the case of transparent
|
||||
|
@ -992,7 +1003,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
|||
JS_ReportError(cx, "Permission denied to access object");
|
||||
return nullptr;
|
||||
}
|
||||
if (wrapped->is<ArrayBufferObject>()) {
|
||||
if (IsArrayBuffer(wrapped)) {
|
||||
/*
|
||||
* And for even more fun, the new view's prototype should be
|
||||
* set to the origin compartment's prototype object, not the
|
||||
|
@ -1027,12 +1038,12 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
|||
}
|
||||
}
|
||||
|
||||
if (!bufobj->is<ArrayBufferObject>()) {
|
||||
if (!IsArrayBuffer(bufobj)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
return nullptr; // must be arrayBuffer
|
||||
}
|
||||
|
||||
ArrayBufferObject &buffer = bufobj->as<ArrayBufferObject>();
|
||||
ArrayBufferObject &buffer = AsArrayBuffer(bufobj);
|
||||
|
||||
if (byteOffset > buffer.byteLength() || byteOffset % sizeof(NativeType) != 0) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
|
||||
|
@ -1625,7 +1636,7 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
|||
// Verify that the private slot is at the expected place
|
||||
JS_ASSERT(dvobj.numFixedSlots() == DATA_SLOT);
|
||||
|
||||
arrayBuffer->as<ArrayBufferObject>().addView(&dvobj);
|
||||
arrayBuffer->addView(&dvobj);
|
||||
|
||||
return &dvobj;
|
||||
}
|
||||
|
@ -1633,13 +1644,13 @@ DataViewObject::create(JSContext *cx, uint32_t byteOffset, uint32_t byteLength,
|
|||
bool
|
||||
DataViewObject::construct(JSContext *cx, JSObject *bufobj, const CallArgs &args, HandleObject proto)
|
||||
{
|
||||
if (!bufobj->is<ArrayBufferObject>()) {
|
||||
if (!IsArrayBuffer(bufobj)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
|
||||
"DataView", "ArrayBuffer", bufobj->getClass()->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &bufobj->as<ArrayBufferObject>());
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
|
||||
uint32_t bufferLength = buffer->byteLength();
|
||||
uint32_t byteOffset = 0;
|
||||
uint32_t byteLength = bufferLength;
|
||||
|
@ -1697,7 +1708,7 @@ DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
|
|||
if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
|
||||
return false;
|
||||
|
||||
if (bufobj->is<WrapperObject>() && UncheckedUnwrap(bufobj)->is<ArrayBufferObject>()) {
|
||||
if (bufobj->is<WrapperObject>() && IsArrayBuffer(UncheckedUnwrap(bufobj))) {
|
||||
Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
|
||||
Rooted<JSObject*> proto(cx, global->getOrCreateDataViewPrototype(cx));
|
||||
if (!proto)
|
||||
|
|
|
@ -67,8 +67,12 @@ class TypedArrayObject : public ArrayBufferViewObject
|
|||
return tarr->getFixedSlot(LENGTH_SLOT);
|
||||
}
|
||||
|
||||
ArrayBufferObject *sharedBuffer() const;
|
||||
ArrayBufferObject *buffer() const {
|
||||
return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<ArrayBufferObject>();
|
||||
JSObject &obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObject();
|
||||
if (obj.is<ArrayBufferObject>())
|
||||
return &obj.as<ArrayBufferObject>();
|
||||
return sharedBuffer();
|
||||
}
|
||||
uint32_t byteOffset() const {
|
||||
return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
|
||||
|
|
Загрузка…
Ссылка в новой задаче