--- a/content/media/encoder/OpusTrackEncoder.cpp
+++ b/content/media/encoder/OpusTrackEncoder.cpp
@@ -34,17 +34,17 @@ static const int MAX_DATA_BYTES = 4096;
// of PCM audio samples at a fixed rate of 48 kHz."
static const int kOpusSamplingRate = 48000;
// The duration of an Opus frame, and it must be 2.5, 5, 10, 20, 40 or 60 ms.
static const int kFrameDurationMs = 20;
// The supported sampling rate of input signal (Hz),
// must be one of the following. Will resampled to 48kHz otherwise.
-static const int kOpusSupportedInputSamplingRates[5] =
+static const int kOpusSupportedInputSamplingRates[] =
{8000, 12000, 16000, 24000, 48000};
namespace {
// An endian-neutral serialization of integers. Serializing T in little endian
// format to aOutput, where T is a 16 bits or 32 bits integer.
template<typename T>
static void
@@ -65,20 +65,20 @@ SerializeToBuffer(const nsCString& aComm
}
static void
SerializeOpusIdHeader(uint8_t aChannelCount, uint16_t aPreskip,
uint32_t aInputSampleRate, nsTArray<uint8_t>* aOutput)
{
// The magic signature, null terminator has to be stripped off from strings.
- static const uint8_t magic[9] = "OpusHead";
- memcpy(aOutput->AppendElements(sizeof(magic) - 1), magic, sizeof(magic) - 1);
+ static const uint8_t magic[] = "OpusHead";
+ aOutput->AppendElements(magic, sizeof(magic) - 1);
- // The version, must always be 1 (8 bits, unsigned).
+ // The version must always be 1 (8 bits, unsigned).
aOutput->AppendElement(1);
// Number of output channels (8 bits, unsigned).
aOutput->AppendElement(aChannelCount);
// Number of samples (at 48 kHz) to discard from the decoder output when
// starting playback (16 bits, unsigned, little endian).
SerializeToBuffer(aPreskip, aOutput);
@@ -96,18 +96,18 @@ SerializeOpusIdHeader(uint8_t aChannelCo
}
static void
SerializeOpusCommentHeader(const nsCString& aVendor,
const nsTArray<nsCString>& aComments,
nsTArray<uint8_t>* aOutput)
{
// The magic signature, null terminator has to be stripped off.
- static const uint8_t magic[9] = "OpusTags";
- memcpy(aOutput->AppendElements(sizeof(magic) - 1), magic, sizeof(magic) - 1);
+ static const uint8_t magic[] = "OpusTags";
+ aOutput->AppendElements(magic, sizeof(magic) - 1);
// The vendor; Should append in the following order:
// vendor string length (32 bits, unsigned, little endian)
// vendor string.
SerializeToBuffer(aVendor, aOutput);
// Add comments; Should append in the following order:
// comment list length (32 bits, unsigned, little endian)
@@ -157,17 +157,17 @@ OpusTrackEncoder::Init(int aChannels, in
// let InterleaveTrackData downmix pcm data.
mChannels = aChannels > MAX_CHANNELS ? MAX_CHANNELS : aChannels;
// According to www.opus-codec.org, creating an opus encoder requires the
// sampling rate of source signal be one of 8000, 12000, 16000, 24000, or
// 48000. If this constraint is not satisfied, we resample the input to 48kHz.
nsTArray<int> supportedSamplingRates;
supportedSamplingRates.AppendElements(kOpusSupportedInputSamplingRates,
- MOZ_ARRAY_LENGTH(kOpusSupportedInputSamplingRates));
+ ArrayLength(kOpusSupportedInputSamplingRates));
if (!supportedSamplingRates.Contains(aSamplingRate)) {
int error;
mResampler = speex_resampler_init(mChannels,
aSamplingRate,
kOpusSamplingRate,
SPEEX_RESAMPLER_QUALITY_DEFAULT,
&error);
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -34,66 +34,66 @@ extern const JSFunctionSpec Int32x4Metho
///////////////////////////////////////////////////////////////////////////
// X4
#define LANE_ACCESSOR(Type32x4, lane) \
bool Type32x4##Lane##lane(JSContext *cx, unsigned argc, Value *vp) { \
static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"}; \
CallArgs args = CallArgsFromVp(argc, vp); \
- if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedDatum>()) { \
+ if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) { \
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
X4TypeDescr::class_.name, laneNames[lane], \
InformalValueTypeName(args.thisv())); \
return false; \
} \
- TypedDatum &datum = args.thisv().toObject().as<TypedDatum>(); \
- TypeDescr &descr = datum.typeDescr(); \
+ TypedObject &typedObj = args.thisv().toObject().as<TypedObject>(); \
+ TypeDescr &descr = typedObj.typeDescr(); \
if (descr.kind() != TypeDescr::X4 || \
descr.as<X4TypeDescr>().type() != Type32x4::type) \
{ \
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
X4TypeDescr::class_.name, laneNames[lane], \
InformalValueTypeName(args.thisv())); \
return false; \
} \
- Type32x4::Elem *data = reinterpret_cast<Type32x4::Elem *>(datum.typedMem()); \
+ Type32x4::Elem *data = reinterpret_cast<Type32x4::Elem *>(typedObj.typedMem()); \
Type32x4::setReturn(args, data[lane]); \
return true; \
}
LANE_ACCESSOR(Float32x4, 0);
LANE_ACCESSOR(Float32x4, 1);
LANE_ACCESSOR(Float32x4, 2);
LANE_ACCESSOR(Float32x4, 3);
LANE_ACCESSOR(Int32x4, 0);
LANE_ACCESSOR(Int32x4, 1);
LANE_ACCESSOR(Int32x4, 2);
LANE_ACCESSOR(Int32x4, 3);
#undef LANE_ACCESSOR
#define SIGN_MASK(Type32x4) \
bool Type32x4##SignMask(JSContext *cx, unsigned argc, Value *vp) { \
CallArgs args = CallArgsFromVp(argc, vp); \
- if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedDatum>()) { \
+ if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) { \
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
X4TypeDescr::class_.name, "signMask", \
InformalValueTypeName(args.thisv())); \
return false; \
} \
- TypedDatum &datum = args.thisv().toObject().as<TypedDatum>(); \
- TypeDescr &descr = datum.typeDescr(); \
+ TypedObject &typedObj = args.thisv().toObject().as<TypedObject>(); \
+ TypeDescr &descr = typedObj.typeDescr(); \
if (descr.kind() != TypeDescr::X4 || \
descr.as<X4TypeDescr>().type() != Type32x4::type) \
{ \
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
X4TypeDescr::class_.name, "signMask", \
InformalValueTypeName(args.thisv())); \
return false; \
} \
- Type32x4::Elem *data = reinterpret_cast<Type32x4::Elem *>(datum.typedMem()); \
+ Type32x4::Elem *data = reinterpret_cast<Type32x4::Elem *>(typedObj.typedMem()); \
int32_t mx = data[0] < 0.0 ? 1 : 0; \
int32_t my = data[1] < 0.0 ? 1 : 0; \
int32_t mz = data[2] < 0.0 ? 1 : 0; \
int32_t mw = data[3] < 0.0 ? 1 : 0; \
int32_t result = mx | my << 1 | mz << 2 | mw << 3; \
args.rval().setInt32(result); \
return true; \
}
@@ -119,66 +119,66 @@ const Class X4TypeDescr::class_ = {
};
// These classes just exist to group together various properties and so on.
namespace js {
class Int32x4Defn {
public:
static const X4TypeDescr::Type type = X4TypeDescr::TYPE_INT32;
static const JSFunctionSpec TypeDescriptorMethods[];
- static const JSPropertySpec TypedDatumProperties[];
- static const JSFunctionSpec TypedDatumMethods[];
+ static const JSPropertySpec TypedObjectProperties[];
+ static const JSFunctionSpec TypedObjectMethods[];
};
class Float32x4Defn {
public:
static const X4TypeDescr::Type type = X4TypeDescr::TYPE_FLOAT32;
static const JSFunctionSpec TypeDescriptorMethods[];
- static const JSPropertySpec TypedDatumProperties[];
- static const JSFunctionSpec TypedDatumMethods[];
+ static const JSPropertySpec TypedObjectProperties[];
+ static const JSFunctionSpec TypedObjectMethods[];
};
} // namespace js
const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END
};
-const JSPropertySpec js::Float32x4Defn::TypedDatumProperties[] = {
+const JSPropertySpec js::Float32x4Defn::TypedObjectProperties[] = {
JS_PSG("x", Float32x4Lane0, JSPROP_PERMANENT),
JS_PSG("y", Float32x4Lane1, JSPROP_PERMANENT),
JS_PSG("z", Float32x4Lane2, JSPROP_PERMANENT),
JS_PSG("w", Float32x4Lane3, JSPROP_PERMANENT),
JS_PSG("signMask", Float32x4SignMask, JSPROP_PERMANENT),
JS_PS_END
};
-const JSFunctionSpec js::Float32x4Defn::TypedDatumMethods[] = {
+const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = {
JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0),
JS_FS_END
};
const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END,
};
-const JSPropertySpec js::Int32x4Defn::TypedDatumProperties[] = {
+const JSPropertySpec js::Int32x4Defn::TypedObjectProperties[] = {
JS_PSG("x", Int32x4Lane0, JSPROP_PERMANENT),
JS_PSG("y", Int32x4Lane1, JSPROP_PERMANENT),
JS_PSG("z", Int32x4Lane2, JSPROP_PERMANENT),
JS_PSG("w", Int32x4Lane3, JSPROP_PERMANENT),
JS_PSG("signMask", Int32x4SignMask, JSPROP_PERMANENT),
JS_PS_END
};
-const JSFunctionSpec js::Int32x4Defn::TypedDatumMethods[] = {
+const JSFunctionSpec js::Int32x4Defn::TypedObjectMethods[] = {
JS_SELF_HOSTED_FN("toSource", "X4ToSource", 0, 0),
JS_FS_END
};
template<typename T>
static JSObject *
CreateX4Class(JSContext *cx, Handle<GlobalObject*> global)
{
@@ -213,18 +213,18 @@ CreateX4Class(JSContext *cx, Handle<Glob
x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
// Link constructor to prototype and install properties.
if (!JS_DefineFunctions(cx, x4, T::TypeDescriptorMethods))
return nullptr;
if (!LinkConstructorAndPrototype(cx, x4, proto) ||
- !DefinePropertiesAndBrand(cx, proto, T::TypedDatumProperties,
- T::TypedDatumMethods))
+ !DefinePropertiesAndBrand(cx, proto, T::TypedObjectProperties,
+ T::TypedObjectMethods))
{
return nullptr;
}
return x4;
}
bool
@@ -361,19 +361,19 @@ js_InitSIMDClass(JSContext *cx, HandleOb
JS_ASSERT(obj->is<GlobalObject>());
Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
return SIMDObject::initClass(cx, global);
}
template<typename V>
static bool
ObjectIsVector(JSObject &obj) {
- if (!obj.is<TypedDatum>())
+ if (!obj.is<TypedObject>())
return false;
- TypeDescr &typeRepr = obj.as<TypedDatum>().typeDescr();
+ TypeDescr &typeRepr = obj.as<TypedObject>().typeDescr();
if (typeRepr.kind() != TypeDescr::X4)
return false;
return typeRepr.as<X4TypeDescr>().type() == V::type;
}
template<typename V>
JSObject *
js::Create(JSContext *cx, typename V::Elem *data)
@@ -528,17 +528,17 @@ Func(JSContext *cx, unsigned argc, Value
if (argc == 1) {
if((!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject()))) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
typename V::Elem *val =
reinterpret_cast<typename V::Elem *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
typename Vret::Elem result[Vret::lanes];
for (int32_t i = 0; i < Vret::lanes; i++)
result[i] = Op::apply(val[i], 0);
RootedObject obj(cx, Create<Vret>(cx, result));
if (!obj)
return false;
@@ -550,20 +550,20 @@ Func(JSContext *cx, unsigned argc, Value
(!args[1].isObject() || !ObjectIsVector<V>(args[1].toObject())))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
typename V::Elem *left =
reinterpret_cast<typename V::Elem *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
typename V::Elem *right =
reinterpret_cast<typename V::Elem *>(
- args[1].toObject().as<TypedDatum>().typedMem());
+ args[1].toObject().as<TypedObject>().typedMem());
typename Vret::Elem result[Vret::lanes];
for (int32_t i = 0; i < Vret::lanes; i++)
result[i] = Op::apply(left[i], right[i]);
RootedObject obj(cx, Create<Vret>(cx, result));
if (!obj)
return false;
@@ -587,17 +587,17 @@ FuncWith(JSContext *cx, unsigned argc, V
(!args[1].isNumber() && !args[1].isBoolean()))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
typename V::Elem *val =
reinterpret_cast<typename V::Elem *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
typename Vret::Elem result[Vret::lanes];
for (int32_t i = 0; i < Vret::lanes; i++) {
if(args[1].isNumber()) {
typename Vret::Elem arg1;
Vret::toType2(cx, args[1], &arg1);
result[i] = OpWith::apply(i, arg1, val[i]);
} else if (args[1].isBoolean()) {
@@ -623,17 +623,17 @@ FuncShuffle(JSContext *cx, unsigned argc
(!args[1].isNumber()))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
typename V::Elem *val =
reinterpret_cast<typename V::Elem *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
typename Vret::Elem result[Vret::lanes];
for (int32_t i = 0; i < Vret::lanes; i++) {
typename Vret::Elem arg1;
Vret::toType2(cx, args[1], &arg1);
result[i] = val[OpShuffle::apply(i * 2, arg1)];
}
RootedObject obj(cx, Create<Vret>(cx, result));
if (!obj)
@@ -646,20 +646,20 @@ FuncShuffle(JSContext *cx, unsigned argc
(!args[1].isObject() || !ObjectIsVector<V>(args[1].toObject())) ||
(!args[2].isNumber()))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
typename V::Elem *val1 =
reinterpret_cast<typename V::Elem *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
typename V::Elem *val2 =
reinterpret_cast<typename V::Elem *>(
- args[1].toObject().as<TypedDatum>().typedMem());
+ args[1].toObject().as<TypedObject>().typedMem());
typename Vret::Elem result[Vret::lanes];
for (int32_t i = 0; i < Vret::lanes; i++) {
typename Vret::Elem arg2;
Vret::toType2(cx, args[2], &arg2);
if(i < Vret::lanes / 2) {
result[i] = val1[OpShuffle::apply(i * 2, arg2)];
} else {
result[i] = val2[OpShuffle::apply(i * 2, arg2)];
@@ -686,17 +686,17 @@ FuncConvert(JSContext *cx, unsigned argc
if ((argc != 1) ||
(!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
typename V::Elem *val =
reinterpret_cast<typename V::Elem *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
typename Vret::Elem result[Vret::lanes];
for (int32_t i = 0; i < Vret::lanes; i++)
result[i] = static_cast<typename Vret::Elem>(val[i]);
RootedObject obj(cx, Create<Vret>(cx, result));
if (!obj)
return false;
@@ -713,17 +713,17 @@ FuncConvertBits(JSContext *cx, unsigned
if ((argc != 1) ||
(!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
typename Vret::Elem *val =
reinterpret_cast<typename Vret::Elem *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
RootedObject obj(cx, Create<Vret>(cx, val));
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
@@ -808,21 +808,21 @@ Float32x4Clamp(JSContext *cx, unsigned a
(!args[0].isObject() || !ObjectIsVector<Float32x4>(args[0].toObject())) ||
(!args[1].isObject() || !ObjectIsVector<Float32x4>(args[1].toObject())) ||
(!args[2].isObject() || !ObjectIsVector<Float32x4>(args[2].toObject())))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
float *val = reinterpret_cast<float *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
float *lowerLimit = reinterpret_cast<float *>(
- args[1].toObject().as<TypedDatum>().typedMem());
+ args[1].toObject().as<TypedObject>().typedMem());
float *upperLimit = reinterpret_cast<float *>(
- args[2].toObject().as<TypedDatum>().typedMem());
+ args[2].toObject().as<TypedObject>().typedMem());
float result[Float32x4::lanes];
result[0] = val[0] < lowerLimit[0] ? lowerLimit[0] : val[0];
result[1] = val[1] < lowerLimit[1] ? lowerLimit[1] : val[1];
result[2] = val[2] < lowerLimit[2] ? lowerLimit[2] : val[2];
result[3] = val[3] < lowerLimit[3] ? lowerLimit[3] : val[3];
result[0] = result[0] > upperLimit[0] ? upperLimit[0] : result[0];
result[1] = result[1] > upperLimit[1] ? upperLimit[1] : result[1];
@@ -845,21 +845,21 @@ Int32x4Select(JSContext *cx, unsigned ar
(!args[0].isObject() || !ObjectIsVector<Int32x4>(args[0].toObject())) ||
(!args[1].isObject() || !ObjectIsVector<Float32x4>(args[1].toObject())) ||
(!args[2].isObject() || !ObjectIsVector<Float32x4>(args[2].toObject())))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
int32_t *val = reinterpret_cast<int32_t *>(
- args[0].toObject().as<TypedDatum>().typedMem());
+ args[0].toObject().as<TypedObject>().typedMem());
int32_t *tv = reinterpret_cast<int32_t *>(
- args[1].toObject().as<TypedDatum>().typedMem());
+ args[1].toObject().as<TypedObject>().typedMem());
int32_t *fv = reinterpret_cast<int32_t *>(
- args[2].toObject().as<TypedDatum>().typedMem());
+ args[2].toObject().as<TypedObject>().typedMem());
int32_t tr[Int32x4::lanes];
for (int32_t i = 0; i < Int32x4::lanes; i++)
tr[i] = And<int32_t, Int32x4>::apply(val[i], tv[i]);
int32_t fr[Int32x4::lanes];
for (int32_t i = 0; i < Int32x4::lanes; i++)
fr[i] = And<int32_t, Int32x4>::apply(Not<int32_t, Int32x4>::apply(val[i], 0), fv[i]);
int32_t orInt[Int32x4::lanes];
for (int32_t i = 0; i < Int32x4::lanes; i++)
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -200,28 +200,30 @@ HashNumber
TypeRepresentationHasher::hashUnsizedArray(UnsizedArrayTypeRepresentation *key)
{
return HashGeneric(key->kind(), key->element());
}
///////////////////////////////////////////////////////////////////////////
// Constructors
-TypeRepresentation::TypeRepresentation(TypeDescr::Kind kind, bool opaque)
+TypeRepresentation::TypeRepresentation(TypeDescr::Kind kind,
+ size_t align,
+ bool opaque)
: kind_(kind),
- opaque_(opaque)
+ opaque_(opaque),
+ alignment_(align)
{}
SizedTypeRepresentation::SizedTypeRepresentation(SizedTypeDescr::Kind kind,
bool opaque,
size_t size,
size_t align)
- : TypeRepresentation(kind, opaque),
- size_(size),
- alignment_(align)
+ : TypeRepresentation(kind, align, opaque),
+ size_(size)
{}
ScalarTypeRepresentation::ScalarTypeRepresentation(ScalarTypeDescr::Type type)
: SizedTypeRepresentation(TypeDescr::Scalar,
false,
ScalarTypeDescr::size(type),
ScalarTypeDescr::alignment(type)),
type_(type)
@@ -264,17 +266,18 @@ SizedArrayTypeRepresentation::SizedArray
: SizedTypeRepresentation(TypeDescr::SizedArray, element->opaque(),
element->size() * length, element->alignment()),
element_(element),
length_(length)
{
}
UnsizedArrayTypeRepresentation::UnsizedArrayTypeRepresentation(SizedTypeRepresentation *element)
- : TypeRepresentation(TypeDescr::UnsizedArray, element->opaque()),
+ : TypeRepresentation(TypeDescr::UnsizedArray, element->alignment(),
+ element->opaque()),
element_(element)
{
}
static inline size_t alignTo(size_t address, size_t align) {
JS_ASSERT(IsPowerOfTwo(align));
return (address + align - 1) & -align;
}
--- a/js/src/builtin/TypeRepresentation.h
+++ b/js/src/builtin/TypeRepresentation.h
@@ -120,39 +120,41 @@ struct TypeRepresentationHasher
typedef js::HashSet<TypeRepresentation *,
TypeRepresentationHasher,
RuntimeAllocPolicy> TypeRepresentationHash;
class TypeRepresentationHelper;
class TypeRepresentation {
protected:
- TypeRepresentation(TypeDescr::Kind kind, bool opaque);
+ TypeRepresentation(TypeDescr::Kind kind, size_t alignment, bool opaque);
// in order to call addToTableOrFree()
friend class TypeRepresentationHelper;
TypeDescr::Kind kind_;
bool opaque_;
+ size_t alignment_;
JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationHash::AddPtr &p);
private:
static const Class class_;
static void obj_trace(JSTracer *trace, JSObject *object);
static void obj_finalize(js::FreeOp *fop, JSObject *object);
HeapPtrObject ownerObject_;
void traceFields(JSTracer *tracer);
public:
TypeDescr::Kind kind() const { return kind_; }
bool opaque() const { return opaque_; }
bool transparent() const { return !opaque_; }
JSObject *ownerObject() const { return ownerObject_.get(); }
+ size_t alignment() const { return alignment_; }
static bool isOwnerObject(JSObject &obj);
static TypeRepresentation *fromOwnerObject(JSObject &obj);
bool isSized() const {
return TypeDescr::isSized(kind());
}
@@ -201,21 +203,19 @@ class TypeRepresentation {
void mark(JSTracer *tracer);
};
class SizedTypeRepresentation : public TypeRepresentation {
protected:
SizedTypeRepresentation(TypeDescr::Kind kind, bool opaque, size_t size, size_t align);
size_t size_;
- size_t alignment_;
public:
size_t size() const { return size_; }
- size_t alignment() const { return alignment_; }
// Initializes memory that contains `count` instances of this type.
// `count` must be at least 1.
void initInstance(const JSRuntime *rt, uint8_t *mem, size_t count);
// Traces memory that contains `count` instances of this type.
void traceInstance(JSTracer *trace, uint8_t *mem, size_t count);
};
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -38,17 +38,18 @@ const Class js::TypedObjectModuleObject:
JS_PropertyStub, /* getProperty */
JS_StrictPropertyStub, /* setProperty */
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub
};
static const JSFunctionSpec TypedObjectMethods[] = {
- JS_SELF_HOSTED_FN("objectType", "TypeOfTypedDatum", 1, 0),
+ JS_SELF_HOSTED_FN("objectType", "TypeOfTypedObject", 1, 0),
+ JS_SELF_HOSTED_FN("storage", "StorageOfTypedObject", 1, 0),
JS_FS_END
};
static void
ReportCannotConvertTo(JSContext *cx, HandleValue fromValue, const char *toType)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
InformalValueTypeName(fromValue), toType);
@@ -63,94 +64,94 @@ ToObjectIf(HandleValue value)
if (!value.toObject().is<T>())
return nullptr;
return &value.toObject().as<T>();
}
/*
- * Overwrites the contents of `datum` at offset `offset` with `val`
+ * Overwrites the contents of `typedObj` at offset `offset` with `val`
* converted to the type `typeObj`. This is done by delegating to
* self-hosted code. This is used for assignments and initializations.
*
* For example, consider the final assignment in this snippet:
*
* var Point = new StructType({x: float32, y: float32});
* var Line = new StructType({from: Point, to: Point});
* var line = new Line();
* line.to = {x: 22, y: 44};
*
* This would result in a call to `ConvertAndCopyTo`
* where:
* - typeObj = Point
- * - datum = line
+ * - typedObj = line
* - offset = sizeof(Point) == 8
* - val = {x: 22, y: 44}
* This would result in loading the value of `x`, converting
* it to a float32, and hen storing it at the appropriate offset,
* and then doing the same for `y`.
*
* Note that the type of `typeObj` may not be the
- * type of `datum` but rather some subcomponent of `datum`.
+ * type of `typedObj` but rather some subcomponent of `typedObj`.
*/
static bool
ConvertAndCopyTo(JSContext *cx,
HandleTypeDescr typeObj,
- HandleTypedDatum datum,
+ HandleTypedObject typedObj,
int32_t offset,
HandleValue val)
{
RootedFunction func(
cx, SelfHostedFunction(cx, cx->names().ConvertAndCopyTo));
if (!func)
return false;
InvokeArgs args(cx);
if (!args.init(4))
return false;
args.setCallee(ObjectValue(*func));
args[0].setObject(*typeObj);
- args[1].setObject(*datum);
+ args[1].setObject(*typedObj);
args[2].setInt32(offset);
args[3].set(val);
return Invoke(cx, args);
}
static bool
-ConvertAndCopyTo(JSContext *cx, HandleTypedDatum datum, HandleValue val)
+ConvertAndCopyTo(JSContext *cx, HandleTypedObject typedObj, HandleValue val)
{
- Rooted<TypeDescr*> type(cx, &datum->typeDescr());
- return ConvertAndCopyTo(cx, type, datum, 0, val);
+ Rooted<TypeDescr*> type(cx, &typedObj->typeDescr());
+ return ConvertAndCopyTo(cx, type, typedObj, 0, val);
}
/*
- * Overwrites the contents of `datum` at offset `offset` with `val`
+ * Overwrites the contents of `typedObj` at offset `offset` with `val`
* converted to the type `typeObj`
*/
static bool
Reify(JSContext *cx,
HandleTypeDescr type,
- HandleTypedDatum datum,
+ HandleTypedObject typedObj,
size_t offset,
MutableHandleValue to)
{
RootedFunction func(cx, SelfHostedFunction(cx, cx->names().Reify));
if (!func)
return false;
InvokeArgs args(cx);
if (!args.init(3))
return false;
args.setCallee(ObjectValue(*func));
args[0].setObject(*type);
- args[1].setObject(*datum);
+ args[1].setObject(*typedObj);
args[2].setInt32(offset);
if (!Invoke(cx, args))
return false;
to.set(args.rval());
return true;
}
@@ -183,16 +184,21 @@ TypeDescr::typeRepresentation() const {
return TypeRepresentation::fromOwnerObject(typeRepresentationOwnerObj());
}
TypeDescr::Kind
TypeDescr::kind() const {
return typeRepresentation()->kind();
}
+bool
+TypeDescr::opaque() const {
+ return typeRepresentation()->opaque();
+}
+
/***************************************************************************
* Scalar type objects
*
* Scalar type objects like `uint8`, `uint16`, are all instances of
* the ScalarTypeDescr class. Like all type objects, they have a reserved
* slot pointing to a TypeRepresentation object, which is used to
* distinguish which scalar type object this actually is.
*/
@@ -434,34 +440,34 @@ const Class UnsizedArrayTypeDescr::class
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
nullptr,
nullptr,
nullptr,
- TypedObject::construct,
+ TypedObject::constructUnsized,
nullptr
};
const Class SizedArrayTypeDescr::class_ = {
"ArrayType",
JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
nullptr,
nullptr,
nullptr,
- TypedObject::construct,
+ TypedObject::constructSized,
nullptr
};
const JSPropertySpec ArrayMetaTypeDescr::typeObjectProperties[] = {
JS_PS_END
};
const JSFunctionSpec ArrayMetaTypeDescr::typeObjectMethods[] = {
@@ -497,24 +503,25 @@ const JSFunctionSpec ArrayMetaTypeDescr:
bool
js::InitializeCommonTypeDescriptorProperties(JSContext *cx,
HandleTypeDescr obj,
HandleObject typeReprOwnerObj)
{
TypeRepresentation *typeRepr =
TypeRepresentation::fromOwnerObject(*typeReprOwnerObj);
+ obj->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT,
+ Int32Value(typeRepr->alignment()));
+
// Regardless of whether the data is transparent, we always
// store the internal size/alignment slots.
if (typeRepr->isSized()) {
SizedTypeRepresentation *sizedTypeRepr = typeRepr->asSized();
obj->initReservedSlot(JS_DESCR_SLOT_SIZE,
Int32Value(sizedTypeRepr->size()));
- obj->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT,
- Int32Value(sizedTypeRepr->alignment()));
}
// If data is transparent, also store the public slots.
if (typeRepr->transparent() && typeRepr->isSized()) {
SizedTypeRepresentation *sizedTypeRepr = typeRepr->asSized();
// byteLength
RootedValue typeByteLength(cx, NumberValue(sizedTypeRepr->size()));
@@ -739,17 +746,17 @@ const Class StructTypeDescr::class_ = {
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
nullptr, /* finalize */
nullptr, /* call */
nullptr, /* hasInstance */
- TypedObject::construct,
+ TypedObject::constructSized,
nullptr /* trace */
};
const JSPropertySpec StructMetaTypeDescr::typeObjectProperties[] = {
JS_PS_END
};
const JSFunctionSpec StructMetaTypeDescr::typeObjectMethods[] = {
@@ -1332,46 +1339,40 @@ TypedObjectModuleObject::getSuitableClas
proto.set(&global->getTypedObjectModule().getSlot(ArrayTypePrototype).toObject());
break;
}
return !!proto;
}
/******************************************************************************
- * Typed datums
- *
- * Datums represent either typed objects or handles. See comment in
- * TypedObject.h.
+ * Typed objects
*/
-template<class T>
-/*static*/ T *
-TypedDatum::createUnattached(JSContext *cx,
- HandleTypeDescr type,
+/*static*/ TypedObject *
+TypedObject::createUnattached(JSContext *cx,
+ HandleTypeDescr descr,
int32_t length)
{
- JS_STATIC_ASSERT(T::IsTypedDatumClass);
-
- RootedObject obj(cx);
- obj = createUnattachedWithClass(cx, &T::class_, type, length);
- if (!obj)
- return nullptr;
-
- return &obj->as<T>();
+ if (descr->opaque())
+ return createUnattachedWithClass(cx, &OpaqueTypedObject::class_, descr, length);
+ else
+ return createUnattachedWithClass(cx, &TransparentTypedObject::class_, descr, length);
}
-/*static*/ TypedDatum *
-TypedDatum::createUnattachedWithClass(JSContext *cx,
+
+/*static*/ TypedObject *
+TypedObject::createUnattachedWithClass(JSContext *cx,
const Class *clasp,
HandleTypeDescr type,
int32_t length)
{
- JS_ASSERT(clasp == &TypedObject::class_ || clasp == &TypedHandle::class_);
- JS_ASSERT(JSCLASS_RESERVED_SLOTS(clasp) == JS_DATUM_SLOTS);
+ JS_ASSERT(clasp == &TransparentTypedObject::class_ ||
+ clasp == &OpaqueTypedObject::class_);
+ JS_ASSERT(JSCLASS_RESERVED_SLOTS(clasp) == JS_TYPEDOBJ_SLOTS);
JS_ASSERT(clasp->hasPrivate());
RootedObject proto(cx);
if (type->is<SimpleTypeDescr>()) {
// FIXME Bug 929651 -- What prototype to use?
proto = type->global().getOrCreateObjectPrototype(cx);
} else {
RootedValue protoVal(cx);
@@ -1383,102 +1384,158 @@ TypedDatum::createUnattachedWithClass(JS
proto = &protoVal.toObject();
}
RootedObject obj(cx, NewObjectWithClassProto(cx, clasp, &*proto, nullptr));
if (!obj)
return nullptr;
obj->setPrivate(nullptr);
- obj->initReservedSlot(JS_DATUM_SLOT_TYPE_DESCR, ObjectValue(*type));
- obj->initReservedSlot(JS_DATUM_SLOT_OWNER, NullValue());
- obj->initReservedSlot(JS_DATUM_SLOT_LENGTH, Int32Value(length));
+ obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(0));
+ obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH, Int32Value(0));
+ obj->initReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, NullValue());
+ obj->initReservedSlot(JS_TYPEDOBJ_SLOT_NEXT_VIEW, PrivateValue(nullptr));
+ obj->initReservedSlot(JS_TYPEDOBJ_SLOT_NEXT_BUFFER, PrivateValue(UNSET_BUFFER_LINK));
+ obj->initReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH, Int32Value(length));
+ obj->initReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR, ObjectValue(*type));
// Tag the type object for this instance with the type
// representation, if that has not been done already.
if (cx->typeInferenceEnabled() && !type->is<SimpleTypeDescr>()) {
// FIXME Bug 929651 ^~~~~~~~~~~~~~~~~~~~~~~~~~~
RootedTypeObject typeObj(cx, obj->getType(cx));
if (typeObj) {
if (!typeObj->addTypedObjectAddendum(cx, type))
return nullptr;
}
}
- return static_cast<TypedDatum*>(&*obj);
-}
-
-void
-TypedDatum::attach(uint8_t *memory)
-{
- setPrivate(memory);
- setReservedSlot(JS_DATUM_SLOT_OWNER, ObjectValue(*this));
+ return static_cast<TypedObject*>(&*obj);
}
void
-TypedDatum::attach(TypedDatum &datum, uint32_t offset)
+TypedObject::attach(ArrayBufferObject &buffer, int32_t offset)
{
- JS_ASSERT(datum.getReservedSlot(JS_DATUM_SLOT_OWNER).isObject());
- JS_ASSERT(offset + size() <= datum.size());
-
- // find the location in memory
- uint8_t *mem = datum.typedMem(offset);
-
- // find the owner, which is often but not always `datum`
- TypedDatum &owner = datum.owner();
-
- setPrivate(mem);
- setReservedSlot(JS_DATUM_SLOT_OWNER, ObjectValue(owner));
+ JS_ASSERT(offset >= 0);
+ JS_ASSERT(offset + size() <= buffer.byteLength());
+
+ buffer.addView(this);
+ InitArrayBufferViewDataPointer(this, &buffer, offset);
+ setReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(offset));
+ setReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, ObjectValue(buffer));
}
-// Returns a suitable JS_DATUM_SLOT_LENGTH value for an instance of
+void
+TypedObject::attach(TypedObject &typedObj, int32_t offset)
+{
+ attach(typedObj.owner(), typedObj.offset() + offset);
+}
+
+// Returns a suitable JS_TYPEDOBJ_SLOT_LENGTH value for an instance of
// the type `type`. `type` must not be an unsized array.
static int32_t
-DatumLengthFromType(TypeDescr &descr)
+TypedObjLengthFromType(TypeDescr &descr)
{
TypeRepresentation *typeRepr = descr.typeRepresentation();
switch (typeRepr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::Struct:
case TypeDescr::X4:
return 0;
case TypeDescr::SizedArray:
return typeRepr->asSizedArray()->length();
case TypeDescr::UnsizedArray:
- MOZ_ASSUME_UNREACHABLE("DatumLengthFromType() invoked on unsized type");
+ MOZ_ASSUME_UNREACHABLE("TypedObjLengthFromType() invoked on unsized type");
}
MOZ_ASSUME_UNREACHABLE("Invalid kind");
}
-/*static*/ TypedDatum *
-TypedDatum::createDerived(JSContext *cx, HandleSizedTypeDescr type,
- HandleTypedDatum datum, size_t offset)
+/*static*/ TypedObject *
+TypedObject::createDerived(JSContext *cx, HandleSizedTypeDescr type,
+ HandleTypedObject typedObj, size_t offset)
{
- JS_ASSERT(offset <= datum->size());
- JS_ASSERT(offset + type->size() <= datum->size());
-
- int32_t length = DatumLengthFromType(*type);
-
- const js::Class *clasp = datum->getClass();
- Rooted<TypedDatum*> obj(
- cx, createUnattachedWithClass(cx, clasp, type, length));
+ JS_ASSERT(offset <= typedObj->size());
+ JS_ASSERT(offset + type->size() <= typedObj->size());
+
+ int32_t length = TypedObjLengthFromType(*type);
+
+ const js::Class *clasp = typedObj->getClass();
+ Rooted<TypedObject*> obj(cx);
+ obj = createUnattachedWithClass(cx, clasp, type, length);
+ if (!obj)
+ return nullptr;
+
+ obj->attach(*typedObj, offset);
+ return obj;
+}
+
+/*static*/ TypedObject *
+TypedObject::createZeroed(JSContext *cx,
+ HandleTypeDescr descr,
+ int32_t length)
+{
+ // Create unattached wrapper object.
+ Rooted<TypedObject*> obj(cx, createUnattached(cx, descr, length));
if (!obj)
return nullptr;
- obj->attach(*datum, offset);
- return obj;
+ // Allocate and initialize the memory for this instance.
+ // Also initialize the JS_TYPEDOBJ_SLOT_LENGTH slot.
+ TypeRepresentation *typeRepr = descr->typeRepresentation();
+ switch (descr->kind()) {
+ case TypeDescr::Scalar:
+ case TypeDescr::Reference:
+ case TypeDescr::Struct:
+ case TypeDescr::X4:
+ case TypeDescr::SizedArray:
+ {
+ size_t totalSize = descr->as<SizedTypeDescr>().size();
+ Rooted<ArrayBufferObject*> buffer(cx);
+ buffer = ArrayBufferObject::create(cx, totalSize, false);
+ if (!buffer)
+ return nullptr;
+ typeRepr->asSized()->initInstance(cx->runtime(), buffer->dataPointer(), 1);
+ obj->attach(*buffer, 0);
+ return obj;
+ }
+
+ case TypeDescr::UnsizedArray:
+ {
+ SizedTypeRepresentation *elementTypeRepr =
+ typeRepr->asUnsizedArray()->element();
+
+ int32_t totalSize;
+ if (!SafeMul(elementTypeRepr->size(), length, &totalSize)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
+ JSMSG_TYPEDOBJECT_TOO_BIG);
+ return nullptr;
+ }
+
+ Rooted<ArrayBufferObject*> buffer(cx);
+ buffer = ArrayBufferObject::create(cx, totalSize, false);
+ if (!buffer)
+ return nullptr;
+
+ if (length)
+ elementTypeRepr->initInstance(cx->runtime(), buffer->dataPointer(), length);
+ obj->attach(*buffer, 0);
+ return obj;
+ }
+ }
+
+ MOZ_ASSUME_UNREACHABLE("Bad TypeRepresentation Kind");
}
static bool
-ReportDatumTypeError(JSContext *cx,
+ReportTypedObjTypeError(JSContext *cx,
const unsigned errorNumber,
- HandleTypedDatum obj)
+ HandleTypedObject obj)
{
// Serialize type string using self-hosted function DescrToSource
RootedFunction func(
cx, SelfHostedFunction(cx, cx->names().DescrToSource));
if (!func)
return false;
InvokeArgs args(cx);
if (!args.init(1))
@@ -1499,70 +1556,54 @@ ReportDatumTypeError(JSContext *cx,
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
errorNumber, typeReprStr);
JS_free(cx, (void *) typeReprStr);
return false;
}
/*static*/ void
-TypedDatum::obj_trace(JSTracer *trace, JSObject *object)
+TypedObject::obj_trace(JSTracer *trace, JSObject *object)
{
- JS_ASSERT(object->is<TypedDatum>());
- TypedDatum &datum = object->as<TypedDatum>();
-
- for (size_t i = 0; i < JS_DATUM_SLOTS; i++)
- gc::MarkSlot(trace, &object->getReservedSlotRef(i), "TypedObjectSlot");
-
- TypeRepresentation *repr = datum.typeRepresentation();
+ gc::MarkSlot(trace, &object->getReservedSlotRef(JS_TYPEDOBJ_SLOT_TYPE_DESCR),
+ "TypedObjectTypeDescr");
+
+ ArrayBufferViewObject::trace(trace, object);
+
+ JS_ASSERT(object->is<TypedObject>());
+ TypedObject &typedObj = object->as<TypedObject>();
+ TypeRepresentation *repr = typedObj.typeRepresentation();
if (repr->opaque()) {
- uint8_t *mem = datum.typedMem();
+ uint8_t *mem = typedObj.typedMem();
if (!mem)
return; // unattached handle or partially constructed
switch (repr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::Struct:
case TypeDescr::SizedArray:
case TypeDescr::X4:
repr->asSized()->traceInstance(trace, mem, 1);
break;
case TypeDescr::UnsizedArray:
- repr->asUnsizedArray()->element()->traceInstance(trace, mem, datum.length());
+ repr->asUnsizedArray()->element()->traceInstance(trace, mem, typedObj.length());
break;
}
}
}
-/*static*/ void
-TypedDatum::obj_finalize(js::FreeOp *op, JSObject *obj)
-{
- // if the obj owns the memory, indicating by the owner slot being
- // set to itself, then we must free it when finalized.
-
- JS_ASSERT(obj->getReservedSlotRef(JS_DATUM_SLOT_OWNER).isObjectOrNull());
-
- if (obj->getReservedSlot(JS_DATUM_SLOT_OWNER).isNull())
- return; // Unattached
-
- if (&obj->getReservedSlot(JS_DATUM_SLOT_OWNER).toObject() == obj) {
- JS_ASSERT(obj->getPrivate());
- op->free_(obj->getPrivate());
- }
-}
-
bool
-TypedDatum::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+TypedObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleObject objp, MutableHandleShape propp)
{
- JS_ASSERT(obj->is<TypedDatum>());
-
- Rooted<TypeDescr*> typeDescr(cx, &obj->as<TypedDatum>().typeDescr());
+ JS_ASSERT(obj->is<TypedObject>());
+
+ Rooted<TypeDescr*> typeDescr(cx, &obj->as<TypedObject>().typeDescr());
TypeRepresentation *typeRepr = typeDescr->typeRepresentation();
switch (typeRepr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::X4:
break;
@@ -1600,31 +1641,31 @@ TypedDatum::obj_lookupGeneric(JSContext
propp.set(nullptr);
return true;
}
return JSObject::lookupGeneric(cx, proto, id, objp, propp);
}
bool
-TypedDatum::obj_lookupProperty(JSContext *cx,
+TypedObject::obj_lookupProperty(JSContext *cx,
HandleObject obj,
HandlePropertyName name,
MutableHandleObject objp,
MutableHandleShape propp)
{
RootedId id(cx, NameToId(name));
return obj_lookupGeneric(cx, obj, id, objp, propp);
}
bool
-TypedDatum::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+TypedObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleObject objp, MutableHandleShape propp)
{
- JS_ASSERT(obj->is<TypedDatum>());
+ JS_ASSERT(obj->is<TypedObject>());
MarkNonNativePropertyFound(propp);
objp.set(obj);
return true;
}
static bool
ReportPropertyError(JSContext *cx,
const unsigned errorNumber,
@@ -1641,202 +1682,202 @@ ReportPropertyError(JSContext *cx,
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
errorNumber, propName);
JS_free(cx, propName);
return false;
}
bool
-TypedDatum::obj_lookupSpecial(JSContext *cx, HandleObject obj,
+TypedObject::obj_lookupSpecial(JSContext *cx, HandleObject obj,
HandleSpecialId sid, MutableHandleObject objp,
MutableHandleShape propp)
{
RootedId id(cx, SPECIALID_TO_JSID(sid));
return obj_lookupGeneric(cx, obj, id, objp, propp);
}
bool
-TypedDatum::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+TypedObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
return ReportPropertyError(cx, JSMSG_UNDEFINED_PROP, id);
}
bool
-TypedDatum::obj_defineProperty(JSContext *cx, HandleObject obj,
+TypedObject::obj_defineProperty(JSContext *cx, HandleObject obj,
HandlePropertyName name, HandleValue v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
Rooted<jsid> id(cx, NameToId(name));
return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
}
bool
-TypedDatum::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
+TypedObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
if (!delegate)
return false;
return baseops::DefineElement(cx, delegate, index, v, getter, setter, attrs);
}
bool
-TypedDatum::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v,
+TypedObject::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v,
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
{
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
}
bool
-TypedDatum::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
+TypedObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
- JS_ASSERT(obj->is<TypedDatum>());
- Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
+ JS_ASSERT(obj->is<TypedObject>());
+ Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
// Dispatch elements to obj_getElement:
uint32_t index;
if (js_IdIsIndex(id, &index))
return obj_getElement(cx, obj, receiver, index, vp);
// Handle everything else here:
- TypeRepresentation *typeRepr = datum->typeRepresentation();
+ TypeRepresentation *typeRepr = typedObj->typeRepresentation();
switch (typeRepr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
break;
case TypeDescr::X4:
break;
case TypeDescr::SizedArray:
case TypeDescr::UnsizedArray:
if (JSID_IS_ATOM(id, cx->names().length)) {
- if (!datum->typedMem()) { // unattached
+ if (!typedObj->typedMem()) { // unattached
JS_ReportErrorNumber(
cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
return false;
}
- vp.setInt32(datum->length());
+ vp.setInt32(typedObj->length());
return true;
}
break;
case TypeDescr::Struct: {
- Rooted<StructTypeDescr*> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
+ Rooted<StructTypeDescr*> descr(cx, &typedObj->typeDescr().as<StructTypeDescr>());
size_t fieldIndex;
if (!descr->fieldIndex(id, &fieldIndex))
break;
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
- return Reify(cx, fieldType, datum, offset, vp);
+ return Reify(cx, fieldType, typedObj, offset, vp);
}
}
RootedObject proto(cx, obj->getProto());
if (!proto) {
vp.setUndefined();
return true;
}
return JSObject::getGeneric(cx, proto, receiver, id, vp);
}
bool
-TypedDatum::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+TypedObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
HandlePropertyName name, MutableHandleValue vp)
{
RootedId id(cx, NameToId(name));
return obj_getGeneric(cx, obj, receiver, id, vp);
}
bool
-TypedDatum::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
+TypedObject::obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp)
{
- JS_ASSERT(obj->is<TypedDatum>());
- Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
- Rooted<TypeDescr *> descr(cx, &datum->typeDescr());
+ JS_ASSERT(obj->is<TypedObject>());
+ Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
+ Rooted<TypeDescr *> descr(cx, &typedObj->typeDescr());
switch (descr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::X4:
case TypeDescr::Struct:
break;
case TypeDescr::SizedArray:
- return obj_getArrayElement<SizedArrayTypeDescr>(cx, datum, descr,
+ return obj_getArrayElement<SizedArrayTypeDescr>(cx, typedObj, descr,
index, vp);
case TypeDescr::UnsizedArray:
- return obj_getArrayElement<UnsizedArrayTypeDescr>(cx, datum, descr,
+ return obj_getArrayElement<UnsizedArrayTypeDescr>(cx, typedObj, descr,
index, vp);
}
RootedObject proto(cx, obj->getProto());
if (!proto) {
vp.setUndefined();
return true;
}
return JSObject::getElement(cx, proto, receiver, index, vp);
}
template<class T>
/*static*/ bool
-TypedDatum::obj_getArrayElement(JSContext *cx,
- Handle<TypedDatum*> datum,
+TypedObject::obj_getArrayElement(JSContext *cx,
+ Handle<TypedObject*> typedObj,
Handle<TypeDescr*> typeDescr,
uint32_t index,
MutableHandleValue vp)
{
JS_ASSERT(typeDescr->is<T>());
- if (index >= datum->length()) {
+ if (index >= typedObj->length()) {
vp.setUndefined();
return true;
}
Rooted<SizedTypeDescr*> elementType(cx, &typeDescr->as<T>().elementType());
size_t offset = elementType->size() * index;
- return Reify(cx, elementType, datum, offset, vp);
+ return Reify(cx, elementType, typedObj, offset, vp);
}
bool
-TypedDatum::obj_getSpecial(JSContext *cx, HandleObject obj,
+TypedObject::obj_getSpecial(JSContext *cx, HandleObject obj,
HandleObject receiver, HandleSpecialId sid,
MutableHandleValue vp)
{
RootedId id(cx, SPECIALID_TO_JSID(sid));
return obj_getGeneric(cx, obj, receiver, id, vp);
}
bool
-TypedDatum::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
+TypedObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleValue vp, bool strict)
{
- JS_ASSERT(obj->is<TypedDatum>());
- Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
+ JS_ASSERT(obj->is<TypedObject>());
+ Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
uint32_t index;
if (js_IdIsIndex(id, &index))
return obj_setElement(cx, obj, index, vp, strict);
- TypeRepresentation *typeRepr = datum->typeRepresentation();
+ TypeRepresentation *typeRepr = typedObj->typeRepresentation();
switch (typeRepr->kind()) {
case ScalarTypeDescr::Scalar:
case TypeDescr::Reference:
break;
case ScalarTypeDescr::X4:
break;
@@ -1845,103 +1886,103 @@ TypedDatum::obj_setGeneric(JSContext *cx
if (JSID_IS_ATOM(id, cx->names().length)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
return false;
}
break;
case ScalarTypeDescr::Struct: {
- Rooted<StructTypeDescr*> descr(cx, &datum->typeDescr().as<StructTypeDescr>());
+ Rooted<StructTypeDescr*> descr(cx, &typedObj->typeDescr().as<StructTypeDescr>());
size_t fieldIndex;
if (!descr->fieldIndex(id, &fieldIndex))
break;
size_t offset = descr->fieldOffset(fieldIndex);
Rooted<SizedTypeDescr*> fieldType(cx, &descr->fieldDescr(fieldIndex));
- return ConvertAndCopyTo(cx, fieldType, datum, offset, vp);
+ return ConvertAndCopyTo(cx, fieldType, typedObj, offset, vp);
}
}
- return ReportDatumTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, datum);
+ return ReportTypedObjTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, typedObj);
}
bool
-TypedDatum::obj_setProperty(JSContext *cx, HandleObject obj,
+TypedObject::obj_setProperty(JSContext *cx, HandleObject obj,
HandlePropertyName name, MutableHandleValue vp,
bool strict)
{
RootedId id(cx, NameToId(name));
return obj_setGeneric(cx, obj, id, vp, strict);
}
bool
-TypedDatum::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
+TypedObject::obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
MutableHandleValue vp, bool strict)
{
- JS_ASSERT(obj->is<TypedDatum>());
- Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
- Rooted<TypeDescr *> descr(cx, &datum->typeDescr());
+ JS_ASSERT(obj->is<TypedObject>());
+ Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
+ Rooted<TypeDescr *> descr(cx, &typedObj->typeDescr());
switch (descr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::X4:
case TypeDescr::Struct:
break;
case TypeDescr::SizedArray:
- return obj_setArrayElement<SizedArrayTypeDescr>(cx, datum, descr, index, vp);
+ return obj_setArrayElement<SizedArrayTypeDescr>(cx, typedObj, descr, index, vp);
case TypeDescr::UnsizedArray:
- return obj_setArrayElement<UnsizedArrayTypeDescr>(cx, datum, descr, index, vp);
+ return obj_setArrayElement<UnsizedArrayTypeDescr>(cx, typedObj, descr, index, vp);
}
- return ReportDatumTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, datum);
+ return ReportTypedObjTypeError(cx, JSMSG_OBJECT_NOT_EXTENSIBLE, typedObj);
}
template<class T>
/*static*/ bool
-TypedDatum::obj_setArrayElement(JSContext *cx,
- Handle<TypedDatum*> datum,
+TypedObject::obj_setArrayElement(JSContext *cx,
+ Handle<TypedObject*> typedObj,
Handle<TypeDescr*> descr,
uint32_t index,
MutableHandleValue vp)
{
JS_ASSERT(descr->is<T>());
- if (index >= datum->length()) {
+ if (index >= typedObj->length()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
nullptr, JSMSG_TYPEDOBJECT_BINARYARRAY_BAD_INDEX);
return false;
}
Rooted<SizedTypeDescr*> elementType(cx);
elementType = &descr->as<T>().elementType();
size_t offset = elementType->size() * index;
- return ConvertAndCopyTo(cx, elementType, datum, offset, vp);
+ return ConvertAndCopyTo(cx, elementType, typedObj, offset, vp);
}
bool
-TypedDatum::obj_setSpecial(JSContext *cx, HandleObject obj,
+TypedObject::obj_setSpecial(JSContext *cx, HandleObject obj,
HandleSpecialId sid, MutableHandleValue vp,
bool strict)
{
RootedId id(cx, SPECIALID_TO_JSID(sid));
return obj_setGeneric(cx, obj, id, vp, strict);
}
bool
-TypedDatum::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
+TypedObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
HandleId id, unsigned *attrsp)
{
uint32_t index;
- Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
- TypeRepresentation *typeRepr = datum->typeRepresentation();
+ Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
+ TypeRepresentation *typeRepr = typedObj->typeRepresentation();
switch (typeRepr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
break;
case TypeDescr::X4:
break;
@@ -1974,18 +2015,18 @@ TypedDatum::obj_getGenericAttributes(JSC
return JSObject::getGenericAttributes(cx, proto, id, attrsp);
}
static bool
IsOwnId(JSContext *cx, HandleObject obj, HandleId id)
{
uint32_t index;
- Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
- TypeRepresentation *typeRepr = datum->typeRepresentation();
+ Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
+ TypeRepresentation *typeRepr = typedObj->typeRepresentation();
switch (typeRepr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::X4:
return false;
case TypeDescr::SizedArray:
@@ -1995,50 +2036,50 @@ IsOwnId(JSContext *cx, HandleObject obj,
case TypeDescr::Struct:
return typeRepr->asStruct()->fieldNamed(id) != nullptr;
}
return false;
}
bool
-TypedDatum::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
+TypedObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
HandleId id, unsigned *attrsp)
{
if (IsOwnId(cx, obj, id))
return ReportPropertyError(cx, JSMSG_CANT_REDEFINE_PROP, id);
RootedObject proto(cx, obj->getProto());
if (!proto) {
*attrsp = 0;
return true;
}
return JSObject::setGenericAttributes(cx, proto, id, attrsp);
}
bool
-TypedDatum::obj_deleteProperty(JSContext *cx, HandleObject obj,
+TypedObject::obj_deleteProperty(JSContext *cx, HandleObject obj,
HandlePropertyName name, bool *succeeded)
{
Rooted<jsid> id(cx, NameToId(name));
if (IsOwnId(cx, obj, id))
return ReportPropertyError(cx, JSMSG_CANT_DELETE, id);
RootedObject proto(cx, obj->getProto());
if (!proto) {
*succeeded = false;
return true;
}
return JSObject::deleteProperty(cx, proto, name, succeeded);
}
bool
-TypedDatum::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
+TypedObject::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
bool *succeeded)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
return false;
if (IsOwnId(cx, obj, id))
return ReportPropertyError(cx, JSMSG_CANT_DELETE, id);
@@ -2048,37 +2089,37 @@ TypedDatum::obj_deleteElement(JSContext
*succeeded = false;
return true;
}
return JSObject::deleteElement(cx, proto, index, succeeded);
}
bool
-TypedDatum::obj_deleteSpecial(JSContext *cx, HandleObject obj,
+TypedObject::obj_deleteSpecial(JSContext *cx, HandleObject obj,
HandleSpecialId sid, bool *succeeded)
{
RootedObject proto(cx, obj->getProto());
if (!proto) {
*succeeded = false;
return true;
}
return JSObject::deleteSpecial(cx, proto, sid, succeeded);
}
bool
-TypedDatum::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
+TypedObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
MutableHandleValue statep, MutableHandleId idp)
{
uint32_t index;
- JS_ASSERT(obj->is<TypedDatum>());
- Rooted<TypedDatum *> datum(cx, &obj->as<TypedDatum>());
- TypeRepresentation *typeRepr = datum->typeRepresentation();
+ JS_ASSERT(obj->is<TypedObject>());
+ Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
+ TypeRepresentation *typeRepr = typedObj->typeRepresentation();
switch (typeRepr->kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::X4:
switch (enum_op) {
case JSENUMERATE_INIT_ALL:
case JSENUMERATE_INIT:
@@ -2093,27 +2134,27 @@ TypedDatum::obj_enumerate(JSContext *cx,
break;
case TypeDescr::SizedArray:
case TypeDescr::UnsizedArray:
switch (enum_op) {
case JSENUMERATE_INIT_ALL:
case JSENUMERATE_INIT:
statep.setInt32(0);
- idp.set(INT_TO_JSID(datum->length()));
+ idp.set(INT_TO_JSID(typedObj->length()));
break;
case JSENUMERATE_NEXT:
index = static_cast<int32_t>(statep.toInt32());
- if (index < datum->length()) {
+ if (index < typedObj->length()) {
idp.set(INT_TO_JSID(index));
statep.setInt32(index + 1);
} else {
- JS_ASSERT(index == datum->length());
+ JS_ASSERT(index == typedObj->length());
statep.setNull();
}
break;
case JSENUMERATE_DESTROY:
statep.setNull();
break;
@@ -2146,417 +2187,577 @@ TypedDatum::obj_enumerate(JSContext *cx,
}
break;
}
return true;
}
/* static */ size_t
-TypedDatum::dataOffset()
+TypedObject::dataOffset()
{
- return JSObject::getPrivateDataOffset(JS_DATUM_SLOTS);
+ // the offset of 7 is based on the alloc kind
+ return JSObject::getPrivateDataOffset(JS_TYPEDOBJ_SLOT_DATA);
+}
+
+void
+TypedObject::neuter(JSContext *cx)
+{
+ setSlot(JS_TYPEDOBJ_SLOT_LENGTH, Int32Value(0));
+ setSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH, Int32Value(0));
+ setSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(0));
+ setPrivate(nullptr);
}
/******************************************************************************
* Typed Objects
*/
-const Class TypedObject::class_ = {
+const Class TransparentTypedObject::class_ = {
"TypedObject",
Class::NON_NATIVE |
- JSCLASS_HAS_RESERVED_SLOTS(JS_DATUM_SLOTS) |
+ JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEDOBJ_SLOTS) |
JSCLASS_HAS_PRIVATE |
JSCLASS_IMPLEMENTS_BARRIERS,
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
- TypedDatum::obj_finalize,
+ nullptr, /* finalize */
nullptr, /* call */
nullptr, /* construct */
nullptr, /* hasInstance */
- TypedDatum::obj_trace,
+ TypedObject::obj_trace,
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
{
- TypedDatum::obj_lookupGeneric,
- TypedDatum::obj_lookupProperty,
- TypedDatum::obj_lookupElement,
- TypedDatum::obj_lookupSpecial,
- TypedDatum::obj_defineGeneric,
- TypedDatum::obj_defineProperty,
- TypedDatum::obj_defineElement,
- TypedDatum::obj_defineSpecial,
- TypedDatum::obj_getGeneric,
- TypedDatum::obj_getProperty,
- TypedDatum::obj_getElement,
- TypedDatum::obj_getSpecial,
- TypedDatum::obj_setGeneric,
- TypedDatum::obj_setProperty,
- TypedDatum::obj_setElement,
- TypedDatum::obj_setSpecial,
- TypedDatum::obj_getGenericAttributes,
- TypedDatum::obj_setGenericAttributes,
- TypedDatum::obj_deleteProperty,
- TypedDatum::obj_deleteElement,
- TypedDatum::obj_deleteSpecial,
+ TypedObject::obj_lookupGeneric,
+ TypedObject::obj_lookupProperty,
+ TypedObject::obj_lookupElement,
+ TypedObject::obj_lookupSpecial,
+ TypedObject::obj_defineGeneric,
+ TypedObject::obj_defineProperty,
+ TypedObject::obj_defineElement,
+ TypedObject::obj_defineSpecial,
+ TypedObject::obj_getGeneric,
+ TypedObject::obj_getProperty,
+ TypedObject::obj_getElement,
+ TypedObject::obj_getSpecial,
+ TypedObject::obj_setGeneric,
+ TypedObject::obj_setProperty,
+ TypedObject::obj_setElement,
+ TypedObject::obj_setSpecial,
+ TypedObject::obj_getGenericAttributes,
+ TypedObject::obj_setGenericAttributes,
+ TypedObject::obj_deleteProperty,
+ TypedObject::obj_deleteElement,
+ TypedObject::obj_deleteSpecial,
nullptr, nullptr, // watch/unwatch
nullptr, /* slice */
- TypedDatum::obj_enumerate,
+ TypedObject::obj_enumerate,
nullptr, /* thisObject */
}
};
-/*static*/ TypedObject *
-TypedObject::createZeroed(JSContext *cx,
- HandleTypeDescr descr,
- int32_t length)
+static int32_t
+LengthForType(TypeDescr &descr)
{
- // Create unattached wrapper object.
- Rooted<TypedObject*> obj(cx);
- obj = createUnattached<TypedObject>(cx, descr, length);
- if (!obj)
- return nullptr;
-
- // Allocate and initialize the memory for this instance.
- // Also initialize the JS_DATUM_SLOT_LENGTH slot.
- TypeRepresentation *typeRepr = descr->typeRepresentation();
- switch (descr->kind()) {
+ switch (descr.kind()) {
case TypeDescr::Scalar:
case TypeDescr::Reference:
case TypeDescr::Struct:
case TypeDescr::X4:
- {
- uint8_t *memory =
- (uint8_t*) cx->malloc_(descr->as<SizedTypeDescr>().size());
- if (!memory)
- return nullptr;
- typeRepr->asSized()->initInstance(cx->runtime(), memory, 1);
- obj->attach(memory);
- return obj;
- }
+ return 0;
case TypeDescr::SizedArray:
- {
- uint8_t *memory =
- (uint8_t*) cx->malloc_(descr->as<SizedTypeDescr>().size());
- if (!memory)
- return nullptr;
- typeRepr->asSizedArray()->initInstance(cx->runtime(), memory, 1);
- obj->attach(memory);
- return obj;
- }
+ return descr.as<SizedArrayTypeDescr>().length();
case TypeDescr::UnsizedArray:
- {
- SizedTypeRepresentation *elementTypeRepr =
- typeRepr->asUnsizedArray()->element();
-
- int32_t totalSize;
- if (!SafeMul(elementTypeRepr->size(), length, &totalSize)) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
- JSMSG_TYPEDOBJECT_TOO_BIG);
- return nullptr;
- }
-
- uint8_t *memory = (uint8_t*) JS_malloc(cx, totalSize);
- if (!memory)
- return nullptr;
-
- if (length)
- elementTypeRepr->initInstance(cx->runtime(), memory, length);
- obj->attach(memory);
- return obj;
- }
+ return 0;
}
- MOZ_ASSUME_UNREACHABLE("Bad TypeRepresentation Kind");
+ MOZ_ASSUME_UNREACHABLE("Invalid kind");
+}
+
+static bool
+CheckOffset(int32_t offset,
+ int32_t size,
+ int32_t alignment,
+ int32_t bufferLength)
+{
+ JS_ASSERT(size >= 0);
+ JS_ASSERT(alignment >= 0);
+
+ // No negative offsets.
+ if (offset < 0)
+ return false;
+
+ // Offset (plus size) must be fully contained within the buffer.
+ if (offset > bufferLength)
+ return false;
+ if (offset + size < offset)
+ return false;
+ if (offset + size > bufferLength)
+ return false;
+
+ // Offset must be aligned.
+ if ((offset % alignment) != 0)
+ return false;
+
+ return true;
}
/*static*/ bool
-TypedObject::construct(JSContext *cx, unsigned int argc, Value *vp)
+TypedObject::constructSized(JSContext *cx, unsigned int argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+
+ JS_ASSERT(args.callee().is<SizedTypeDescr>());
+ Rooted<SizedTypeDescr*> callee(cx, &args.callee().as<SizedTypeDescr>());
+
+ // Typed object constructors for sized types are overloaded in
+ // three ways, in order of precedence:
+ //
+ // new TypeObj()
+ // new TypeObj(buffer, [offset])
+ // new TypeObj(data)
+
+ // Zero argument constructor:
+ if (args.length() == 0) {
+ int32_t length = LengthForType(*callee);
+ Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+ }
+
+ // Buffer constructor.
+ if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
+ Rooted<ArrayBufferObject*> buffer(cx);
+ buffer = &args[0].toObject().as<ArrayBufferObject>();
+
+ int32_t offset;
+ if (args.length() >= 2 && !args[1].isUndefined()) {
+ if (!args[1].isInt32()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+
+ offset = args[1].toInt32();
+ } else {
+ offset = 0;
+ }
+
+ if (args.length() >= 3 && !args[2].isUndefined()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+
+ if (!CheckOffset(offset, callee->size(), callee->alignment(),
+ buffer->byteLength()))
+ {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+
+ Rooted<TypedObject*> obj(cx);
+ obj = TypedObject::createUnattached(cx, callee, LengthForType(*callee));
+ if (!obj)
+ return false;
+
+ obj->attach(*buffer, offset);
+ args.rval().setObject(*obj);
+ return true;
+ }
+
+ // Data constructor.
+ if (args[0].isObject()) {
+ // Create the typed object.
+ int32_t length = LengthForType(*callee);
+ Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
+ if (!obj)
+ return false;
+
+ // Initialize from `arg`.
+ if (!ConvertAndCopyTo(cx, obj, args[0]))
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+ }
+
+ // Something bogus.
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+}
+
+/*static*/ bool
+TypedObject::constructUnsized(JSContext *cx, unsigned int argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.callee().is<TypeDescr>());
- Rooted<TypeDescr*> callee(cx, &args.callee().as<TypeDescr>());
- TypeRepresentation *typeRepr = callee->typeRepresentation();
-
- // Determine the length based on the target type.
- uint32_t nextArg = 0;
- int32_t length = 0;
- switch (typeRepr->kind()) {
- case TypeDescr::Scalar:
- case TypeDescr::Reference:
- case TypeDescr::Struct:
- case TypeDescr::X4:
- length = 0;
- break;
-
- case TypeDescr::SizedArray:
- length = typeRepr->asSizedArray()->length();
- break;
-
- case TypeDescr::UnsizedArray:
- // First argument is a length.
- if (nextArg >= argc || !args[nextArg].isInt32()) {
+ Rooted<UnsizedArrayTypeDescr*> callee(cx);
+ callee = &args.callee().as<UnsizedArrayTypeDescr>();
+
+ // Typed object constructors for unsized arrays are overloaded in
+ // four ways, in order of precedence:
+ //
+ // new TypeObj(buffer, [offset, [length]]) // [1]
+ // new TypeObj(length) // [1]
+ // new TypeObj(data)
+ // new TypeObj()
+ //
+ // [1] Explicit lengths only available for unsized arrays.
+
+ // Zero argument constructor:
+ if (args.length() == 0) {
+ Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, 0));
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+ }
+
+ // Length constructor.
+ if (args[0].isInt32()) {
+ int32_t length = args[0].toInt32();
+ Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
+ if (!obj)
+ return false;
+ args.rval().setObject(*obj);
+ return true;
+ }
+
+ // Buffer constructor.
+ if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
+ Rooted<ArrayBufferObject*> buffer(cx);
+ buffer = &args[0].toObject().as<ArrayBufferObject>();
+
+ int32_t offset;
+ if (args.length() >= 2 && !args[1].isUndefined()) {
+ if (!args[1].isInt32()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+
+ offset = args[1].toInt32();
+ } else {
+ offset = 0;
+ }
+
+ if (!CheckOffset(offset, 0, callee->alignment(), buffer->byteLength())) {
JS_ReportErrorNumber(cx, js_GetErrorMessage,
- nullptr, JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS,
- "1", "array length");
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
}
- length = args[nextArg++].toInt32();
- break;
+
+ int32_t elemSize = callee->elementType().size();
+ int32_t bytesRemaining = buffer->byteLength() - offset;
+ int32_t maximumLength = bytesRemaining / elemSize;
+
+ int32_t length;
+ if (args.length() >= 3 && !args[2].isUndefined()) {
+ if (!args[2].isInt32()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+ length = args[2].toInt32();
+
+ if (length < 0 || length > maximumLength) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+ } else {
+ if ((bytesRemaining % elemSize) != 0) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+
+ length = maximumLength;
+ }
+
+ Rooted<TypedObject*> obj(cx);
+ obj = TypedObject::createUnattached(cx, callee, length);
+ if (!obj)
+ return false;
+
+ obj->attach(args[0].toObject().as<ArrayBufferObject>(), offset);
}
- // Create zeroed wrapper object.
- Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
- if (!obj)
- return nullptr;
-
- if (nextArg < argc) {
- RootedValue initial(cx, args[nextArg++]);
- if (!ConvertAndCopyTo(cx, obj, initial))
+ // Data constructor for unsized values
+ if (args[0].isObject()) {
+ // Read length out of the object.
+ RootedObject arg(cx, &args[0].toObject());
+ RootedValue lengthVal(cx);
+ if (!JSObject::getProperty(cx, arg, arg, cx->names().length, &lengthVal))
+ return false;
+ if (!lengthVal.isInt32()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
return false;
+ }
+ int32_t length = lengthVal.toInt32();
+
+ // Check that length * elementSize does not overflow.
+ int32_t elementSize = callee->elementType().size();
+ int32_t byteLength;
+ if (!SafeMul(elementSize, length, &byteLength)) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
+ }
+
+ // Create the unsized array.
+ Rooted<TypedObject*> obj(cx, createZeroed(cx, callee, length));
+ if (!obj)
+ return false;
+
+ // Initialize from `arg`
+ if (!ConvertAndCopyTo(cx, obj, args[0]))
+ return false;
+ args.rval().setObject(*obj);
+ return true;
}
- args.rval().setObject(*obj);
- return true;
+ // Something bogus.
+ JS_ReportErrorNumber(cx, js_GetErrorMessage,
+ nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return false;
}
/******************************************************************************
* Handles
*/
-const Class TypedHandle::class_ = {
+const Class OpaqueTypedObject::class_ = {
"Handle",
Class::NON_NATIVE |
- JSCLASS_HAS_RESERVED_SLOTS(JS_DATUM_SLOTS) |
+ JSCLASS_HAS_RESERVED_SLOTS(JS_TYPEDOBJ_SLOTS) |
JSCLASS_HAS_PRIVATE |
JSCLASS_IMPLEMENTS_BARRIERS,
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub,
- TypedDatum::obj_finalize,
+ nullptr, /* finalize */
nullptr, /* call */
nullptr, /* construct */
nullptr, /* hasInstance */
- TypedDatum::obj_trace,
+ TypedObject::obj_trace,
JS_NULL_CLASS_SPEC,
JS_NULL_CLASS_EXT,
{
- TypedDatum::obj_lookupGeneric,
- TypedDatum::obj_lookupProperty,
- TypedDatum::obj_lookupElement,
- TypedDatum::obj_lookupSpecial,
- TypedDatum::obj_defineGeneric,
- TypedDatum::obj_defineProperty,
- TypedDatum::obj_defineElement,
- TypedDatum::obj_defineSpecial,
- TypedDatum::obj_getGeneric,
- TypedDatum::obj_getProperty,
- TypedDatum::obj_getElement,
- TypedDatum::obj_getSpecial,
- TypedDatum::obj_setGeneric,
- TypedDatum::obj_setProperty,
- TypedDatum::obj_setElement,
- TypedDatum::obj_setSpecial,
- TypedDatum::obj_getGenericAttributes,
- TypedDatum::obj_setGenericAttributes,
- TypedDatum::obj_deleteProperty,
- TypedDatum::obj_deleteElement,
- TypedDatum::obj_deleteSpecial,
+ TypedObject::obj_lookupGeneric,
+ TypedObject::obj_lookupProperty,
+ TypedObject::obj_lookupElement,
+ TypedObject::obj_lookupSpecial,
+ TypedObject::obj_defineGeneric,
+ TypedObject::obj_defineProperty,
+ TypedObject::obj_defineElement,
+ TypedObject::obj_defineSpecial,
+ TypedObject::obj_getGeneric,
+ TypedObject::obj_getProperty,
+ TypedObject::obj_getElement,
+ TypedObject::obj_getSpecial,
+ TypedObject::obj_setGeneric,
+ TypedObject::obj_setProperty,
+ TypedObject::obj_setElement,
+ TypedObject::obj_setSpecial,
+ TypedObject::obj_getGenericAttributes,
+ TypedObject::obj_setGenericAttributes,
+ TypedObject::obj_deleteProperty,
+ TypedObject::obj_deleteElement,
+ TypedObject::obj_deleteSpecial,
nullptr, nullptr, // watch/unwatch
nullptr, // slice
- TypedDatum::obj_enumerate,
+ TypedObject::obj_enumerate,
nullptr, /* thisObject */
}
};
-const JSFunctionSpec TypedHandle::handleStaticMethods[] = {
+const JSFunctionSpec OpaqueTypedObject::handleStaticMethods[] = {
{"move", {nullptr, nullptr}, 3, 0, "HandleMove"},
{"get", {nullptr, nullptr}, 1, 0, "HandleGet"},
{"set", {nullptr, nullptr}, 2, 0, "HandleSet"},
{"isHandle", {nullptr, nullptr}, 1, 0, "HandleTest"},
JS_FS_END
};
/******************************************************************************
* Intrinsics
*/
bool
-js::NewTypedHandle(JSContext *cx, unsigned argc, Value *vp)
+js::NewOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 1);
+ JS_ASSERT(args.length() == 1);
JS_ASSERT(args[0].isObject() && args[0].toObject().is<SizedTypeDescr>());
Rooted<SizedTypeDescr*> descr(cx, &args[0].toObject().as<SizedTypeDescr>());
- int32_t length = DatumLengthFromType(*descr);
- Rooted<TypedHandle*> obj(cx);
- obj = TypedDatum::createUnattached<TypedHandle>(cx, descr, length);
+ int32_t length = TypedObjLengthFromType(*descr);
+ Rooted<TypedObject*> obj(cx);
+ obj = TypedObject::createUnattachedWithClass(cx, &OpaqueTypedObject::class_, descr, length);
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
bool
-js::NewDerivedTypedDatum(JSContext *cx, unsigned argc, Value *vp)
+js::NewDerivedTypedObject(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 3);
+ JS_ASSERT(args.length() == 3);
JS_ASSERT(args[0].isObject() && args[0].toObject().is<SizedTypeDescr>());
- JS_ASSERT(args[1].isObject() && args[1].toObject().is<TypedDatum>());
+ JS_ASSERT(args[1].isObject() && args[1].toObject().is<TypedObject>());
JS_ASSERT(args[2].isInt32());
Rooted<SizedTypeDescr*> descr(cx, &args[0].toObject().as<SizedTypeDescr>());
- Rooted<TypedDatum*> datum(cx, &args[1].toObject().as<TypedDatum>());
+ Rooted<TypedObject*> typedObj(cx, &args[1].toObject().as<TypedObject>());
int32_t offset = args[2].toInt32();
- Rooted<TypedDatum*> obj(cx);
- obj = TypedDatum::createDerived(cx, descr, datum, offset);
+ Rooted<TypedObject*> obj(cx);
+ obj = TypedObject::createDerived(cx, descr, typedObj, offset);
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
bool
-js::AttachHandle(ThreadSafeContext *, unsigned argc, Value *vp)
+js::AttachTypedObject(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 3);
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedHandle>());
- JS_ASSERT(args[1].isObject() && args[1].toObject().is<TypedDatum>());
+ JS_ASSERT(args.length() == 3);
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());
+ JS_ASSERT(args[1].isObject() && args[1].toObject().is<TypedObject>());
JS_ASSERT(args[2].isInt32());
- TypedHandle &handle = args[0].toObject().as<TypedHandle>();
- TypedDatum &target = args[1].toObject().as<TypedDatum>();
+ TypedObject &handle = args[0].toObject().as<TypedObject>();
+ TypedObject &target = args[1].toObject().as<TypedObject>();
+ JS_ASSERT(handle.typedMem() == nullptr); // must not be attached already
size_t offset = args[2].toInt32();
handle.attach(target, offset);
return true;
}
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::AttachHandleJitInfo, AttachHandleJitInfo,
- js::AttachHandle);
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::AttachTypedObjectJitInfo,
+ AttachTypedObjectJitInfo,
+ js::AttachTypedObject);
bool
js::ObjectIsTypeDescr(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 1);
+ JS_ASSERT(args.length() == 1);
JS_ASSERT(args[0].isObject());
args.rval().setBoolean(args[0].toObject().is<TypeDescr>());
return true;
}
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ObjectIsTypeDescrJitInfo, ObjectIsTypeDescrJitInfo,
js::ObjectIsTypeDescr);
bool
-js::ObjectIsTypeRepresentation(ThreadSafeContext *, unsigned argc, Value *vp)
+js::ObjectIsOpaqueTypedObject(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 1);
+ JS_ASSERT(args.length() == 1);
JS_ASSERT(args[0].isObject());
- args.rval().setBoolean(TypeRepresentation::isOwnerObject(args[0].toObject()));
- return true;
-}
-
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ObjectIsTypeRepresentationJitInfo,
- ObjectIsTypeRepresentationJitInfo,
- js::ObjectIsTypeRepresentation);
-
-bool
-js::ObjectIsTypedHandle(ThreadSafeContext *, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 1);
- JS_ASSERT(args[0].isObject());
- args.rval().setBoolean(args[0].toObject().is<TypedHandle>());
+ args.rval().setBoolean(args[0].toObject().is<OpaqueTypedObject>());
return true;
}
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ObjectIsTypedHandleJitInfo, ObjectIsTypedHandleJitInfo,
- js::ObjectIsTypedHandle);
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ObjectIsOpaqueTypedObjectJitInfo,
+ ObjectIsOpaqueTypedObjectJitInfo,
+ js::ObjectIsOpaqueTypedObject);
bool
-js::ObjectIsTypedObject(ThreadSafeContext *, unsigned argc, Value *vp)
+js::ObjectIsTransparentTypedObject(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 1);
+ JS_ASSERT(args.length() == 1);
JS_ASSERT(args[0].isObject());
- args.rval().setBoolean(args[0].toObject().is<TypedObject>());
+ args.rval().setBoolean(args[0].toObject().is<TransparentTypedObject>());
return true;
}
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ObjectIsTypedObjectJitInfo, ObjectIsTypedObjectJitInfo,
- js::ObjectIsTypedObject);
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ObjectIsTransparentTypedObjectJitInfo,
+ ObjectIsTransparentTypedObjectJitInfo,
+ js::ObjectIsTransparentTypedObject);
bool
-js::IsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp)
+js::TypedObjectIsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedDatum>());
- TypedDatum &datum = args[0].toObject().as<TypedDatum>();
- args.rval().setBoolean(datum.typedMem() != nullptr);
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());
+ TypedObject &typedObj = args[0].toObject().as<TypedObject>();
+ args.rval().setBoolean(typedObj.typedMem() != nullptr);
return true;
}
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::IsAttachedJitInfo, IsAttachedJitInfo, js::IsAttached);
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::TypedObjectIsAttachedJitInfo,
+ TypedObjectIsAttachedJitInfo,
+ js::TypedObjectIsAttached);
bool
js::ClampToUint8(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
- JS_ASSERT(argc == 1);
+ JS_ASSERT(args.length() == 1);
JS_ASSERT(args[0].isNumber());
args.rval().setNumber(ClampDoubleToUint8(args[0].toNumber()));
return true;
}
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ClampToUint8JitInfo, ClampToUint8JitInfo,
js::ClampToUint8);
bool
js::Memcpy(ThreadSafeContext *, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() == 5);
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedDatum>());
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());
JS_ASSERT(args[1].isInt32());
- JS_ASSERT(args[2].isObject() && args[2].toObject().is<TypedDatum>());
+ JS_ASSERT(args[2].isObject() && args[2].toObject().is<TypedObject>());
JS_ASSERT(args[3].isInt32());
JS_ASSERT(args[4].isInt32());
- TypedDatum &targetDatum = args[0].toObject().as<TypedDatum>();
+ TypedObject &targetTypedObj = args[0].toObject().as<TypedObject>();
int32_t targetOffset = args[1].toInt32();
- TypedDatum &sourceDatum = args[2].toObject().as<TypedDatum>();
+ TypedObject &sourceTypedObj = args[2].toObject().as<TypedObject>();
int32_t sourceOffset = args[3].toInt32();
int32_t size = args[4].toInt32();
JS_ASSERT(targetOffset >= 0);
JS_ASSERT(sourceOffset >= 0);
JS_ASSERT(size >= 0);
- JS_ASSERT((size_t) (size + targetOffset) <= targetDatum.size());
- JS_ASSERT((size_t) (size + sourceOffset) <= sourceDatum.size());
-
- uint8_t *target = targetDatum.typedMem(targetOffset);
- uint8_t *source = sourceDatum.typedMem(sourceOffset);
+ JS_ASSERT((size_t) (size + targetOffset) <= targetTypedObj.size());
+ JS_ASSERT((size_t) (size + sourceOffset) <= sourceTypedObj.size());
+
+ uint8_t *target = targetTypedObj.typedMem(targetOffset);
+ uint8_t *source = sourceTypedObj.typedMem(sourceOffset);
memcpy(target, source, size);
args.rval().setUndefined();
return true;
}
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::MemcpyJitInfo, MemcpyJitInfo, js::Memcpy);
bool
@@ -2590,104 +2791,107 @@ js::GetInt32x4TypeDescr(JSContext *cx, u
}
#define JS_STORE_SCALAR_CLASS_IMPL(_constant, T, _name) \
bool \
js::StoreScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \
{ \
CallArgs args = CallArgsFromVp(argc, vp); \
JS_ASSERT(args.length() == 3); \
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedDatum>()); \
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>()); \
JS_ASSERT(args[1].isInt32()); \
JS_ASSERT(args[2].isNumber()); \
\
- TypedDatum &datum = args[0].toObject().as<TypedDatum>(); \
+ TypedObject &typedObj = args[0].toObject().as<TypedObject>(); \
int32_t offset = args[1].toInt32(); \
\
/* Should be guaranteed by the typed objects API: */ \
JS_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
\
- T *target = reinterpret_cast<T*>(datum.typedMem(offset)); \
+ T *target = reinterpret_cast<T*>(typedObj.typedMem(offset)); \
double d = args[2].toNumber(); \
*target = ConvertScalar<T>(d); \
args.rval().setUndefined(); \
return true; \
} \
\
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::StoreScalar##T::JitInfo, StoreScalar##T, \
- js::StoreScalar##T::Func);
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::StoreScalar##T::JitInfo, \
+ StoreScalar##T, \
+ js::StoreScalar##T::Func);
#define JS_STORE_REFERENCE_CLASS_IMPL(_constant, T, _name) \
bool \
js::StoreReference##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \
{ \
CallArgs args = CallArgsFromVp(argc, vp); \
JS_ASSERT(args.length() == 3); \
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedDatum>()); \
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>()); \
JS_ASSERT(args[1].isInt32()); \
\
- TypedDatum &datum = args[0].toObject().as<TypedDatum>(); \
+ TypedObject &typedObj = args[0].toObject().as<TypedObject>(); \
int32_t offset = args[1].toInt32(); \
\
/* Should be guaranteed by the typed objects API: */ \
JS_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
\
- T *target = reinterpret_cast<T*>(datum.typedMem(offset)); \
+ T *target = reinterpret_cast<T*>(typedObj.typedMem(offset)); \
store(target, args[2]); \
args.rval().setUndefined(); \
return true; \
} \
\
- JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::StoreReference##T::JitInfo, StoreReference##T, \
- js::StoreReference##T::Func);
-
-#define JS_LOAD_SCALAR_CLASS_IMPL(_constant, T, _name) \
-bool \
-js::LoadScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \
-{ \
- CallArgs args = CallArgsFromVp(argc, vp); \
- JS_ASSERT(args.length() == 2); \
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedDatum>()); \
- JS_ASSERT(args[1].isInt32()); \
- \
- TypedDatum &datum = args[0].toObject().as<TypedDatum>(); \
- int32_t offset = args[1].toInt32(); \
- \
- /* Should be guaranteed by the typed objects API: */ \
- JS_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
- \
- T *target = reinterpret_cast<T*>(datum.typedMem(offset)); \
- args.rval().setNumber((double) *target); \
- return true; \
-} \
- \
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::LoadScalar##T::JitInfo, LoadScalar##T, \
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::StoreReference##T::JitInfo, \
+ StoreReference##T, \
+ js::StoreReference##T::Func);
+
+#define JS_LOAD_SCALAR_CLASS_IMPL(_constant, T, _name) \
+bool \
+js::LoadScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \
+{ \
+ CallArgs args = CallArgsFromVp(argc, vp); \
+ JS_ASSERT(args.length() == 2); \
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>()); \
+ JS_ASSERT(args[1].isInt32()); \
+ \
+ TypedObject &typedObj = args[0].toObject().as<TypedObject>(); \
+ int32_t offset = args[1].toInt32(); \
+ \
+ /* Should be guaranteed by the typed objects API: */ \
+ JS_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
+ \
+ T *target = reinterpret_cast<T*>(typedObj.typedMem(offset)); \
+ args.rval().setNumber((double) *target); \
+ return true; \
+} \
+ \
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::LoadScalar##T::JitInfo, LoadScalar##T, \
js::LoadScalar##T::Func);
#define JS_LOAD_REFERENCE_CLASS_IMPL(_constant, T, _name) \
bool \
js::LoadReference##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \
{ \
CallArgs args = CallArgsFromVp(argc, vp); \
JS_ASSERT(args.length() == 2); \
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedDatum>()); \
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>()); \
JS_ASSERT(args[1].isInt32()); \
\
- TypedDatum &datum = args[0].toObject().as<TypedDatum>(); \
+ TypedObject &typedObj = args[0].toObject().as<TypedObject>(); \
int32_t offset = args[1].toInt32(); \
\
/* Should be guaranteed by the typed objects API: */ \
JS_ASSERT(offset % MOZ_ALIGNOF(T) == 0); \
\
- T *target = reinterpret_cast<T*>(datum.typedMem(offset)); \
+ T *target = reinterpret_cast<T*>(typedObj.typedMem(offset)); \
load(target, args.rval()); \
return true; \
} \
\
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::LoadReference##T::JitInfo, LoadReference##T, \
+JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::LoadReference##T::JitInfo, \
+ LoadReference##T, \
js::LoadReference##T::Func);
// Because the precise syntax for storing values/objects/strings
// differs, we abstract it away using specialized variants of the
// private methods `store()` and `load()`.
void
StoreReferenceHeapValue::store(HeapValue *heap, const Value &v)
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef builtin_TypedObject_h
#define builtin_TypedObject_h
#include "jsobj.h"
#include "builtin/TypedObjectConstants.h"
+#include "vm/ArrayBufferObject.h"
/*
* -------------
* Typed Objects
* -------------
*
* Typed objects are a special kind of JS object where the data is
* given well-structured form. To use a typed object, users first
@@ -50,33 +51,43 @@
*
* Each type object is associated with a *type representation* (see
* TypeRepresentation.h). Type representations are canonical versions
* of type objects. We attach them to TI type objects and (eventually)
* use them for shape guards etc. They are purely internal to the
* engine and are not exposed to end users (though self-hosted code
* sometimes accesses them).
*
- * - Typed datums, objects, and handles:
+ * - Typed objects:
*
- * A typed object is an instance of a type object. A handle is a
- * relocatable pointer that points into other typed objects. Both of them
- * are basically represented the same way, though they have distinct
- * js::Class entries. They are both subtypes of `TypedDatum`.
+ * A typed object is an instance of a *type object* (note the past
+ * participle). There is one class for *transparent* typed objects and
+ * one for *opaque* typed objects. These classes are equivalent in
+ * basically every way, except that requesting the backing buffer of
+ * an opaque typed object yields null. We use distinct js::Classes to
+ * avoid the need for an extra slot in every typed object.
*
- * Both typed objects and handles are non-native objects that fully
- * override the property accessors etc. The overridden accessor
- * methods are the same in each and are defined in methods of
- * TypedDatum.
+ * Note that whether a typed object is opaque is not directly
+ * connected to its type. That is, opaque types are *always*
+ * represented by opaque typed objects, but you may have opaque typed
+ * objects for transparent types too. This can occur for two reasons:
+ * (1) a transparent type may be embedded within an opaque type or (2)
+ * users can choose to convert transparent typed objects into opaque
+ * ones to avoid giving access to the buffer itself.
*
- * Typed datums may be attached or unattached. An unattached typed
- * datum has no memory associated with it; it is basically a null
- * pointer. This can only happen when a new handle is created, since
- * typed object instances are always associated with memory at the
- * point of creation.
+ * Typed objects (no matter their class) are non-native objects that
+ * fully override the property accessors etc. The overridden accessor
+ * methods are the same in each and are defined in methods of
+ * TypedObject.
+ *
+ * Typed objects may be attached or unattached. An unattached typed
+ * object has no memory associated with it; it is basically a null
+ * pointer. When first created, objects are always attached, but they
+ * can become unattached if their buffer is neutered (note that this
+ * implies that typed objects of opaque types can never be unattached).
*
* When a new typed object instance is created, fresh memory is
* allocated and set as that typed object's private field. The object
* is then considered the *owner* of that memory: when the object is
* collected, its finalizer will free the memory. The fact that an
* object `o` owns its memory is indicated by setting its reserved
* slot JS_TYPEDOBJ_SLOT_OWNER to `o` (a trivial cycle, in other
* words).
@@ -139,45 +150,26 @@ class TypeDescr : public JSObject
JSObject &typeRepresentationOwnerObj() const {
return getReservedSlot(JS_DESCR_SLOT_TYPE_REPR).toObject();
}
TypeRepresentation *typeRepresentation() const;
TypeDescr::Kind kind() const;
-};
+
+ bool opaque() const;
-/*
- * This object exists in order to encapsulate the typed object types
- * somewhat, rather than sticking them all into the global object.
- * Eventually it will go away and become a module.
- */
-class TypedObjectModuleObject : public JSObject {
- public:
- enum Slot {
- ArrayTypePrototype,
- StructTypePrototype,
- SlotCount
- };
-
- static const Class class_;
-
- static bool getSuitableClaspAndProto(JSContext *cx,
- TypeDescr::Kind kind,
- const Class **clasp,
- MutableHandleObject proto);
+ size_t alignment() {
+ return getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
+ }
};
typedef Handle<TypeDescr*> HandleTypeDescr;
-bool InitializeCommonTypeDescriptorProperties(JSContext *cx,
- HandleTypeDescr obj,
- HandleObject typeReprOwnerObj);
-
class SizedTypeDescr : public TypeDescr
{
public:
size_t size() {
return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
}
};
@@ -298,16 +290,22 @@ class X4TypeDescr : public SizedTypeDesc
static bool call(JSContext *cx, unsigned argc, Value *vp);
static bool is(const Value &v);
};
#define JS_FOR_EACH_X4_TYPE_REPR(macro_) \
macro_(X4TypeDescr::TYPE_INT32, int32_t, int32) \
macro_(X4TypeDescr::TYPE_FLOAT32, float, float32)
+bool IsTypedObjectClass(const Class *clasp); // Defined in TypedArrayObject.h
+
+bool InitializeCommonTypeDescriptorProperties(JSContext *cx,
+ HandleTypeDescr obj,
+ HandleObject typeReprOwnerObj);
+
/*
* Properties and methods of the `ArrayType` meta type object. There
* is no `class_` field because `ArrayType` is just a native
* constructor function.
*/
class ArrayMetaTypeDescr : public JSObject
{
private:
@@ -427,41 +425,60 @@ class StructTypeDescr : public SizedType
// Return the offset of the field at index `index`.
size_t fieldOffset(size_t index);
};
typedef Handle<StructTypeDescr*> HandleStructTypeDescr;
/*
+ * This object exists in order to encapsulate the typed object types
+ * somewhat, rather than sticking them all into the global object.
+ * Eventually it will go away and become a module.
+ */
+class TypedObjectModuleObject : public JSObject {
+ public:
+ enum Slot {
+ ArrayTypePrototype,
+ StructTypePrototype,
+ SlotCount
+ };
+
+ static const Class class_;
+
+ static bool getSuitableClaspAndProto(JSContext *cx,
+ TypeDescr::Kind kind,
+ const Class **clasp,
+ MutableHandleObject proto);
+};
+
+/*
* Base type for typed objects and handles. Basically any type whose
* contents consist of typed memory.
*/
-class TypedDatum : public JSObject
+class TypedObject : public ArrayBufferViewObject
{
private:
- static const bool IsTypedDatumClass = true;
+ static const bool IsTypedObjectClass = true;
template<class T>
static bool obj_getArrayElement(JSContext *cx,
- Handle<TypedDatum*> datum,
+ Handle<TypedObject*> typedObj,
Handle<TypeDescr*> typeDescr,
uint32_t index,
MutableHandleValue vp);
template<class T>
static bool obj_setArrayElement(JSContext *cx,
- Handle<TypedDatum*> datum,
+ Handle<TypedObject*> typedObj,
Handle<TypeDescr*> typeDescr,
uint32_t index,
MutableHandleValue vp);
protected:
- static void obj_finalize(js::FreeOp *op, JSObject *obj);
-
static void obj_trace(JSTracer *trace, JSObject *object);
static bool obj_lookupGeneric(JSContext *cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp);
static bool obj_lookupProperty(JSContext *cx, HandleObject obj,
HandlePropertyName name,
@@ -533,66 +550,87 @@ class TypedDatum : public JSObject
// Each typed object contains a void* pointer pointing at the
// binary data that it represents. (That data may be owned by this
// object or this object may alias data owned by someone else.)
// This function returns the offset in bytes within the object
// where the `void*` pointer can be found. It is intended for use
// by the JIT.
static size_t dataOffset();
- static TypedDatum *createUnattachedWithClass(JSContext *cx,
+ // Helper for createUnattached()
+ static TypedObject *createUnattachedWithClass(JSContext *cx,
const Class *clasp,
HandleTypeDescr type,
int32_t length);
// Creates an unattached typed object or handle (depending on the
// type parameter T). Note that it is only legal for unattached
// handles to escape to the end user; for non-handles, the caller
// should always invoke one of the `attach()` methods below.
//
// Arguments:
// - type: type object for resulting object
// - length: 0 unless this is an array, otherwise the length
- template<class T>
- static T *createUnattached(JSContext *cx, HandleTypeDescr type,
- int32_t length);
+ static TypedObject *createUnattached(JSContext *cx, HandleTypeDescr type,
+ int32_t length);
- // Creates a datum that aliases the memory pointed at by `owner`
- // at the given offset. The datum will be a handle iff type is a
+ // Creates a typedObj that aliases the memory pointed at by `owner`
+ // at the given offset. The typedObj will be a handle iff type is a
// handle and a typed object otherwise.
- static TypedDatum *createDerived(JSContext *cx,
+ static TypedObject *createDerived(JSContext *cx,
HandleSizedTypeDescr type,
- Handle<TypedDatum*> typedContents,
+ Handle<TypedObject*> typedContents,
size_t offset);
+ // Creates a new typed object whose memory is freshly allocated
+ // and initialized with zeroes (or, in the case of references, an
+ // appropriate default value).
+ static TypedObject *createZeroed(JSContext *cx,
+ HandleTypeDescr typeObj,
+ int32_t length);
- // If `this` is the owner of the memory, use this.
- void attach(uint8_t *mem);
+ // User-accessible constructor (`new TypeDescriptor(...)`)
+ // used for sized types. Note that the callee here is the *type descriptor*,
+ // not the typedObj.
+ static bool constructSized(JSContext *cx, unsigned argc, Value *vp);
+
+ // As `constructSized`, but for unsized array types.
+ static bool constructUnsized(JSContext *cx, unsigned argc, Value *vp);
- // Otherwise, use this to attach to memory referenced by another datum.
- void attach(TypedDatum &datum, uint32_t offset);
+ // Use this method when `buffer` is the owner of the memory.
+ void attach(ArrayBufferObject &buffer, int32_t offset);
+
+ // Otherwise, use this to attach to memory referenced by another typedObj.
+ void attach(TypedObject &typedObj, int32_t offset);
- TypedDatum &owner() const {
- return getReservedSlot(JS_DATUM_SLOT_OWNER).toObject().as<TypedDatum>();
+ // Invoked when array buffer is transferred elsewhere
+ void neuter(JSContext *cx);
+
+ int32_t offset() const {
+ return getReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET).toInt32();
+ }
+
+ ArrayBufferObject &owner() const {
+ return getReservedSlot(JS_TYPEDOBJ_SLOT_OWNER).toObject().as<ArrayBufferObject>();
}
TypeDescr &typeDescr() const {
- return getReservedSlot(JS_DATUM_SLOT_TYPE_DESCR).toObject().as<TypeDescr>();
+ return getReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR).toObject().as<TypeDescr>();
}
TypeRepresentation *typeRepresentation() const {
return typeDescr().typeRepresentation();
}
uint8_t *typedMem() const {
return (uint8_t*) getPrivate();
}
size_t length() const {
- return getReservedSlot(JS_DATUM_SLOT_LENGTH).toInt32();
+ return getReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH).toInt32();
}
size_t size() const {
switch (typeDescr().kind()) {
case TypeDescr::Scalar:
case TypeDescr::X4:
case TypeDescr::Reference:
case TypeDescr::Struct:
@@ -613,113 +651,88 @@ class TypedDatum : public JSObject
// 0-sized value. (In other words, we maintain the invariant
// that `offset + size <= size()` -- this is always checked in
// the caller's side.)
JS_ASSERT(offset <= size());
return typedMem() + offset;
}
};
-typedef Handle<TypedDatum*> HandleTypedDatum;
+typedef Handle<TypedObject*> HandleTypedObject;
-class TypedObject : public TypedDatum
+class TransparentTypedObject : public TypedObject
{
public:
static const Class class_;
-
- // Creates a new typed object whose memory is freshly allocated
- // and initialized with zeroes (or, in the case of references, an
- // appropriate default value).
- static TypedObject *createZeroed(JSContext *cx,
- HandleTypeDescr typeObj,
- int32_t length);
-
- // user-accessible constructor (`new TypeDescriptor(...)`)
- static bool construct(JSContext *cx, unsigned argc, Value *vp);
};
-typedef Handle<TypedObject*> HandleTypedObject;
+typedef Handle<TransparentTypedObject*> HandleTransparentTypedObject;
-class TypedHandle : public TypedDatum
+class OpaqueTypedObject : public TypedObject
{
public:
static const Class class_;
static const JSFunctionSpec handleStaticMethods[];
};
/*
- * Usage: NewTypedHandle(typeObj)
+ * Usage: NewOpaqueTypedObject(typeObj)
*
* Constructs a new, unattached instance of `Handle`.
*/
-bool NewTypedHandle(JSContext *cx, unsigned argc, Value *vp);
+bool NewOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp);
/*
- * Usage: NewTypedHandle(typeObj)
+ * Usage: NewDerivedTypedObject(typeObj, owner, offset)
*
* Constructs a new, unattached instance of `Handle`.
*/
-bool NewTypedHandle(JSContext *cx, unsigned argc, Value *vp);
+bool NewDerivedTypedObject(JSContext *cx, unsigned argc, Value *vp);
/*
- * Usage: NewDerivedTypedDatum(typeObj, owner, offset)
+ * Usage: AttachTypedObject(typedObj, newDatum, newOffset)
*
- * Constructs a new, unattached instance of `Handle`.
- */
-bool NewDerivedTypedDatum(JSContext *cx, unsigned argc, Value *vp);
-
-/*
- * Usage: AttachHandle(handle, newOwner, newOffset)
- *
- * Moves `handle` to point at the memory owned by `newOwner` with
+ * Moves `typedObj` to point at the memory referenced by `newDatum` with
* the offset `newOffset`.
*/
-bool AttachHandle(ThreadSafeContext *cx, unsigned argc, Value *vp);
-extern const JSJitInfo AttachHandleJitInfo;
+bool AttachTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
+extern const JSJitInfo AttachTypedObjectJitInfo;
/*
* Usage: ObjectIsTypeDescr(obj)
*
* True if `obj` is a type object.
*/
bool ObjectIsTypeDescr(ThreadSafeContext *cx, unsigned argc, Value *vp);
extern const JSJitInfo ObjectIsTypeDescrJitInfo;
/*
- * Usage: ObjectIsTypeRepresentation(obj)
- *
- * True if `obj` is a type representation object.
- */
-bool ObjectIsTypeRepresentation(ThreadSafeContext *cx, unsigned argc, Value *vp);
-extern const JSJitInfo ObjectIsTypeRepresentationJitInfo;
-
-/*
- * Usage: ObjectIsTypedHandle(obj)
+ * Usage: ObjectIsOpaqueTypedObject(obj)
*
* True if `obj` is a handle.
*/
-bool ObjectIsTypedHandle(ThreadSafeContext *cx, unsigned argc, Value *vp);
-extern const JSJitInfo ObjectIsTypedHandleJitInfo;
+bool ObjectIsOpaqueTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
+extern const JSJitInfo ObjectIsOpaqueTypedObjectJitInfo;
/*
- * Usage: ObjectIsTypedObject(obj)
+ * Usage: ObjectIsTransparentTypedObject(obj)
*
* True if `obj` is a typed object.
*/
-bool ObjectIsTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
-extern const JSJitInfo ObjectIsTypedObjectJitInfo;
+bool ObjectIsTransparentTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
+extern const JSJitInfo ObjectIsTransparentTypedObjectJitInfo;
/*
- * Usage: IsAttached(obj)
+ * Usage: TypedObjectIsAttached(obj)
*
- * Given a TypedDatum `obj`, returns true if `obj` is
+ * Given a TypedObject `obj`, returns true if `obj` is
* "attached" (i.e., its data pointer is nullptr).
*/
-bool IsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp);
-extern const JSJitInfo IsAttachedJitInfo;
+bool TypedObjectIsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp);
+extern const JSJitInfo TypedObjectIsAttachedJitInfo;
/*
* Usage: ClampToUint8(v)
*
* Same as the C function ClampDoubleToUint8. `v` must be a number.
*/
bool ClampToUint8(ThreadSafeContext *cx, unsigned argc, Value *vp);
extern const JSJitInfo ClampToUint8JitInfo;
@@ -747,25 +760,25 @@ extern const JSJitInfo MemcpyJitInfo;
* to access them; eventually this should be linked into the module
* system.
*/
bool GetTypedObjectModule(JSContext *cx, unsigned argc, Value *vp);
/*
* Usage: GetFloat32x4TypeDescr()
*
- * Returns the float32x4 type object. SIMD pseudo-module must have
+ * Returns the float32x4 type object. SIMD pseudo-module must have
* been initialized for this to be safe.
*/
bool GetFloat32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp);
/*
* Usage: GetInt32x4TypeDescr()
*
- * Returns the int32x4 type object. SIMD pseudo-module must have
+ * Returns the int32x4 type object. SIMD pseudo-module must have
* been initialized for this to be safe.
*/
bool GetInt32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp);
/*
* Usage: Store_int8(targetDatum, targetOffset, value)
* ...
* Store_uint8(targetDatum, targetOffset, value)
@@ -846,16 +859,23 @@ class LoadReference##T {
// I was using templates for this stuff instead of macros, but ran
// into problems with the Unagi compiler.
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_STORE_SCALAR_CLASS_DEFN)
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_LOAD_SCALAR_CLASS_DEFN)
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_STORE_REFERENCE_CLASS_DEFN)
JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_DEFN)
+inline bool
+IsTypedObjectClass(const Class *class_)
+{
+ return class_ == &TransparentTypedObject::class_ ||
+ class_ == &OpaqueTypedObject::class_;
+}
+
} // namespace js
JSObject *
js_InitTypedObjectModuleObject(JSContext *cx, JS::HandleObject obj);
template <>
inline bool
JSObject::is<js::SimpleTypeDescr>() const
@@ -879,15 +899,15 @@ inline bool
JSObject::is<js::TypeDescr>() const
{
return is<js::SizedTypeDescr>() ||
is<js::UnsizedArrayTypeDescr>();
}
template <>
inline bool
-JSObject::is<js::TypedDatum>() const
+JSObject::is<js::TypedObject>() const
{
- return is<js::TypedObject>() || is<js::TypedHandle>();
+ return IsTypedObjectClass(getClass());
}
#endif /* builtin_TypedObject_h */
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -24,29 +24,33 @@
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_NAMES)
#define DESCR_STRUCT_FIELD_TYPES(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_TYPES)
#define DESCR_STRUCT_FIELD_OFFSETS(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS)
// Typed object slots
-#define DATUM_TYPE_DESCR(obj) \
- UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_TYPE_DESCR)
-#define DATUM_OWNER(obj) \
- UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_OWNER)
-#define DATUM_LENGTH(obj) \
- TO_INT32(UnsafeGetReservedSlot(obj, JS_DATUM_SLOT_LENGTH))
+#define TYPEDOBJ_BYTEOFFSET(obj) \
+ TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_BYTEOFFSET))
+#define TYPEDOBJ_BYTELENGTH(obj) \
+ TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_BYTELENGTH))
+#define TYPEDOBJ_TYPE_DESCR(obj) \
+ UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_TYPE_DESCR)
+#define TYPEDOBJ_OWNER(obj) \
+ UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_OWNER)
+#define TYPEDOBJ_LENGTH(obj) \
+ TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_LENGTH))
#define HAS_PROPERTY(obj, prop) \
callFunction(std_Object_hasOwnProperty, obj, prop)
-function DATUM_TYPE_REPR(obj) {
+function TYPEDOBJ_TYPE_REPR(obj) {
// Eventually this will be a slot on typed objects
- return DESCR_TYPE_REPR(DATUM_TYPE_DESCR(obj));
+ return DESCR_TYPE_REPR(TYPEDOBJ_TYPE_DESCR(obj));
}
///////////////////////////////////////////////////////////////////////////
// DescrToSource
//
// Converts a type descriptor to a descriptive string
// toSource() for type descriptors.
@@ -130,58 +134,58 @@ function DescrToSource(descr) {
}
///////////////////////////////////////////////////////////////////////////
// TypedObjectPointer
//
// TypedObjectPointers are internal structs used to represent a
// pointer into typed object memory. They pull together:
// - descr: the type descriptor
-// - datum: the typed object that contains the allocated block of memory
+// - typedObj: the typed object that contains the allocated block of memory
// - offset: an offset into that typed object
//
// They are basically equivalent to a typed object, except that they
// offer lots of internal unsafe methods and are not native objects.
// These should never escape into user code; ideally ion would stack
// allocate them.
//
// Most `TypedObjectPointers` methods are written in a "chaining"
// style, meaning that they return `this`. This is true even though
// they mutate the receiver in place, because it makes for prettier
// code.
-function TypedObjectPointer(descr, datum, offset) {
+function TypedObjectPointer(descr, typedObj, offset) {
assert(IsObject(descr) && ObjectIsTypeDescr(descr), "Not descr");
- assert(IsObject(datum) && ObjectIsTypedDatum(datum), "Not datum");
+ assert(IsObject(typedObj) && ObjectIsTypedObject(typedObj), "Not typedObj");
assert(TO_INT32(offset) === offset, "offset not int");
this.descr = descr;
- this.datum = datum;
+ this.typedObj = typedObj;
this.offset = offset;
}
MakeConstructible(TypedObjectPointer, {});
-TypedObjectPointer.fromTypedDatum = function(typed) {
- return new TypedObjectPointer(DATUM_TYPE_DESCR(typed), typed, 0);
+TypedObjectPointer.fromTypedObject = function(typed) {
+ return new TypedObjectPointer(TYPEDOBJ_TYPE_DESCR(typed), typed, 0);
}
#ifdef DEBUG
TypedObjectPointer.prototype.toString = function() {
return "Ptr(" + DescrToSource(this.descr) + " @ " + this.offset + ")";
};
#endif
TypedObjectPointer.prototype.copy = function() {
- return new TypedObjectPointer(this.descr, this.datum, this.offset);
+ return new TypedObjectPointer(this.descr, this.typedObj, this.offset);
};
TypedObjectPointer.prototype.reset = function(inPtr) {
this.descr = inPtr.descr;
- this.datum = inPtr.datum;
+ this.typedObj = inPtr.typedObj;
this.offset = inPtr.offset;
return this;
};
TypedObjectPointer.prototype.bump = function(size) {
assert(TO_INT32(this.offset) === this.offset, "current offset not int");
assert(TO_INT32(size) === size, "size not int");
this.offset += size;
@@ -194,17 +198,17 @@ TypedObjectPointer.prototype.kind = func
// Extract the length. This does a switch on kind, so it's
// best if we can avoid it.
TypedObjectPointer.prototype.length = function() {
switch (this.kind()) {
case JS_TYPEREPR_SIZED_ARRAY_KIND:
return DESCR_SIZED_ARRAY_LENGTH(this.descr);
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
- return this.datum.length;
+ return this.typedObj.length;
}
assert(false, "Invalid kind for length");
return false;
}
///////////////////////////////////////////////////////////////////////////
// Moving the pointer
//
@@ -219,33 +223,33 @@ TypedObjectPointer.prototype.moveTo = fu
case JS_TYPEREPR_REFERENCE_KIND:
case JS_TYPEREPR_X4_KIND:
break;
case JS_TYPEREPR_SIZED_ARRAY_KIND:
return this.moveToArray(propName, DESCR_SIZED_ARRAY_LENGTH(this.descr));
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
- return this.moveToArray(propName, this.datum.length);
+ return this.moveToArray(propName, this.typedObj.length);
case JS_TYPEREPR_STRUCT_KIND:
if (HAS_PROPERTY(this.descr.fieldTypes, propName))
return this.moveToField(propName);
break;
}
ThrowError(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, propName);
return undefined;
};
TypedObjectPointer.prototype.moveToArray = function(propName, length) {
// For an array, property must be an element. Note that we take
// the length as an argument rather than loading it from the descriptor.
// This is because this same helper is used for *unsized arrays*, where
- // the length is drawn from the datum, and *sized arrays*, where the
+ // the length is drawn from the typedObj, and *sized arrays*, where the
// length is drawn from the type.
var index = TO_INT32(propName);
if (index === propName && index >= 0 && index < length)
return this.moveToElem(index);
ThrowError(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, propName);
return undefined;
}
@@ -313,19 +317,19 @@ TypedObjectPointer.prototype.moveToField
//
// The methods in this section read from the memory pointed at
// by `this` and produce JS values. This process is called *reification*
// in the spec.
// Reifies the value referenced by the pointer, meaning that it
// returns a new object pointing at the value. If the value is
// a scalar, it will return a JS number, but otherwise the reified
-// result will be a datum of the same class as the ptr's datum.
+// result will be a typedObj of the same class as the ptr's typedObj.
TypedObjectPointer.prototype.get = function() {
- assert(ObjectIsAttached(this.datum), "get() called with unattached datum");
+ assert(TypedObjectIsAttached(this.typedObj), "get() called with unattached typedObj");
switch (this.kind()) {
case JS_TYPEREPR_SCALAR_KIND:
return this.getScalar();
case JS_TYPEREPR_REFERENCE_KIND:
return this.getReference();
@@ -342,113 +346,113 @@ TypedObjectPointer.prototype.get = funct
assert(false, "Unhandled kind: " + this.kind());
return undefined;
}
TypedObjectPointer.prototype.getDerived = function() {
assert(!TypeDescrIsSimpleType(this.descr),
"getDerived() used with simple type");
- return NewDerivedTypedDatum(this.descr, this.datum, this.offset);
+ return NewDerivedTypedObject(this.descr, this.typedObj, this.offset);
}
TypedObjectPointer.prototype.getScalar = function() {
var type = DESCR_TYPE(this.descr);
switch (type) {
case JS_SCALARTYPEREPR_INT8:
- return Load_int8(this.datum, this.offset);
+ return Load_int8(this.typedObj, this.offset);
case JS_SCALARTYPEREPR_UINT8:
case JS_SCALARTYPEREPR_UINT8_CLAMPED:
- return Load_uint8(this.datum, this.offset);
+ return Load_uint8(this.typedObj, this.offset);
case JS_SCALARTYPEREPR_INT16:
- return Load_int16(this.datum, this.offset);
+ return Load_int16(this.typedObj, this.offset);
case JS_SCALARTYPEREPR_UINT16:
- return Load_uint16(this.datum, this.offset);
+ return Load_uint16(this.typedObj, this.offset);
case JS_SCALARTYPEREPR_INT32:
- return Load_int32(this.datum, this.offset);
+ return Load_int32(this.typedObj, this.offset);
case JS_SCALARTYPEREPR_UINT32:
- return Load_uint32(this.datum, this.offset);
+ return Load_uint32(this.typedObj, this.offset);
case JS_SCALARTYPEREPR_FLOAT32:
- return Load_float32(this.datum, this.offset);
+ return Load_float32(this.typedObj, this.offset);
case JS_SCALARTYPEREPR_FLOAT64:
- return Load_float64(this.datum, this.offset);
+ return Load_float64(this.typedObj, this.offset);
}
assert(false, "Unhandled scalar type: " + type);
return undefined;
}
TypedObjectPointer.prototype.getReference = function() {
var type = DESCR_TYPE(this.descr);
switch (type) {
case JS_REFERENCETYPEREPR_ANY:
- return Load_Any(this.datum, this.offset);
+ return Load_Any(this.typedObj, this.offset);
case JS_REFERENCETYPEREPR_OBJECT:
- return Load_Object(this.datum, this.offset);
+ return Load_Object(this.typedObj, this.offset);
case JS_REFERENCETYPEREPR_STRING:
- return Load_string(this.datum, this.offset);
+ return Load_string(this.typedObj, this.offset);
}
assert(false, "Unhandled scalar type: " + type);
return undefined;
}
TypedObjectPointer.prototype.getX4 = function() {
var type = DESCR_TYPE(this.descr);
switch (type) {
case JS_X4TYPEREPR_FLOAT32:
- var x = Load_float32(this.datum, this.offset + 0);
- var y = Load_float32(this.datum, this.offset + 4);
- var z = Load_float32(this.datum, this.offset + 8);
- var w = Load_float32(this.datum, this.offset + 12);
+ var x = Load_float32(this.typedObj, this.offset + 0);
+ var y = Load_float32(this.typedObj, this.offset + 4);
+ var z = Load_float32(this.typedObj, this.offset + 8);
+ var w = Load_float32(this.typedObj, this.offset + 12);
return GetFloat32x4TypeDescr()(x, y, z, w);
case JS_X4TYPEREPR_INT32:
- var x = Load_int32(this.datum, this.offset + 0);
- var y = Load_int32(this.datum, this.offset + 4);
- var z = Load_int32(this.datum, this.offset + 8);
- var w = Load_int32(this.datum, this.offset + 12);
+ var x = Load_int32(this.typedObj, this.offset + 0);
+ var y = Load_int32(this.typedObj, this.offset + 4);
+ var z = Load_int32(this.typedObj, this.offset + 8);
+ var w = Load_int32(this.typedObj, this.offset + 12);
return GetInt32x4TypeDescr()(x, y, z, w);
}
assert(false, "Unhandled x4 type: " + type);
return undefined;
}
///////////////////////////////////////////////////////////////////////////
// Setting values
//
// The methods in this section modify the data pointed at by `this`.
// Assigns `fromValue` to the memory pointed at by `this`, adapting it
// to `typeRepr` as needed. This is the most general entry point and
// works for any type.
TypedObjectPointer.prototype.set = function(fromValue) {
- assert(ObjectIsAttached(this.datum), "set() called with unattached datum");
+ assert(TypedObjectIsAttached(this.typedObj), "set() called with unattached typedObj");
// Fast path: `fromValue` is a typed object with same type
// representation as the destination. In that case, we can just do a
// memcpy.
- if (IsObject(fromValue) && ObjectIsTypedDatum(fromValue)) {
+ if (IsObject(fromValue) && ObjectIsTypedObject(fromValue)) {
var typeRepr = DESCR_TYPE_REPR(this.descr);
- if (!typeRepr.variable && DATUM_TYPE_REPR(fromValue) === typeRepr) {
- if (!ObjectIsAttached(fromValue))
+ if (!typeRepr.variable && TYPEDOBJ_TYPE_REPR(fromValue) === typeRepr) {
+ if (!TypedObjectIsAttached(fromValue))
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
var size = DESCR_SIZE(this.descr);
- Memcpy(this.datum, this.offset, fromValue, 0, size);
+ Memcpy(this.typedObj, this.offset, fromValue, 0, size);
return;
}
}
switch (this.kind()) {
case JS_TYPEREPR_SCALAR_KIND:
this.setScalar(fromValue);
return;
@@ -462,17 +466,17 @@ TypedObjectPointer.prototype.set = funct
return;
case JS_TYPEREPR_SIZED_ARRAY_KIND:
if (this.setArray(fromValue, DESCR_SIZED_ARRAY_LENGTH(this.descr)))
return;
break;
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
- if (this.setArray(fromValue, this.datum.length))
+ if (this.setArray(fromValue, this.typedObj.length))
return;
break;
case JS_TYPEREPR_STRUCT_KIND:
if (!IsObject(fromValue))
break;
// Adapt each field.
@@ -514,66 +518,66 @@ TypedObjectPointer.prototype.setArray =
// Sets `fromValue` to `this` assuming that `this` is a scalar type.
TypedObjectPointer.prototype.setScalar = function(fromValue) {
assert(this.kind() == JS_TYPEREPR_SCALAR_KIND,
"setScalar called with non-scalar");
var type = DESCR_TYPE(this.descr);
switch (type) {
case JS_SCALARTYPEREPR_INT8:
- return Store_int8(this.datum, this.offset,
+ return Store_int8(this.typedObj, this.offset,
TO_INT32(fromValue) & 0xFF);
case JS_SCALARTYPEREPR_UINT8:
- return Store_uint8(this.datum, this.offset,
+ return Store_uint8(this.typedObj, this.offset,
TO_UINT32(fromValue) & 0xFF);
case JS_SCALARTYPEREPR_UINT8_CLAMPED:
var v = ClampToUint8(+fromValue);
- return Store_int8(this.datum, this.offset, v);
+ return Store_int8(this.typedObj, this.offset, v);
case JS_SCALARTYPEREPR_INT16:
- return Store_int16(this.datum, this.offset,
+ return Store_int16(this.typedObj, this.offset,
TO_INT32(fromValue) & 0xFFFF);
case JS_SCALARTYPEREPR_UINT16:
- return Store_uint16(this.datum, this.offset,
+ return Store_uint16(this.typedObj, this.offset,
TO_UINT32(fromValue) & 0xFFFF);
case JS_SCALARTYPEREPR_INT32:
- return Store_int32(this.datum, this.offset,
+ return Store_int32(this.typedObj, this.offset,
TO_INT32(fromValue));
case JS_SCALARTYPEREPR_UINT32:
- return Store_uint32(this.datum, this.offset,
+ return Store_uint32(this.typedObj, this.offset,
TO_UINT32(fromValue));
case JS_SCALARTYPEREPR_FLOAT32:
- return Store_float32(this.datum, this.offset, +fromValue);
+ return Store_float32(this.typedObj, this.offset, +fromValue);
case JS_SCALARTYPEREPR_FLOAT64:
- return Store_float64(this.datum, this.offset, +fromValue);
+ return Store_float64(this.typedObj, this.offset, +fromValue);
}
assert(false, "Unhandled scalar type: " + type);
return undefined;
}
TypedObjectPointer.prototype.setReference = function(fromValue) {
var type = DESCR_TYPE(this.descr);
switch (type) {
case JS_REFERENCETYPEREPR_ANY:
- return Store_Any(this.datum, this.offset, fromValue);
+ return Store_Any(this.typedObj, this.offset, fromValue);
case JS_REFERENCETYPEREPR_OBJECT:
var value = (fromValue === null ? fromValue : ToObject(fromValue));
- return Store_Object(this.datum, this.offset, value);
+ return Store_Object(this.typedObj, this.offset, value);
case JS_REFERENCETYPEREPR_STRING:
- return Store_string(this.datum, this.offset, ToString(fromValue));
+ return Store_string(this.typedObj, this.offset, ToString(fromValue));
}
assert(false, "Unhandled scalar type: " + type);
return undefined;
}
// Sets `fromValue` to `this` assuming that `this` is a scalar type.
TypedObjectPointer.prototype.setX4 = function(fromValue) {
@@ -588,76 +592,76 @@ TypedObjectPointer.prototype.setX4 = fun
///////////////////////////////////////////////////////////////////////////
// C++ Wrappers
//
// These helpers are invoked by C++ code or used as method bodies.
// Wrapper for use from C++ code.
function ConvertAndCopyTo(destDescr,
- destDatum,
+ destTypedObj,
destOffset,
fromValue)
{
assert(IsObject(destDescr) && ObjectIsTypeDescr(destDescr),
"ConvertAndCopyTo: not type obj");
- assert(IsObject(destDatum) && ObjectIsTypedDatum(destDatum),
- "ConvertAndCopyTo: not type datum");
+ assert(IsObject(destTypedObj) && ObjectIsTypedObject(destTypedObj),
+ "ConvertAndCopyTo: not type typedObj");
- if (!ObjectIsAttached(destDatum))
+ if (!TypedObjectIsAttached(destTypedObj))
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
- var ptr = new TypedObjectPointer(destDescr, destDatum, destOffset);
+ var ptr = new TypedObjectPointer(destDescr, destTypedObj, destOffset);
ptr.set(fromValue);
}
// Wrapper for use from C++ code.
function Reify(sourceDescr,
- sourceDatum,
+ sourceTypedObj,
sourceOffset) {
assert(IsObject(sourceDescr) && ObjectIsTypeDescr(sourceDescr),
"Reify: not type obj");
- assert(IsObject(sourceDatum) && ObjectIsTypedDatum(sourceDatum),
- "Reify: not type datum");
+ assert(IsObject(sourceTypedObj) && ObjectIsTypedObject(sourceTypedObj),
+ "Reify: not type typedObj");
- if (!ObjectIsAttached(sourceDatum))
+ if (!TypedObjectIsAttached(sourceTypedObj))
ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
- var ptr = new TypedObjectPointer(sourceDescr, sourceDatum, sourceOffset);
+ var ptr = new TypedObjectPointer(sourceDescr, sourceTypedObj, sourceOffset);
return ptr.get();
}
function FillTypedArrayWithValue(destArray, fromValue) {
- assert(IsObject(handle) && ObjectIsTypedDatum(destArray),
+ assert(IsObject(handle) && ObjectIsTypedObject(destArray),
"FillTypedArrayWithValue: not typed handle");
- var descr = DATUM_TYPE_DESCR(destArray);
+ var descr = TYPEDOBJ_TYPE_DESCR(destArray);
var length = DESCR_SIZED_ARRAY_LENGTH(descr);
if (length === 0)
return;
// Use convert and copy to to produce the first element:
- var ptr = TypedObjectPointer.fromTypedDatum(destArray);
+ var ptr = TypedObjectPointer.fromTypedObject(destArray);
ptr.moveToElem(0);
ptr.set(fromValue);
// Stamp out the remaining copies:
var elementSize = DESCR_SIZE(ptr.descr);
var totalSize = length * elementSize;
for (var offset = elementSize; offset < totalSize; offset += elementSize)
Memcpy(destArray, offset, destArray, 0, elementSize);
}
// Warning: user exposed!
function TypeDescrEquivalent(otherDescr) {
if (!IsObject(this) || !ObjectIsTypeDescr(this))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "type object");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (!IsObject(otherDescr) || !ObjectIsTypeDescr(otherDescr))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "1", "type object");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return DESCR_TYPE_REPR(this) === DESCR_TYPE_REPR(otherDescr);
}
// TypedArray.redimension(newArrayType)
//
// Method that "repackages" the data from this array into a new typed
// object whose type is `newArrayType`. Once you strip away all the
// outer array dimensions, the type of `this` array and `newArrayType`
@@ -672,39 +676,39 @@ function TypeDescrEquivalent(otherDescr)
// U[2][2][8]
// Because they all share the same total number (32) of equivalent elements.
// But it would be illegal to convert `T[32]` to `U[31]` or `U[2][17]`, since
// the number of elements differs. And it's just plain incompatible to convert
// if the base element types are not equivalent.
//
// Warning: user exposed!
function TypedArrayRedimension(newArrayType) {
- if (!IsObject(this) || !ObjectIsTypedDatum(this))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
+ if (!IsObject(this) || !ObjectIsTypedObject(this))
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (!IsObject(newArrayType) || !ObjectIsTypeDescr(newArrayType))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "type object");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
// Peel away the outermost array layers from the type of `this` to find
// the core element type. In the process, count the number of elements.
- var oldArrayType = DATUM_TYPE_DESCR(this);
+ var oldArrayType = TYPEDOBJ_TYPE_DESCR(this);
var oldArrayReprKind = DESCR_KIND(oldArrayType);
var oldElementType = oldArrayType;
var oldElementCount = 1;
switch (oldArrayReprKind) {
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
oldElementCount *= this.length;
oldElementType = oldElementType.elementType;
break;
case JS_TYPEREPR_SIZED_ARRAY_KIND:
break;
default:
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
while (DESCR_KIND(oldElementType) === JS_TYPEREPR_SIZED_ARRAY_KIND) {
oldElementCount *= oldElementType.length;
oldElementType = oldElementType.elementType;
}
// Peel away the outermost array layers from `newArrayType`. In the
// process, count the number of elements.
@@ -712,32 +716,30 @@ function TypedArrayRedimension(newArrayT
var newElementCount = 1;
while (DESCR_KIND(newElementType) == JS_TYPEREPR_SIZED_ARRAY_KIND) {
newElementCount *= newElementType.length;
newElementType = newElementType.elementType;
}
// Check that the total number of elements does not change.
if (oldElementCount !== newElementCount) {
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
- "New number of elements does not match old number of elements");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
// Check that the element types are equivalent.
if (DESCR_TYPE_REPR(oldElementType) !== DESCR_TYPE_REPR(newElementType)) {
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1,
- "New element type is not equivalent to old element type");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
// Together, this should imply that the sizes are unchanged.
assert(DESCR_SIZE(oldArrayType) == DESCR_SIZE(newArrayType),
"Byte sizes should be equal");
// Rewrap the data from `this` in a new type.
- return NewDerivedTypedDatum(newArrayType, this, 0);
+ return NewDerivedTypedObject(newArrayType, this, 0);
}
///////////////////////////////////////////////////////////////////////////
// X4
function X4ProtoString(type) {
switch (type) {
case JS_X4TYPEREPR_INT32:
@@ -746,54 +748,74 @@ function X4ProtoString(type) {
return "float32x4";
}
assert(false, "Unhandled type constant");
return undefined;
}
function X4ToSource() {
- if (!IsObject(this) || !ObjectIsTypedDatum(this))
+ if (!IsObject(this) || !ObjectIsTypedObject(this))
ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
if (DESCR_KIND(this) != JS_TYPEREPR_X4_KIND)
ThrowError(JSMSG_INCOMPATIBLE_PROTO, "X4", "toSource", typeof this);
- var descr = DATUM_TYPE_DESCR(this);
+ var descr = TYPEDOBJ_TYPE_DESCR(this);
var type = DESCR_TYPE(descr);
return X4ProtoString(type)+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
}
///////////////////////////////////////////////////////////////////////////
// Miscellaneous
// Warning: user exposed!
function ArrayShorthand(...dims) {
if (!IsObject(this) || !ObjectIsTypeDescr(this))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS,
- "this", "typed object");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
var T = GetTypedObjectModule();
if (dims.length == 0)
return new T.ArrayType(this);
var accum = this;
for (var i = dims.length - 1; i >= 0; i--)
accum = new T.ArrayType(accum).dimension(dims[i]);
return accum;
}
+// This is the `storage()` function defined in the spec. When
+// provided with a *transparent* typed object, it returns an object
+// containing buffer, byteOffset, byteLength. When given an opaque
+// typed object, it returns null. Otherwise it throws.
+//
+// Warning: user exposed!
+function StorageOfTypedObject(obj) {
+ if (IsObject(obj)) {
+ if (ObjectIsOpaqueTypedObject(obj))
+ return null;
+
+ if (ObjectIsTransparentTypedObject(obj))
+ return { buffer: TYPEDOBJ_OWNER(obj),
+ byteLength: TYPEDOBJ_BYTELENGTH(obj),
+ byteOffset: TYPEDOBJ_BYTEOFFSET(obj) };
+ }
+
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
+ return null; // pacify silly "always returns a value" lint
+}
+
// This is the `objectType()` function defined in the spec.
// It returns the type of its argument.
//
// Warning: user exposed!
-function TypeOfTypedDatum(obj) {
- if (IsObject(obj) && ObjectIsTypedDatum(obj))
- return DATUM_TYPE_DESCR(obj);
+function TypeOfTypedObject(obj) {
+ if (IsObject(obj) && ObjectIsTypedObject(obj))
+ return TYPEDOBJ_TYPE_DESCR(obj);
// Note: Do not create bindings for `Any`, `String`, etc in
// Utilities.js, but rather access them through
// `GetTypedObjectModule()`. The reason is that bindings
// you create in Utilities.js are part of the self-hosted global,
// vs the user-accessible global, and hence should not escape to
// user script.
var T = GetTypedObjectModule();
@@ -802,163 +824,156 @@ function TypeOfTypedDatum(obj) {
case "function": return T.Object;
case "string": return T.String;
case "number": return T.float64;
case "undefined": return T.Any;
default: return T.Any;
}
}
-function ObjectIsTypedDatum(obj) {
- assert(IsObject(obj), "ObjectIsTypedDatum invoked with non-object")
- return ObjectIsTypedObject(obj) || ObjectIsTypedHandle(obj);
-}
-
-function ObjectIsAttached(obj) {
- assert(IsObject(obj), "ObjectIsAttached invoked with non-object")
- assert(ObjectIsTypedDatum(obj),
- "ObjectIsAttached() invoked on invalid obj");
- return DATUM_OWNER(obj) != null;
+function ObjectIsTypedObject(obj) {
+ assert(IsObject(obj), "ObjectIsTypedObject invoked with non-object")
+ return ObjectIsTransparentTypedObject(obj) || ObjectIsOpaqueTypedObject(obj);
}
///////////////////////////////////////////////////////////////////////////
// TypedObject surface API methods (sequential implementations).
// Warning: user exposed!
function TypedObjectArrayTypeBuild(a,b,c) {
// Arguments (this sized) : [depth], func
// Arguments (this unsized) : length, [depth], func
if (!IsObject(this) || !ObjectIsTypeDescr(this))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "type object");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
var kind = DESCR_KIND(this);
switch (kind) {
case JS_TYPEREPR_SIZED_ARRAY_KIND:
if (typeof a === "function") // XXX here and elsewhere: these type dispatches are fragile at best.
return BuildTypedSeqImpl(this, this.length, 1, a);
else if (typeof a === "number" && typeof b === "function")
return BuildTypedSeqImpl(this, this.length, a, b);
else if (typeof a === "number")
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "2", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
else
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "1", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
var len = a;
if (typeof b === "function")
return BuildTypedSeqImpl(this, len, 1, b);
else if (typeof b === "number" && typeof c === "function")
return BuildTypedSeqImpl(this, len, b, c);
else if (typeof b === "number")
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "3", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
else
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "2", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
default:
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "type object");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
}
// Warning: user exposed!
function TypedObjectArrayTypeFrom(a, b, c) {
// Arguments: arrayLike, [depth], func
if (!IsObject(this) || !ObjectIsTypeDescr(this))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "type object");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
- var untypedInput = !IsObject(a) || !ObjectIsTypedDatum(a);
+ var untypedInput = !IsObject(a) || !ObjectIsTypedObject(a);
// for untyped input array, the expectation (in terms of error
// reporting for invalid parameters) is no-depth, despite
// supporting an explicit depth of 1; while for typed input array,
// the expectation is explicit depth.
if (untypedInput) {
var explicitDepth = (b === 1);
if (explicitDepth && IsCallable(c))
return MapUntypedSeqImpl(a, this, c);
else if (IsCallable(b))
return MapUntypedSeqImpl(a, this, b);
else
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "2", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
} else {
var explicitDepth = (typeof b === "number");
if (explicitDepth && IsCallable(c))
return MapTypedSeqImpl(a, b, this, c);
else if (IsCallable(b))
return MapTypedSeqImpl(a, 1, this, b);
else if (explicitDepth)
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "3", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
else
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "2", "number");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
}
// Warning: user exposed!
function TypedArrayMap(a, b) {
- if (!IsObject(this) || !ObjectIsTypedDatum(this))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
- var thisType = DATUM_TYPE_DESCR(this);
+ if (!IsObject(this) || !ObjectIsTypedObject(this))
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
+ var thisType = TYPEDOBJ_TYPE_DESCR(this);
if (!TypeDescrIsArrayType(thisType))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
// Arguments: [depth], func
if (typeof a === "number" && typeof b === "function")
return MapTypedSeqImpl(this, a, thisType, b);
else if (typeof a === "function")
return MapTypedSeqImpl(this, 1, thisType, a);
else if (typeof a === "number")
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "3", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
else
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "2", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
// Warning: user exposed!
function TypedArrayReduce(a, b) {
// Arguments: func, [initial]
- if (!IsObject(this) || !ObjectIsTypedDatum(this))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
- var thisType = DATUM_TYPE_DESCR(this);
+ if (!IsObject(this) || !ObjectIsTypedObject(this))
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
+ var thisType = TYPEDOBJ_TYPE_DESCR(this);
if (!TypeDescrIsArrayType(thisType))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (a !== undefined && typeof a !== "function")
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "1", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
var outputType = thisType.elementType;
return ReduceTypedSeqImpl(this, outputType, a, b);
}
// Warning: user exposed!
function TypedArrayScatter(a, b, c, d) {
// Arguments: outputArrayType, indices, defaultValue, conflictFunction
- if (!IsObject(this) || !ObjectIsTypedDatum(this))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
- var thisType = DATUM_TYPE_DESCR(this);
+ if (!IsObject(this) || !ObjectIsTypedObject(this))
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
+ var thisType = TYPEDOBJ_TYPE_DESCR(this);
if (!TypeDescrIsArrayType(thisType))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (!IsObject(a) || !ObjectIsTypeDescr(a) || !TypeDescrIsSizedArrayType(a))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "1", "sized array type");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (d !== undefined && typeof d !== "function")
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "4", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return ScatterTypedSeqImpl(this, a, b, c, d);
}
// Warning: user exposed!
function TypedArrayFilter(func) {
// Arguments: predicate
- if (!IsObject(this) || !ObjectIsTypedDatum(this))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
- var thisType = DATUM_TYPE_DESCR(this);
+ if (!IsObject(this) || !ObjectIsTypedObject(this))
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
+ var thisType = TYPEDOBJ_TYPE_DESCR(this);
if (!TypeDescrIsArrayType(thisType))
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
if (typeof func !== "function")
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "1", "function");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
return FilterTypedSeqImpl(this, func);
}
// placeholders
// Warning: user exposed!
function TypedObjectArrayTypeBuildPar(a,b,c) {
@@ -1014,17 +1029,17 @@ function TypeDescrIsArrayType(t) {
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
return true;
case JS_TYPEREPR_SCALAR_KIND:
case JS_TYPEREPR_REFERENCE_KIND:
case JS_TYPEREPR_X4_KIND:
case JS_TYPEREPR_STRUCT_KIND:
return false;
default:
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "unknown kind of typed object");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
}
function TypeDescrIsSizedArrayType(t) {
assert(IsObject(t) && ObjectIsTypeDescr(t), "TypeDescrIsSizedArrayType called on non-type-object");
var kind = DESCR_KIND(t);
switch (kind) {
@@ -1032,17 +1047,17 @@ function TypeDescrIsSizedArrayType(t) {
return true;
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
case JS_TYPEREPR_SCALAR_KIND:
case JS_TYPEREPR_REFERENCE_KIND:
case JS_TYPEREPR_X4_KIND:
case JS_TYPEREPR_STRUCT_KIND:
return false;
default:
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "unknown kind of typed object");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
}
function TypeDescrIsSimpleType(t) {
assert(IsObject(t) && ObjectIsTypeDescr(t), "TypeDescrIsSimpleType called on non-type-object");
var kind = DESCR_KIND(t);
switch (kind) {
@@ -1050,27 +1065,27 @@ function TypeDescrIsSimpleType(t) {
case JS_TYPEREPR_REFERENCE_KIND:
case JS_TYPEREPR_X4_KIND:
return true;
case JS_TYPEREPR_SIZED_ARRAY_KIND:
case JS_TYPEREPR_UNSIZED_ARRAY_KIND:
case JS_TYPEREPR_STRUCT_KIND:
return false;
default:
- return ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "unknown kind of typed object");
+ return ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
}
}
// Bug 956914: make performance-tuned variants tailored to 1, 2, and 3 dimensions.
function BuildTypedSeqImpl(arrayType, len, depth, func) {
assert(IsObject(arrayType) && ObjectIsTypeDescr(arrayType), "Build called on non-type-object");
if (depth <= 0 || TO_INT32(depth) !== depth)
// RangeError("bad depth")
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "depth", "positive int");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
// For example, if we have as input
// ArrayType(ArrayType(T, 4), 5)
// and a depth of 2, we get
// grainType = T
// iterationSpace = [5, 4]
var [iterationSpace, grainType, totalLength] =
ComputeIterationSpace(arrayType, depth, len);
@@ -1205,28 +1220,28 @@ function MapUntypedSeqImpl(inArray, outp
}
return result;
}
// Implements |map| and |from| methods for typed |inArray|.
function MapTypedSeqImpl(inArray, depth, outputType, func) {
assert(IsObject(outputType) && ObjectIsTypeDescr(outputType), "2. Map/From called on non-type-object outputType");
- assert(IsObject(inArray) && ObjectIsTypedDatum(inArray), "Map/From called on non-object or untyped input array.");
+ assert(IsObject(inArray) && ObjectIsTypedObject(inArray), "Map/From called on non-object or untyped input array.");
assert(TypeDescrIsArrayType(outputType), "Map/From called on non array-type outputType");
if (depth <= 0 || TO_INT32(depth) !== depth)
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "depth", "positive int");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
// Compute iteration space for input and output and check for compatibility.
- var inputType = TypeOfTypedDatum(inArray);
+ var inputType = TypeOfTypedObject(inArray);
var [inIterationSpace, inGrainType, _] =
ComputeIterationSpace(inputType, depth, inArray.length);
if (!IsObject(inGrainType) || !ObjectIsTypeDescr(inGrainType))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 1, "type object");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
var [iterationSpace, outGrainType, totalLength] =
ComputeIterationSpace(outputType, depth, outputType.variable ? inArray.length : outputType.length);
for (var i = 0; i < depth; i++)
if (inIterationSpace[i] !== iterationSpace[i])
// TypeError("Incompatible iteration space in input and output type");
ThrowError(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS);
// Create a zeroed instance with no data
@@ -1293,17 +1308,17 @@ function MapTypedSeqImpl(inArray, depth,
return DoMapTypedSeqDepth1();
} else {
return DoMapTypedSeqDepthN();
}
}
function ReduceTypedSeqImpl(array, outputType, func, initial) {
- assert(IsObject(array) && ObjectIsTypedDatum(array), "Reduce called on non-object or untyped input array.");
+ assert(IsObject(array) && ObjectIsTypedObject(array), "Reduce called on non-object or untyped input array.");
assert(IsObject(outputType) && ObjectIsTypeDescr(outputType), "Reduce called on non-type-object outputType");
var start, value;
if (initial === undefined && array.length < 1)
// RangeError("reduce requires array of length > 0")
ThrowError(JSMSG_TYPEDOBJECT_ARRAYTYPE_BAD_ARGS);
@@ -1334,17 +1349,17 @@ function ReduceTypedSeqImpl(array, outpu
for (var i = start; i < array.length; i++)
value = func(value, array[i]);
}
return value;
}
function ScatterTypedSeqImpl(array, outputType, indices, defaultValue, conflictFunc) {
- assert(IsObject(array) && ObjectIsTypedDatum(array), "Scatter called on non-object or untyped input array.");
+ assert(IsObject(array) && ObjectIsTypedObject(array), "Scatter called on non-object or untyped input array.");
assert(IsObject(outputType) && ObjectIsTypeDescr(outputType), "Scatter called on non-type-object outputType");
assert(TypeDescrIsSizedArrayType(outputType), "Scatter called on non-sized array type");
assert(conflictFunc === undefined || typeof conflictFunc === "function", "Scatter called with invalid conflictFunc");
var result = new outputType();
var bitvec = new Uint8Array(result.length);
var elemType = outputType.elementType;
var i, j;
@@ -1364,22 +1379,22 @@ function ScatterTypedSeqImpl(array, outp
} else {
result[j] = conflictFunc(result[j], elemType(array[i]));
}
}
return result;
}
function FilterTypedSeqImpl(array, func) {
- assert(IsObject(array) && ObjectIsTypedDatum(array), "Filter called on non-object or untyped input array.");
+ assert(IsObject(array) && ObjectIsTypedObject(array), "Filter called on non-object or untyped input array.");
assert(typeof func === "function", "Filter called with non-function predicate");
- var arrayType = TypeOfTypedDatum(array);
+ var arrayType = TypeOfTypedObject(array);
if (!TypeDescrIsArrayType(arrayType))
- ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, "this", "typed array");
+ ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
var elementType = arrayType.elementType;
var flags = new Uint8Array(NUM_BYTES(array.length));
var count = 0;
var size = DESCR_SIZE(elementType);
var inPointer = new TypedObjectPointer(elementType, array, 0);
for (var i = 0; i < array.length; i++) {
if (func(inPointer.get(), i, array)) {
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -14,18 +14,18 @@
//
// Some slots apply to all type objects and some are specific to
// particular kinds of type objects. For simplicity we use the same
// number of slots no matter what kind of type descriptor we are
// working with, even though this is mildly wasteful.
// Slots on all type objects
#define JS_DESCR_SLOT_TYPE_REPR 0 // Associated Type Representation
-#define JS_DESCR_SLOT_SIZE 1 // Size in bytes, if sized
-#define JS_DESCR_SLOT_ALIGNMENT 2 // Alignment in bytes, if sized
+#define JS_DESCR_SLOT_ALIGNMENT 1 // Alignment in bytes
+#define JS_DESCR_SLOT_SIZE 2 // Size in bytes, if sized, else 0
// Slots on scalars, references, and x4s
#define JS_DESCR_SLOT_TYPE 3 // Type code
// Slots on all array descriptors
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 3
// Slots on sized array descriptors
@@ -98,21 +98,30 @@
// These constants are for use exclusively in JS code. In C++ code,
// prefer X4TypeRepresentation::TYPE_INT32 etc, since that allows
// you to write a switch which will receive a warning if you omit a
// case.
#define JS_X4TYPEREPR_INT32 0
#define JS_X4TYPEREPR_FLOAT32 1
///////////////////////////////////////////////////////////////////////////
-// Slots for typed objects (actually, any TypedContents objects)
+// Slots for typed objects
+
+#define JS_TYPEDOBJ_SLOT_BYTEOFFSET 0
+#define JS_TYPEDOBJ_SLOT_BYTELENGTH 1
+#define JS_TYPEDOBJ_SLOT_OWNER 2
+#define JS_TYPEDOBJ_SLOT_NEXT_VIEW 3
+#define JS_TYPEDOBJ_SLOT_NEXT_BUFFER 4
+
+#define JS_DATAVIEW_SLOTS 5 // Number of slots for data views
-#define JS_DATUM_SLOT_TYPE_DESCR 0 // Type descr for a given typed object
-#define JS_DATUM_SLOT_OWNER 1 // Owner of data (if null, this is owner)
-#define JS_DATUM_SLOT_LENGTH 2 // Length of array (see (*) below)
-#define JS_DATUM_SLOTS 3 // Number of slots for typed objs
+#define JS_TYPEDOBJ_SLOT_LENGTH 5 // Length of array (see (*) below)
+#define JS_TYPEDOBJ_SLOT_TYPE_DESCR 6 // For typed objects, type descr
-// (*) The JS_DATUM_SLOT_LENGTH slot stores the length for datums of
+#define JS_TYPEDOBJ_SLOT_DATA 7 // private slot, based on alloc kind
+#define JS_TYPEDOBJ_SLOTS 7 // Number of slots for typed objs
+
+// (*) The JS_TYPEDOBJ_SLOT_LENGTH slot stores the length for typed objects of
// sized and unsized array type. The slot contains 0 for non-arrays.
-// The slot also contains 0 for *unattached* datums, no matter what
+// The slot also contains 0 for *unattached* typed objects, no matter what
// type they have.
#endif
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobj.js
@@ -0,0 +1,32 @@
+if (!this.hasOwnProperty("TypedObject"))
+ quit();
+
+var {StructType, uint32, storage} = TypedObject;
+var S = new StructType({f: uint32, g: uint32});
+
+function readFromS(s) {
+ return s.f + s.g;
+}
+
+function main() {
+ var s = new S({f: 22, g: 44});
+
+ for (var i = 0; i < 10; i++)
+ assertEq(readFromS(s), 66);
+
+ neuter(storage(s).buffer);
+
+ for (var i = 0; i < 10; i++) {
+ var ok = false;
+
+ try {
+ readFromS(s);
+ } catch (e) {
+ ok = e instanceof TypeError;
+ }
+
+ assertEq(ok, true);
+ }
+}
+
+main();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobjsizedarray.js
@@ -0,0 +1,40 @@
+// Test the case where we neuter an instance of a fixed-sized array.
+// This is a bit of a tricky case because we cannot (necessarily) fold
+// the neuter check into the bounds check, as we obtain the bounds
+// directly from the type.
+
+if (!this.hasOwnProperty("TypedObject"))
+ quit();
+
+var {StructType, uint32, storage} = TypedObject;
+var S = new StructType({f: uint32, g: uint32});
+var A = S.array(10);
+
+function readFrom(a) {
+ return a[2].f + a[2].g;
+}
+
+function main() {
+ var a = new A();
+ a[2].f = 22;
+ a[2].g = 44;
+
+ for (var i = 0; i < 10; i++)
+ assertEq(readFrom(a), 66);
+
+ neuter(storage(a).buffer);
+
+ for (var i = 0; i < 10; i++) {
+ var ok = false;
+
+ try {
+ readFrom(a);
+ } catch (e) {
+ ok = e instanceof TypeError;
+ }
+
+ assertEq(ok, true);
+ }
+}
+
+main();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobjunsizedarray.js
@@ -0,0 +1,38 @@
+// Test the case where we neuter an instance of a variable-length array.
+// Here we can fold the neuter check into the bounds check.
+
+if (!this.hasOwnProperty("TypedObject"))
+ quit();
+
+var {StructType, uint32, storage} = TypedObject;
+var S = new StructType({f: uint32, g: uint32});
+var A = S.array();
+
+function readFrom(a) {
+ return a[2].f + a[2].g;
+}
+
+function main() {
+ var a = new A(10);
+ a[2].f = 22;
+ a[2].g = 44;
+
+ for (var i = 0; i < 10; i++)
+ assertEq(readFrom(a), 66);
+
+ neuter(storage(a).buffer);
+
+ for (var i = 0; i < 10; i++) {
+ var ok = false;
+
+ try {
+ readFrom(a);
+ } catch (e) {
+ ok = e instanceof TypeError;
+ }
+
+ assertEq(ok, true);
+ }
+}
+
+main();
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4079,16 +4079,28 @@ CodeGenerator::visitTypedArrayElements(L
{
Register obj = ToRegister(lir->object());
Register out = ToRegister(lir->output());
masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), out);
return true;
}
bool
+CodeGenerator::visitNeuterCheck(LNeuterCheck *lir)
+{
+ Register obj = ToRegister(lir->object());
+ Register temp = ToRegister(lir->temp());
+ masm.loadPtr(Address(obj, TypedObject::dataOffset()), temp);
+ masm.testPtr(temp, temp);
+ if (!bailoutIf(Assembler::Zero, lir->snapshot()))
+ return false;
+ return true;
+}
+
+bool
CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
{
Register obj = ToRegister(lir->object());
Register out = ToRegister(lir->output());
masm.loadPtr(Address(obj, TypedObject::dataOffset()), out);
return true;
}
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -159,16 +159,17 @@ class CodeGenerator : public CodeGenerat
bool visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir);
bool visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir);
bool visitReturnFromCtor(LReturnFromCtor *lir);
bool visitComputeThis(LComputeThis *lir);
bool visitArrayLength(LArrayLength *lir);
bool visitSetArrayLength(LSetArrayLength *lir);
bool visitTypedArrayLength(LTypedArrayLength *lir);
bool visitTypedArrayElements(LTypedArrayElements *lir);
+ bool visitNeuterCheck(LNeuterCheck *lir);
bool visitTypedObjectElements(LTypedObjectElements *lir);
bool visitStringLength(LStringLength *lir);
bool visitInitializedLength(LInitializedLength *lir);
bool visitSetInitializedLength(LSetInitializedLength *lir);
bool visitNotO(LNotO *ins);
bool visitNotV(LNotV *ins);
bool visitBoundsCheck(LBoundsCheck *lir);
bool visitBoundsCheckRange(LBoundsCheckRange *lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6606,39 +6606,49 @@ IonBuilder::getElemTryTypedObject(bool *
static MIRType
MIRTypeForTypedArrayRead(ScalarTypeDescr::Type arrayType,
bool observedDouble);
bool
IonBuilder::checkTypedObjectIndexInBounds(size_t elemSize,
MDefinition *obj,
MDefinition *index,
+ TypeDescrSet objDescrs,
MDefinition **indexAsByteOffset,
- TypeDescrSet objDescrs)
+ bool *canBeNeutered)
{
// Ensure index is an integer.
MInstruction *idInt32 = MToInt32::New(alloc(), index);
current->add(idInt32);
// If we know the length statically from the type, just embed it.
// Otherwise, load it from the appropriate reserved slot on the
// typed object. We know it's an int32, so we can convert from
// Value to int32 using truncation.
size_t lenOfAll;
MDefinition *length;
if (objDescrs.hasKnownArrayLength(&lenOfAll)) {
length = constantInt(lenOfAll);
+
+ // If we are not loading the length from the object itself,
+ // then we still need to check if the object was neutered.
+ *canBeNeutered = true;
} else {
- MInstruction *lengthValue = MLoadFixedSlot::New(alloc(), obj, JS_DATUM_SLOT_LENGTH);
+ MInstruction *lengthValue = MLoadFixedSlot::New(alloc(), obj, JS_TYPEDOBJ_SLOT_LENGTH);
current->add(lengthValue);
MInstruction *length32 = MTruncateToInt32::New(alloc(), lengthValue);
current->add(length32);
length = length32;
+
+ // If we are loading the length from the object itself,
+ // then we do not need an extra neuter check, because the length
+ // will have been set to 0 when the object was neutered.
+ *canBeNeutered = false;
}
index = addBoundsCheck(idInt32, length);
// Since we passed the bounds check, it is impossible for the
// result of multiplication to overflow; so enable imul path.
MMul *mul = MMul::New(alloc(), index, constantInt(elemSize),
MIRType_Int32, MMul::Integer);
@@ -6659,35 +6669,41 @@ IonBuilder::getElemTryScalarElemOfTypedO
JS_ASSERT(objDescrs.allOfArrayKind());
// Must always be loading the same scalar type
ScalarTypeDescr::Type elemType;
if (!elemDescrs.scalarType(&elemType))
return true;
JS_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
+ bool canBeNeutered;
MDefinition *indexAsByteOffset;
- if (!checkTypedObjectIndexInBounds(elemSize, obj, index, &indexAsByteOffset, objDescrs))
- return false;
-
- return pushScalarLoadFromTypedObject(emitted, obj, indexAsByteOffset, elemType);
+ if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objDescrs,
+ &indexAsByteOffset, &canBeNeutered))
+ {
+ return false;
+ }
+
+ return pushScalarLoadFromTypedObject(emitted, obj, indexAsByteOffset, elemType, canBeNeutered);
}
bool
IonBuilder::pushScalarLoadFromTypedObject(bool *emitted,
MDefinition *obj,
MDefinition *offset,
- ScalarTypeDescr::Type elemType)
+ ScalarTypeDescr::Type elemType,
+ bool canBeNeutered)
{
size_t size = ScalarTypeDescr::size(elemType);
JS_ASSERT(size == ScalarTypeDescr::alignment(elemType));
// Find location within the owner object.
MDefinition *elements, *scaledOffset;
- loadTypedObjectElements(obj, offset, size, &elements, &scaledOffset);
+ loadTypedObjectElements(obj, offset, size, canBeNeutered,
+ &elements, &scaledOffset);
// Load the element.
MLoadTypedArrayElement *load = MLoadTypedArrayElement::New(alloc(), elements, scaledOffset, elemType);
current->add(load);
current->push(load);
// If we are reading in-bounds elements, we can use knowledge about
// the array type to determine the result type, even if the opcode has
@@ -6718,36 +6734,41 @@ IonBuilder::getElemTryComplexElemOfTyped
TypeDescrSet elemDescrs,
size_t elemSize)
{
JS_ASSERT(objDescrs.allOfArrayKind());
MDefinition *type = loadTypedObjectType(obj);
MDefinition *elemTypeObj = typeObjectForElementFromArrayStructType(type);
+ bool canBeNeutered;
MDefinition *indexAsByteOffset;
- if (!checkTypedObjectIndexInBounds(elemSize, obj, index, &indexAsByteOffset, objDescrs))
- return false;
+ if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objDescrs,
+ &indexAsByteOffset, &canBeNeutered))
+ {
+ return false;
+ }
return pushDerivedTypedObject(emitted, obj, indexAsByteOffset,
- elemDescrs, elemTypeObj);
+ elemDescrs, elemTypeObj, canBeNeutered);
}
bool
IonBuilder::pushDerivedTypedObject(bool *emitted,
MDefinition *obj,
MDefinition *offset,
TypeDescrSet derivedTypeDescrs,
- MDefinition *derivedTypeObj)
+ MDefinition *derivedTypeObj,
+ bool canBeNeutered)
{
// Find location within the owner object.
MDefinition *owner, *ownerOffset;
- loadTypedObjectData(obj, offset, &owner, &ownerOffset);
-
- // Create the derived datum.
+ loadTypedObjectData(obj, offset, canBeNeutered, &owner, &ownerOffset);
+
+ // Create the derived typed object.
MInstruction *derivedTypedObj = MNewDerivedTypedObject::New(alloc(),
derivedTypeDescrs,
derivedTypeObj,
owner,
ownerOffset);
current->add(derivedTypedObj);
current->push(derivedTypedObj);
@@ -7396,49 +7417,53 @@ IonBuilder::setElemTryTypedObject(bool *
case TypeDescr::Reference:
case TypeDescr::Struct:
case TypeDescr::SizedArray:
case TypeDescr::UnsizedArray:
// For now, only optimize storing scalars.
return true;
case TypeDescr::Scalar:
- return setElemTryScalarPropOfTypedObject(emitted,
+ return setElemTryScalarElemOfTypedObject(emitted,
obj,
index,
objTypeDescrs,
value,
elemTypeDescrs,
elemSize);
}
MOZ_ASSUME_UNREACHABLE("Bad kind");
}
bool
-IonBuilder::setElemTryScalarPropOfTypedObject(bool *emitted,
+IonBuilder::setElemTryScalarElemOfTypedObject(bool *emitted,
MDefinition *obj,
MDefinition *index,
TypeDescrSet objTypeDescrs,
MDefinition *value,
TypeDescrSet elemTypeDescrs,
size_t elemSize)
{
// Must always be loading the same scalar type
ScalarTypeDescr::Type elemType;
if (!elemTypeDescrs.scalarType(&elemType))
return true;
JS_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
+ bool canBeNeutered;
MDefinition *indexAsByteOffset;
- if (!checkTypedObjectIndexInBounds(elemSize, obj, index, &indexAsByteOffset, objTypeDescrs))
- return false;
+ if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objTypeDescrs,
+ &indexAsByteOffset, &canBeNeutered))
+ {
+ return false;
+ }
// Store the element
- if (!storeScalarTypedObjectValue(obj, indexAsByteOffset, elemType, value))
+ if (!storeScalarTypedObjectValue(obj, indexAsByteOffset, elemType, canBeNeutered, value))
return false;
current->push(value);
*emitted = true;
return true;
}
@@ -8430,17 +8455,17 @@ IonBuilder::getPropTryScalarPropOfTypedO
if (!fieldDescrs.scalarType(&fieldType))
return true;
// OK, perform the optimization
MDefinition *typedObj = current->pop();
return pushScalarLoadFromTypedObject(emitted, typedObj, constantInt(fieldOffset),
- fieldType);
+ fieldType, true);
}
bool
IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
int32_t fieldOffset,
TypeDescrSet fieldDescrs,
size_t fieldIndex,
types::TemporaryTypeSet *resultTypes)
@@ -8454,17 +8479,17 @@ IonBuilder::getPropTryComplexPropOfTyped
MDefinition *typedObj = current->pop();
// Identify the type object for the field.
MDefinition *type = loadTypedObjectType(typedObj);
MDefinition *fieldTypeObj = typeObjectForFieldFromStructType(type, fieldIndex);
return pushDerivedTypedObject(emitted, typedObj, constantInt(fieldOffset),
- fieldDescrs, fieldTypeObj);
+ fieldDescrs, fieldTypeObj, true);
}
bool
IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
bool barrier, types::TemporaryTypeSet *types)
{
JS_ASSERT(*emitted == false);
types::HeapTypeSetKey property;
@@ -8948,17 +8973,17 @@ IonBuilder::setPropTryScalarPropOfTypedO
{
// Must always be loading the same scalar type
ScalarTypeDescr::Type fieldType;
if (!fieldDescrs.scalarType(&fieldType))
return true;
// OK! Perform the optimization.
- if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldType, value))
+ if (!storeScalarTypedObjectValue(obj, constantInt(fieldOffset), fieldType, true, value))
return false;
current->push(value);
*emitted = true;
return true;
}
@@ -9799,71 +9824,83 @@ IonBuilder::loadTypedObjectType(MDefinit
// Shortcircuit derived type objects, meaning the intermediate
// objects created to represent `a.b` in an expression like
// `a.b.c`. In that case, the type object can be simply pulled
// from the operands of that instruction.
if (typedObj->isNewDerivedTypedObject())
return typedObj->toNewDerivedTypedObject()->type();
MInstruction *load = MLoadFixedSlot::New(alloc(), typedObj,
- JS_DATUM_SLOT_TYPE_DESCR);
+ JS_TYPEDOBJ_SLOT_TYPE_DESCR);
current->add(load);
return load;
}
// Given a typed object `typedObj` and an offset `offset` into that
// object's data, returns another typed object and adusted offset
// where the data can be found. Often, these returned values are the
// same as the inputs, but in cases where intermediate derived type
// objects have been created, the return values will remove
// intermediate layers (often rendering those derived type objects
// into dead code).
void
IonBuilder::loadTypedObjectData(MDefinition *typedObj,
MDefinition *offset,
+ bool canBeNeutered,
MDefinition **owner,
MDefinition **ownerOffset)
{
JS_ASSERT(typedObj->type() == MIRType_Object);
JS_ASSERT(offset->type() == MIRType_Int32);
// Shortcircuit derived type objects, meaning the intermediate
// objects created to represent `a.b` in an expression like
// `a.b.c`. In that case, the owned and a base offset can be
// pulled from the operands of the instruction and combined with
// `offset`.
if (typedObj->isNewDerivedTypedObject()) {
MNewDerivedTypedObject *ins = typedObj->toNewDerivedTypedObject();
+ // Note: we never need to check for neutering on this path,
+ // because when we create the derived typed object, we check
+ // for neutering there, if needed.
+
MAdd *offsetAdd = MAdd::NewAsmJS(alloc(), ins->offset(), offset, MIRType_Int32);
current->add(offsetAdd);
*owner = ins->owner();
*ownerOffset = offsetAdd;
return;
}
+ if (canBeNeutered) {
+ MNeuterCheck *chk = MNeuterCheck::New(alloc(), typedObj);
+ current->add(chk);
+ typedObj = chk;
+ }
+
*owner = typedObj;
*ownerOffset = offset;
}
// Takes as input a typed object, an offset into that typed object's
// memory, and the type repr of the data found at that offset. Returns
// the elements pointer and a scaled offset. The scaled offset is
// expressed in units of `unit`; when working with typed array MIR,
// this is typically the alignment.
void
IonBuilder::loadTypedObjectElements(MDefinition *typedObj,
MDefinition *offset,
int32_t unit,
+ bool canBeNeutered,
MDefinition **ownerElements,
MDefinition **ownerScaledOffset)
{
MDefinition *owner, *ownerOffset;
- loadTypedObjectData(typedObj, offset, &owner, &ownerOffset);
+ loadTypedObjectData(typedObj, offset, canBeNeutered, &owner, &ownerOffset);
// Load the element data.
MTypedObjectElements *elements = MTypedObjectElements::New(alloc(), owner);
current->add(elements);
// Scale to a different unit for compat with typed array MIRs.
if (unit != 1) {
MDiv *scaledOffset = MDiv::NewAsmJS(alloc(), ownerOffset, constantInt(unit), MIRType_Int32,
@@ -9955,22 +9992,24 @@ IonBuilder::typeObjectForFieldFromStruct
return unboxFieldType;
}
bool
IonBuilder::storeScalarTypedObjectValue(MDefinition *typedObj,
MDefinition *offset,
ScalarTypeDescr::Type type,
+ bool canBeNeutered,
MDefinition *value)
{
// Find location within the owner object.
MDefinition *elements, *scaledOffset;
size_t alignment = ScalarTypeDescr::alignment(type);
- loadTypedObjectElements(typedObj, offset, alignment, &elements, &scaledOffset);
+ loadTypedObjectElements(typedObj, offset, alignment, canBeNeutered,
+ &elements, &scaledOffset);
// Clamp value to [0, 255] when type is Uint8Clamped
MDefinition *toWrite = value;
if (type == ScalarTypeDescr::TYPE_UINT8_CLAMPED) {
toWrite = MClampToUint8::New(alloc(), value);
current->add(toWrite->toInstruction());
}
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -437,59 +437,66 @@ class IonBuilder : public MIRGenerator
bool lookupTypedObjectField(MDefinition *typedObj,
PropertyName *name,
int32_t *fieldOffset,
TypeDescrSet *fieldTypeReprs,
size_t *fieldIndex);
MDefinition *loadTypedObjectType(MDefinition *value);
void loadTypedObjectData(MDefinition *typedObj,
MDefinition *offset,
+ bool canBeNeutered,
MDefinition **owner,
MDefinition **ownerOffset);
void loadTypedObjectElements(MDefinition *typedObj,
MDefinition *offset,
int32_t unit,
+ bool canBeNeutered,
MDefinition **ownerElements,
MDefinition **ownerScaledOffset);
MDefinition *typeObjectForElementFromArrayStructType(MDefinition *typedObj);
MDefinition *typeObjectForFieldFromStructType(MDefinition *type,
size_t fieldIndex);
bool storeScalarTypedObjectValue(MDefinition *typedObj,
MDefinition *offset,
ScalarTypeDescr::Type type,
+ bool canBeNeutered,
MDefinition *value);
bool checkTypedObjectIndexInBounds(size_t elemSize,
MDefinition *obj,
MDefinition *index,
+ TypeDescrSet objTypeDescrs,
MDefinition **indexAsByteOffset,
- TypeDescrSet objTypeDescrs);
+ bool *canBeNeutered);
bool pushDerivedTypedObject(bool *emitted,
MDefinition *obj,
MDefinition *offset,
TypeDescrSet derivedTypeDescrs,
- MDefinition *derivedTypeObj);
+ MDefinition *derivedTypeObj,
+ bool canBeNeutered);
bool pushScalarLoadFromTypedObject(bool *emitted,
MDefinition *obj,
MDefinition *offset,
- ScalarTypeDescr::Type type);
+ ScalarTypeDescr::Type type,
+ bool canBeNeutered);
+ MDefinition *neuterCheck(MDefinition *obj);
// jsop_setelem() helpers.
bool setElemTryTypedArray(bool *emitted, MDefinition *object,
MDefinition *index, MDefinition *value);
bool setElemTryTypedObject(bool *emitted, MDefinition *obj,
MDefinition *index, MDefinition *value);
bool setElemTryTypedStatic(bool *emitted, MDefinition *object,
MDefinition *index, MDefinition *value);
bool setElemTryDense(bool *emitted, MDefinition *object,
MDefinition *index, MDefinition *value);
bool setElemTryArguments(bool *emitted, MDefinition *object,
MDefinition *index, MDefinition *value);
bool setElemTryCache(bool *emitted, MDefinition *object,
MDefinition *index, MDefinition *value);
- bool setElemTryScalarPropOfTypedObject(bool *emitted,
+ bool setElemTryScalarElemOfTypedObject(bool *emitted,
MDefinition *obj,
MDefinition *index,
TypeDescrSet objTypeReprs,
MDefinition *value,
TypeDescrSet elemTypeReprs,
size_t elemSize);
// jsop_getelem() helpers.
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -3641,16 +3641,38 @@ class LTypedObjectElements : public LIns
LIR_HEADER(TypedObjectElements)
LTypedObjectElements(const LAllocation &object) {
setOperand(0, object);
}
const LAllocation *object() {
return getOperand(0);
}
+ const MTypedObjectElements *mir() const {
+ return mir_->toTypedObjectElements();
+ }
+};
+
+// Check whether a typed object has a NULL data pointer
+// (i.e., has been neutered).
+class LNeuterCheck : public LInstructionHelper<0, 1, 1>
+{
+ public:
+ LIR_HEADER(NeuterCheck)
+
+ LNeuterCheck(const LAllocation &object, const LDefinition &temp) {
+ setOperand(0, object);
+ setTemp(0, temp);
+ }
+ const LAllocation *object() {
+ return getOperand(0);
+ }
+ const LDefinition *temp() {
+ return getTemp(0);
+ }
};
// Bailout if index >= length.
class LBoundsCheck : public LInstructionHelper<0, 2, 0>
{
public:
LIR_HEADER(BoundsCheck)
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -177,16 +177,17 @@
_(TypeBarrierV) \
_(TypeBarrierO) \
_(MonitorTypes) \
_(PostWriteBarrierO) \
_(PostWriteBarrierV) \
_(PostWriteBarrierAllSlots) \
_(InitializedLength) \
_(SetInitializedLength) \
+ _(NeuterCheck) \
_(BoundsCheck) \
_(BoundsCheckRange) \
_(BoundsCheckLower) \
_(LoadElementV) \
_(LoadElementT) \
_(LoadElementHole) \
_(StoreElementV) \
_(StoreElementT) \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2402,16 +2402,26 @@ LIRGenerator::visitNot(MNot *ins)
}
default:
MOZ_ASSUME_UNREACHABLE("Unexpected MIRType.");
}
}
bool
+LIRGenerator::visitNeuterCheck(MNeuterCheck *ins)
+{
+ LNeuterCheck *chk = new(alloc()) LNeuterCheck(useRegister(ins->object()),
+ temp());
+ if (!assignSnapshot(chk, Bailout_BoundsCheck))
+ return false;
+ return redefine(ins, ins->input()) && add(chk, ins);
+}
+
+bool
LIRGenerator::visitBoundsCheck(MBoundsCheck *ins)
{
LInstruction *check;
if (ins->minimum() || ins->maximum()) {
check = new(alloc()) LBoundsCheckRange(useRegisterOrConstant(ins->index()),
useAny(ins->length()),
temp());
} else {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -168,16 +168,17 @@ class LIRGenerator : public LIRGenerator
bool visitStoreSlot(MStoreSlot *ins);
bool visitTypeBarrier(MTypeBarrier *ins);
bool visitMonitorTypes(MMonitorTypes *ins);
bool visitPostWriteBarrier(MPostWriteBarrier *ins);
bool visitArrayLength(MArrayLength *ins);
bool visitSetArrayLength(MSetArrayLength *ins);
bool visitTypedArrayLength(MTypedArrayLength *ins);
bool visitTypedArrayElements(MTypedArrayElements *ins);
+ bool visitNeuterCheck(MNeuterCheck *lir);
bool visitTypedObjectElements(MTypedObjectElements *ins);
bool visitInitializedLength(MInitializedLength *ins);
bool visitSetInitializedLength(MSetInitializedLength *ins);
bool visitNot(MNot *ins);
bool visitBoundsCheck(MBoundsCheck *ins);
bool visitBoundsCheckLower(MBoundsCheckLower *ins);
bool visitLoadElement(MLoadElement *ins);
bool visitLoadElementHole(MLoadElementHole *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -770,19 +770,19 @@ IonBuilder::inlineMathPow(CallInfo &call
// Typechecking.
MIRType baseType = callInfo.getArg(0)->type();
MIRType powerType = callInfo.getArg(1)->type();
MIRType outputType = getInlineReturnType();
if (outputType != MIRType_Int32 && outputType != MIRType_Double)
return InliningStatus_NotInlined;
- if (baseType != MIRType_Int32 && baseType != MIRType_Double)
+ if (!IsNumberType(baseType))
return InliningStatus_NotInlined;
- if (powerType != MIRType_Int32 && powerType != MIRType_Double)
+ if (!IsNumberType(powerType))
return InliningStatus_NotInlined;
callInfo.setImplicitlyUsedUnchecked();
MDefinition *base = callInfo.getArg(0);
MDefinition *power = callInfo.getArg(1);
MDefinition *output = nullptr;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -5532,16 +5532,51 @@ class MTypedArrayElements
bool congruentTo(MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
+// Checks whether a typed object is neutered.
+class MNeuterCheck
+ : public MUnaryInstruction
+{
+ private:
+ MNeuterCheck(MDefinition *object)
+ : MUnaryInstruction(object)
+ {
+ JS_ASSERT(object->type() == MIRType_Object);
+ setResultType(MIRType_Object);
+ setResultTypeSet(object->resultTypeSet());
+ setGuard();
+ setMovable();
+ }
+
+ public:
+ INSTRUCTION_HEADER(NeuterCheck)
+
+ static MNeuterCheck *New(TempAllocator &alloc, MDefinition *object) {
+ return new(alloc) MNeuterCheck(object);
+ }
+
+ MDefinition *object() const {
+ return getOperand(0);
+ }
+
+ bool congruentTo(MDefinition *ins) const {
+ return congruentIfOperandsEqual(ins);
+ }
+
+ AliasSet getAliasSet() const {
+ return AliasSet::Load(AliasSet::ObjectFields);
+ }
+};
+
// Load a binary data object's "elements", which is just its opaque
// binary data space. Eventually this should probably be
// unified with `MTypedArrayElements`.
class MTypedObjectElements
: public MUnaryInstruction,
public SingleObjectPolicy
{
private:
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -130,16 +130,17 @@ namespace jit {
_(ArrayLength) \
_(SetArrayLength) \
_(TypedArrayLength) \
_(TypedArrayElements) \
_(TypedObjectElements) \
_(InitializedLength) \
_(SetInitializedLength) \
_(Not) \
+ _(NeuterCheck) \
_(BoundsCheck) \
_(BoundsCheckLower) \
_(InArray) \
_(LoadElement) \
_(LoadElementHole) \
_(StoreElement) \
_(StoreElementHole) \
_(ArrayPopShift) \
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -77,48 +77,48 @@ jit::ParallelWriteGuard(ForkJoinContext
// In order to be able to distinguish escaped out pointers from
// prior iterations and the proper out pointers from the
// current iteration, we always track a *target memory region*
// (which is a span of bytes within the output buffer) and not
// just the output buffer itself.
JS_ASSERT(ForkJoinContext::current() == cx);
- if (object->is<TypedDatum>()) {
- TypedDatum &datum = object->as<TypedDatum>();
+ if (object->is<TypedObject>()) {
+ TypedObject &typedObj = object->as<TypedObject>();
- // Note: check target region based on `datum`, not the owner.
- // This is because `datum` may point to some subregion of the
+ // Note: check target region based on `typedObj`, not the owner.
+ // This is because `typedObj` may point to some subregion of the
// owner and we only care if that *subregion* is within the
// target region, not the entire owner.
- if (IsInTargetRegion(cx, &datum))
+ if (IsInTargetRegion(cx, &typedObj))
return true;
// Also check whether owner is thread-local.
- TypedDatum &owner = datum.owner();
+ ArrayBufferObject &owner = typedObj.owner();
return cx->isThreadLocal(&owner);
}
// For other kinds of writable objects, must be thread-local.
return cx->isThreadLocal(object);
}
-// Check that |object| (which must be a typed datum) maps
+// Check that |object| (which must be a typed typedObj) maps
// to memory in the target region.
//
// For efficiency, we assume that all handles which the user has
// access to are either entirely within the target region or entirely
// without, but not straddling the target region nor encompassing
// it. This invariant is maintained by the PJS APIs, where the target
// region and handles are always elements of the same output array.
bool
-jit::IsInTargetRegion(ForkJoinContext *cx, TypedDatum *datum)
+jit::IsInTargetRegion(ForkJoinContext *cx, TypedObject *typedObj)
{
- JS_ASSERT(datum->is<TypedDatum>()); // in case JIT supplies something bogus
- uint8_t *typedMem = datum->typedMem();
+ JS_ASSERT(typedObj->is<TypedObject>()); // in case JIT supplies something bogus
+ uint8_t *typedMem = typedObj->typedMem();
return (typedMem >= cx->targetRegionStart &&
typedMem < cx->targetRegionEnd);
}
#ifdef DEBUG
static void
printTrace(const char *prefix, struct IonLIRTraceData *cached)
{
--- a/js/src/jit/ParallelFunctions.h
+++ b/js/src/jit/ParallelFunctions.h
@@ -7,24 +7,24 @@
#ifndef jit_ParallelFunctions_h
#define jit_ParallelFunctions_h
#include "gc/Heap.h"
#include "vm/ForkJoin.h"
namespace js {
-class TypedDatum; // subclass of JSObject* defined in builtin/TypedObject.h
+class TypedObject; // subclass of JSObject* defined in builtin/TypedObject.h
namespace jit {
ForkJoinContext *ForkJoinContextPar();
JSObject *NewGCThingPar(ForkJoinContext *cx, gc::AllocKind allocKind);
bool ParallelWriteGuard(ForkJoinContext *cx, JSObject *object);
-bool IsInTargetRegion(ForkJoinContext *cx, TypedDatum *object);
+bool IsInTargetRegion(ForkJoinContext *cx, TypedObject *object);
bool CheckOverRecursedPar(ForkJoinContext *cx);
bool InterruptCheckPar(ForkJoinContext *cx);
// Extends the given array with `length` new holes. Returns nullptr on
// failure or else `array`, which is convenient during code
// generation.
JSObject *ExtendArrayPar(ForkJoinContext *cx, JSObject *array, uint32_t length);
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -218,16 +218,17 @@ class ParallelSafetyVisitor : public MIn
SAFE_OP(ArrayLength)
WRITE_GUARDED_OP(SetArrayLength, elements)
SAFE_OP(TypedArrayLength)
SAFE_OP(TypedArrayElements)
SAFE_OP(TypedObjectElements)
SAFE_OP(InitializedLength)
WRITE_GUARDED_OP(SetInitializedLength, elements)
SAFE_OP(Not)
+ SAFE_OP(NeuterCheck)
SAFE_OP(BoundsCheck)
SAFE_OP(BoundsCheckLower)
SAFE_OP(LoadElement)
SAFE_OP(LoadElementHole)
MAYBE_WRITE_GUARDED_OP(StoreElement, elements)
WRITE_GUARDED_OP(StoreElementHole, elements)
UNSAFE_OP(ArrayPopShift)
UNSAFE_OP(ArrayPush)
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -951,23 +951,24 @@ LeaveWith(JSContext *cx, BaselineFrame *
}
bool
InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame, uint32_t numStackValues)
{
return frame->initForOsr(interpFrame, numStackValues);
}
-JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
- HandleObject owner, int32_t offset)
+JSObject *
+CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
+ HandleObject owner, int32_t offset)
{
JS_ASSERT(descr->is<SizedTypeDescr>());
- JS_ASSERT(owner->is<TypedDatum>());
+ JS_ASSERT(owner->is<TypedObject>());
Rooted<SizedTypeDescr*> descr1(cx, &descr->as<SizedTypeDescr>());
- Rooted<TypedDatum*> owner1(cx, &owner->as<TypedDatum>());
+ Rooted<TypedObject*> owner1(cx, &owner->as<TypedObject>());
return TypedObject::createDerived(cx, descr1, owner1, offset);
}
JSString *
RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp, HandleString repl)
{
JS_ASSERT(string);
JS_ASSERT(repl);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -409,17 +409,17 @@ MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD
MSG_DEF(JSMSG_GENERATOR_FINISHED, 356, 0, JSEXN_TYPEERR, "generator has already finished")
MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG, 357, 0, JSEXN_ERR, "Type is too large to allocate")
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPE_OBJECT, 358, 0, JSEXN_ERR, "Expected a type object")
MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 359, 0, JSEXN_RANGEERR, "too many constructor arguments")
MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 360, 0, JSEXN_RANGEERR, "too many function arguments")
MSG_DEF(JSMSG_DEBUG_NOT_DEBUGGEE, 361, 2, JSEXN_ERR, "{0} is not a debuggee {1}")
MSG_DEF(JSMSG_TYPEDOBJECT_NOT_TYPED_OBJECT, 362, 0, JSEXN_ERR, "Expected a typed object")
MSG_DEF(JSMSG_TYPEDOBJECT_NO_SUCH_PROP, 363, 1, JSEXN_TYPEERR, "No such property: {0}")
-MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_ARGS, 364, 2, JSEXN_TYPEERR, "argument {0} invalid: expected {1}")
+MSG_DEF(JSMSG_TYPEDOBJECT_BAD_ARGS, 364, 0, JSEXN_TYPEERR, "invalid arguments")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED, 365, 0, JSEXN_TYPEERR, "handle unattached")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE, 366, 0, JSEXN_TYPEERR, "handle moved to destination of incorrect type")
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 367, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level")
MSG_DEF(JSMSG_NO_IMPORT_NAME, 368, 0, JSEXN_SYNTAXERR, "missing import name")
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 369, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
MSG_DEF(JSMSG_NO_BINDING_NAME, 370, 0, JSEXN_SYNTAXERR, "missing binding name")
MSG_DEF(JSMSG_RC_AFTER_IMPORT_SPEC_LIST, 371, 0, JSEXN_SYNTAXERR, "missing '}' after module specifier list")
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -912,16 +912,27 @@ NewBuiltinClassInstance(ExclusiveContext
inline JSObject *
NewBuiltinClassInstance(ExclusiveContext *cx, const Class *clasp, NewObjectKind newKind = GenericObject)
{
gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
return NewBuiltinClassInstance(cx, clasp, allocKind, newKind);
}
+template<typename T>
+inline T *
+NewBuiltinClassInstance(ExclusiveContext *cx, NewObjectKind newKind = GenericObject)
+{
+ JSObject *obj = NewBuiltinClassInstance(cx, &T::class_, newKind);
+ if (!obj)
+ return nullptr;
+
+ return &obj->as<T>();
+}
+
// Used to optimize calls to (new Object())
bool
NewObjectScriptedCall(JSContext *cx, MutableHandleObject obj);
/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
static inline JSObject *
CopyInitializerObject(JSContext *cx, HandleObject baseobj, NewObjectKind newKind = GenericObject)
{
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -150,16 +150,17 @@ UNIFIED_SOURCES += [
'jsstr.cpp',
'jswatchpoint.cpp',
'jsweakmap.cpp',
'jsworkers.cpp',
'jswrapper.cpp',
'perf/jsperf.cpp',
'prmjtime.cpp',
'vm/ArgumentsObject.cpp',
+ 'vm/ArrayBufferObject.cpp',
'vm/CallNonGenericMethod.cpp',
'vm/CharacterEncoding.cpp',
'vm/Compression.cpp',
'vm/DateTime.cpp',
'vm/Debugger.cpp',
'vm/ErrorObject.cpp',
'vm/ForkJoin.cpp',
'vm/GlobalObject.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedObject/atopbuffer.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
+var BUGNUMBER = 898356;
+
+var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+
+function main() { // once a C programmer, always a C programmer.
+ print(BUGNUMBER + ": " + summary);
+
+ var Uints = new StructType({f: uint32, g: uint32});
+
+ var anArray = new Uint32Array(2);
+ anArray[0] = 22;
+ anArray[1] = 44;
+
+ var uints = new Uints(anArray.buffer);
+ assertEq(storage(uints).buffer, anArray.buffer);
+ assertEq(uints.f, 22);
+ assertEq(uints.g, 44);
+
+ uints.f++;
+ assertEq(anArray[0], 23);
+
+ reportCompare(true, true);
+ print("Tests complete");
+}
+
+main();
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedObject/atopbufferwithoffset.js
@@ -0,0 +1,51 @@
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
+var BUGNUMBER = 898356;
+
+var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+
+function main() { // once a C programmer, always a C programmer.
+ print(BUGNUMBER + ": " + summary);
+
+ var Uints = new StructType({f: uint32, g: uint32});
+
+ var anArray = new Uint32Array(4);
+ anArray[1] = 22;
+ anArray[2] = 44;
+
+ var uints = new Uints(anArray.buffer, 4);
+ assertEq(storage(uints).buffer, anArray.buffer);
+ assertEq(uints.f, 22);
+ assertEq(uints.g, 44);
+ uints.f++;
+ assertEq(anArray[1], 23);
+
+ // No misaligned byte offsets or offsets that would stretch past the end:
+ assertThrows(() => new Uints(anArray.buffer, -4)); // negative
+ assertThrows(() => new Uints(anArray.buffer, -3)); // negative
+ assertThrows(() => new Uints(anArray.buffer, -2)); // negative
+ assertThrows(() => new Uints(anArray.buffer, -1)); // negative
+ new Uints(anArray.buffer, 0); // ok
+ assertThrows(() => new Uints(anArray.buffer, 1)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 2)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 3)); // misaligned
+ new Uints(anArray.buffer, 4); // ok
+ assertThrows(() => new Uints(anArray.buffer, 5)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 6)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 7)); // misaligned
+ new Uints(anArray.buffer, 8); // ok
+ assertThrows(() => new Uints(anArray.buffer, 9)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 10)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 11)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 12)); // would extend past end
+ assertThrows(() => new Uints(anArray.buffer, 13)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 14)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 15)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 16)); // would extend past end
+ assertThrows(() => new Uints(anArray.buffer, 17)); // misaligned
+ assertThrows(() => new Uints(anArray.buffer, 4294967292)); // overflows int
+
+ reportCompare(true, true);
+ print("Tests complete");
+}
+
+main();
--- a/js/src/tests/ecma_6/TypedObject/referencetypetrace.js
+++ b/js/src/tests/ecma_6/TypedObject/referencetypetrace.js
@@ -44,17 +44,17 @@ function TestArrayElements(RefType) {
assertCanReach(s1, rabbit);
s1[0] = null;
assertCannotReach(s1, rabbit);
}
function TestUnsizedArrayElements(RefType) {
var rabbit = {};
var S1 = new ArrayType(RefType);
- var s1 = new S1(1, [rabbit]);
+ var s1 = new S1([rabbit]);
assertCanReach(s1, rabbit);
s1[0] = null;
assertCannotReach(s1, rabbit);
}
function TestStructInArray(RefType) {
var rabbit = {};
var S2 = new StructType({f: RefType, g: RefType});
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedObject/storageopaque.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
+var BUGNUMBER = 898356;
+
+var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+
+function main() { // once a C programmer, always a C programmer.
+ print(BUGNUMBER + ": " + summary);
+
+ var Uints = new StructType({f: uint32, g: uint32});
+ var uints = new Uints({f: 0, g: 1});
+ assertEq(storage(uints) != null, true);
+
+ var Objects = new StructType({f: Object, g: Object});
+ var objects = new Objects({f: 0, g: 1});
+ assertEq(storage(objects), null);
+
+ var Anys = new StructType({f: Any, g: Any});
+ var anys = new Anys({f: 0, g: 1});
+ assertEq(storage(anys), null);
+
+ // Note: test that `mixed.g`, when derived from an opaque buffer,
+ // remains opaque.
+ var Mixed = new StructType({f: Object, g: Uints});
+ var mixed = new Mixed({f: 0, g: {f: 22, g: 44}});
+ assertEq(storage(mixed), null);
+ assertEq(objectType(mixed.g), Uints);
+ assertEq(storage(mixed.g), null);
+
+ reportCompare(true, true);
+ print("Tests complete");
+}
+
+main();
--- a/js/src/tests/ecma_6/TypedObject/unsizedarrays.js
+++ b/js/src/tests/ecma_6/TypedObject/unsizedarrays.js
@@ -11,18 +11,18 @@ var { ArrayType, StructType, uint8, floa
var ObjectType = TypedObject.Object;
function runTests() {
print(BUGNUMBER + ": " + summary);
(function SimpleArrayOfTwoObjects() {
print("SimpleArrayOfTwoObjects");
var Objects = new ArrayType(ObjectType);
- var objects2 = new Objects(2, [{f: "Hello"},
- {f: "World"}]);
+ var objects2 = new Objects([{f: "Hello"},
+ {f: "World"}]);
assertEq(objects2[0].f, "Hello");
assertEq(objects2[1].f, "World");
assertEq(objects2.length, 2);
})();
(function EmbedUnsizedArraysBad() {
print("EmbedUnsizedArraysBad");
var Objects = new ArrayType(ObjectType);
@@ -30,17 +30,17 @@ function runTests() {
assertThrows(() => new StructType({f: Objects}));
})();
(function MultipleSizes() {
print("MultipleSizes");
var Uints = new ArrayType(uint32);
var Point = new StructType({values: new ArrayType(uint32).dimension(3)});
- var uints = new Uints(3, [0, 1, 2]);
+ var uints = new Uints([0, 1, 2]);
var point = new Point({values: uints});
assertEq(uints.length, point.values.length);
for (var i = 0; i < uints.length; i++) {
assertEq(uints[i], i);
assertEq(uints[i], point.values[i]);
}
})();
new file mode 100644
--- /dev/null
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -0,0 +1,1427 @@
+/* -*- 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/ArrayBufferObject.h"
+
+#include "mozilla/Alignment.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/PodOperations.h"
+
+#include <string.h>
+#ifndef XP_WIN
+# include <sys/mman.h>
+#endif
+
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jscntxt.h"
+#include "jscpucfg.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jstypes.h"
+#include "jsutil.h"
+#ifdef XP_WIN
+# include "jswin.h"
+#endif
+#include "jswrapper.h"
+
+#include "gc/Barrier.h"
+#include "gc/Marking.h"
+#include "jit/AsmJS.h"
+#include "jit/AsmJSModule.h"
+#include "vm/GlobalObject.h"
+#include "vm/Interpreter.h"
+#include "vm/NumericConversions.h"
+#include "vm/WrapperObject.h"
+
+#include "jsatominlines.h"
+#include "jsinferinlines.h"
+#include "jsobjinlines.h"
+
+#include "vm/Shape-inl.h"
+
+#if JS_USE_NEW_OBJECT_REPRESENTATION
+// See the comment above OldObjectRepresentationHack.
+# error "TypedArray support for new object representation unimplemented."
+#endif
+
+using namespace js;
+using namespace js::gc;
+using namespace js::types;
+
+/*
+ * Allocate array buffers with the maximum number of fixed slots marked as
+ * reserved, so that the fixed slots may be used for the buffer's contents.
+ * The last fixed slot is kept for the object's private data.
+ */
+static const uint8_t ARRAYBUFFER_RESERVED_SLOTS = JSObject::MAX_FIXED_SLOTS - 1;
+
+// Sentinel value used to initialize ArrayBufferViewObjects' NEXT_BUFFER_SLOTs
+// to show that they have not yet been added to any ArrayBufferObject list.
+js::ArrayBufferObject * const js::UNSET_BUFFER_LINK = reinterpret_cast<js::ArrayBufferObject*>(0x2);
+
+/*
+ * Convert |v| to an array index for an array of length |length| per
+ * the Typed Array Specification section 7.0, |subarray|. If successful,
+ * the output value is in the range [0, length].
+ */
+bool
+js::ToClampedIndex(JSContext *cx, HandleValue v, uint32_t length, uint32_t *out)
+{
+ int32_t result;
+ if (!ToInt32(cx, v, &result))
+ return false;
+ if (result < 0) {
+ result += length;
+ if (result < 0)
+ result = 0;
+ } else if (uint32_t(result) > length) {
+ result = length;
+ }
+ *out = uint32_t(result);
+ return true;
+}
+
+/*
+ * ArrayBufferObject
+ *
+ * This class holds the underlying raw buffer that the TypedArrayObject classes
+ * access. It can be created explicitly and passed to a TypedArrayObject, or
+ * can be created implicitly by constructing a TypedArrayObject with a size.
+ */
+
+/*
+ * ArrayBufferObject (base)
+ */
+
+const Class ArrayBufferObject::protoClass = {
+ "ArrayBufferPrototype",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
+ JS_PropertyStub, /* addProperty */
+ JS_DeletePropertyStub, /* delProperty */
+ JS_PropertyStub, /* getProperty */
+ JS_StrictPropertyStub, /* setProperty */
+ JS_EnumerateStub,
+ JS_ResolveStub,
+ JS_ConvertStub
+};
+
+const Class ArrayBufferObject::class_ = {
+ "ArrayBuffer",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_IMPLEMENTS_BARRIERS |
+ Class::NON_NATIVE |
+ JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
+ JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
+ JS_PropertyStub, /* addProperty */
+ JS_DeletePropertyStub, /* delProperty */
+ JS_PropertyStub, /* getProperty */
+ JS_StrictPropertyStub, /* setProperty */
+ JS_EnumerateStub,
+ JS_ResolveStub,
+ JS_ConvertStub,
+ nullptr, /* 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 */
+ }
+};
+
+const JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
+ JS_FN("slice", ArrayBufferObject::fun_slice, 2, JSFUN_GENERIC_NATIVE),
+ JS_FS_END
+};
+
+const JSFunctionSpec ArrayBufferObject::jsstaticfuncs[] = {
+ JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
+ JS_FS_END
+};
+
+MOZ_ALWAYS_INLINE bool
+ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
+{
+ JS_ASSERT(IsArrayBuffer(args.thisv()));
+ args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
+ return true;
+}
+
+bool
+ArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
+}
+
+bool
+ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
+{
+ JS_ASSERT(IsArrayBuffer(args.thisv()));
+
+ Rooted<ArrayBufferObject*> thisObj(cx, &args.thisv().toObject().as<ArrayBufferObject>());
+
+ // these are the default values
+ uint32_t length = thisObj->byteLength();
+ uint32_t begin = 0, end = length;
+
+ if (args.length() > 0) {
+ if (!ToClampedIndex(cx, args[0], length, &begin))
+ return false;
+
+ if (args.length() > 1) {
+ if (!ToClampedIndex(cx, args[1], length, &end))
+ return false;
+ }
+ }
+
+ if (begin > end)
+ begin = end;
+
+ JSObject *nobj = createSlice(cx, thisObj, begin, end);
+ if (!nobj)
+ return false;
+ args.rval().setObject(*nobj);
+ return true;
+}
+
+bool
+ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsArrayBuffer, fun_slice_impl>(cx, args);
+}
+
+/*
+ * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
+ */
+bool
+ArrayBufferObject::fun_isView(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ args.rval().setBoolean(args.get(0).isObject() &&
+ JS_IsArrayBufferViewObject(&args.get(0).toObject()));
+ return true;
+}
+
+/*
+ * new ArrayBuffer(byteLength)
+ */
+bool
+ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
+{
+ int32_t nbytes = 0;
+ CallArgs args = CallArgsFromVp(argc, vp);
+ if (argc > 0 && !ToInt32(cx, args[0], &nbytes))
+ return false;
+
+ if (nbytes < 0) {
+ /*
+ * We're just not going to support arrays that are bigger than what will fit
+ * as an integer value; if someone actually ever complains (validly), then we
+ * can fix.
+ */
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+ return false;
+ }
+
+ JSObject *bufobj = create(cx, uint32_t(nbytes));
+ if (!bufobj)
+ return false;
+ args.rval().setObject(*bufobj);
+ return true;
+}
+
+/*
+ * Note that some callers are allowed to pass in a nullptr cx, so we allocate
+ * with the cx if available and fall back to the runtime. If oldptr is given,
+ * it's expected to be a previously-allocated ObjectElements* pointer that we
+ * then realloc.
+ */
+static ObjectElements *
+AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr)
+{
+ uint32_t size = nbytes + sizeof(ObjectElements);
+ ObjectElements *newheader;
+
+ // if oldptr is given, then we need to do a realloc
+ if (oldptr) {
+ ObjectElements *oldheader = static_cast<ObjectElements *>(oldptr);
+ uint32_t oldnbytes = ArrayBufferObject::headerInitializedLength(oldheader);
+
+ void *p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, size) : js_realloc(oldptr, size);
+ newheader = static_cast<ObjectElements *>(p);
+
+ // if we grew the array, we need to set the new bytes to 0
+ if (newheader && nbytes > oldnbytes)
+ memset(reinterpret_cast<uint8_t*>(newheader->elements()) + oldnbytes, 0, nbytes - oldnbytes);
+ } else {
+ void *p = maybecx ? maybecx->runtime()->callocCanGC(size) : js_calloc(size);
+ newheader = static_cast<ObjectElements *>(p);
+ }
+ if (!newheader) {
+ if (maybecx)
+ js_ReportOutOfMemory(maybecx);
+ return nullptr;
+ }
+
+ ArrayBufferObject::updateElementsHeader(newheader, nbytes);
+
+ return newheader;
+}
+
+// The list of views must be stored somewhere in the ArrayBufferObject, but
+// the slots are already being used for the element storage and the private
+// field is used for a delegate object. The ObjectElements header has space
+// for it, but I don't want to mess around with adding unions to it with
+// JS_USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much
+// more cleanly.
+struct OldObjectRepresentationHack {
+ uint32_t flags;
+ uint32_t initializedLength;
+ EncapsulatedPtr<ArrayBufferViewObject> views;
+};
+
+static ArrayBufferViewObject *
+GetViewList(ArrayBufferObject *obj)
+{
+ return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
+}
+
+static void
+SetViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
+{
+ reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views = viewsHead;
+ PostBarrierTypedArrayObject(obj);
+}
+
+static void
+InitViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
+{
+ reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views.init(viewsHead);
+ PostBarrierTypedArrayObject(obj);
+}
+
+static EncapsulatedPtr<ArrayBufferViewObject> &
+GetViewListRef(ArrayBufferObject *obj)
+{
+ JS_ASSERT(obj->runtimeFromMainThread()->isHeapBusy());
+ return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
+}
+
+/* static */ bool
+ArrayBufferObject::neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+ ArrayBufferViewObject *view;
+ size_t numViews = 0;
+ for (view = GetViewList(buffer); view; view = view->nextView()) {
+ numViews++;
+ view->neuter(cx);
+
+ // Notify compiled jit code that the base pointer has moved.
+ MarkObjectStateChange(cx, view);
+ }
+
+ // neuterAsmJSArrayBuffer adjusts state specific to the ArrayBuffer data
+ // itself, but it only affects the behavior of views
+ if (buffer->isAsmJSArrayBuffer()) {
+ if (!ArrayBufferObject::neuterAsmJSArrayBuffer(cx, *buffer))
+ return false;
+ }
+
+ // Remove buffer from the list of buffers with > 1 view.
+ if (numViews > 1 && GetViewList(buffer)->bufferLink() != UNSET_BUFFER_LINK) {
+ ArrayBufferObject *prev = buffer->compartment()->gcLiveArrayBuffers;
+ if (prev == buffer) {
+ buffer->compartment()->gcLiveArrayBuffers = GetViewList(prev)->bufferLink();
+ } else {
+ for (ArrayBufferObject *b = GetViewList(prev)->bufferLink();
+ b;
+ b = GetViewList(b)->bufferLink())
+ {
+ if (b == buffer) {
+ GetViewList(prev)->setBufferLink(GetViewList(b)->bufferLink());
+ break;
+ }
+ prev = b;
+ }
+ }
+ }
+
+ return true;
+}
+
+void
+ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
+{
+ JS_ASSERT(!isAsmJSArrayBuffer());
+
+ // Grab out data before invalidating it.
+ uint32_t byteLengthCopy = byteLength();
+ uintptr_t oldDataPointer = uintptr_t(dataPointer());
+ ArrayBufferViewObject *viewListHead = GetViewList(this);
+
+ // Update all views.
+ uintptr_t newDataPointer = uintptr_t(newHeader->elements());
+ for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
+ uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer;
+ view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr));
+
+ // Notify compiled jit code that the base pointer has moved.
+ MarkObjectStateChange(cx, view);
+ }
+
+ // The list of views in the old header is reachable if the contents are
+ // being transferred, so null it out
+ SetViewList(this, nullptr);
+
+#ifdef JSGC_GENERATIONAL
+ ObjectElements *oldHeader = ObjectElements::fromElements(elements);
+ JS_ASSERT(oldHeader != newHeader);
+ JSRuntime *rt = runtimeFromMainThread();
+ if (hasDynamicElements())
+ rt->gcNursery.notifyRemovedElements(this, oldHeader);
+#endif
+
+ elements = newHeader->elements();
+
+#ifdef JSGC_GENERATIONAL
+ if (hasDynamicElements())
+ rt->gcNursery.notifyNewElements(this, newHeader);
+#endif
+
+ initElementsHeader(newHeader, byteLengthCopy);
+ InitViewList(this, viewListHead);
+}
+
+void
+ArrayBufferObject::neuter(JSContext *cx)
+{
+ JS_ASSERT(cx);
+ if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
+ ObjectElements *oldHeader = getElementsHeader();
+ changeContents(cx, ObjectElements::fromElements(fixedElements()));
+
+ FreeOp fop(cx->runtime(), false);
+ fop.free_(oldHeader);
+ }
+
+ uint32_t byteLen = 0;
+ updateElementsHeader(getElementsHeader(), byteLen);
+
+ getElementsHeader()->setIsNeuteredBuffer();
+}
+
+/* static */ bool
+ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+ if (buffer->hasDynamicElements())
+ return true;
+
+ ObjectElements *newHeader = AllocateArrayBufferContents(cx, buffer->byteLength());
+ if (!newHeader)
+ return false;
+
+ void *newHeaderDataPointer = reinterpret_cast<void*>(newHeader->elements());
+ memcpy(newHeaderDataPointer, buffer->dataPointer(), buffer->byteLength());
+
+ buffer->changeContents(cx, newHeader);
+ 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
+//
+JS_STATIC_ASSERT(sizeof(ObjectElements) < AsmJSPageSize);
+JS_STATIC_ASSERT(AsmJSAllocationGranularity == AsmJSPageSize);
+static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
+
+bool
+ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+ if (buffer->isAsmJSArrayBuffer())
+ return true;
+
+ // Get the entire reserved region (with all pages inaccessible).
+ void *p;
+# ifdef XP_WIN
+ p = VirtualAlloc(nullptr, AsmJSMappedSize, MEM_RESERVE, PAGE_NOACCESS);
+ if (!p)
+ return false;
+# else
+ p = mmap(nullptr, AsmJSMappedSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (p == MAP_FAILED)
+ return false;
+# endif
+
+ // Enable access to the valid region.
+ JS_ASSERT(buffer->byteLength() % AsmJSAllocationGranularity == 0);
+# ifdef XP_WIN
+ if (!VirtualAlloc(p, AsmJSPageSize + buffer->byteLength(), MEM_COMMIT, PAGE_READWRITE)) {
+ VirtualFree(p, 0, MEM_RELEASE);
+ return false;
+ }
+# else
+ if (mprotect(p, AsmJSPageSize + buffer->byteLength(), PROT_READ | PROT_WRITE)) {
+ munmap(p, AsmJSMappedSize);
+ return false;
+ }
+# endif
+
+ // Copy over the current contents of the typed array.
+ uint8_t *data = reinterpret_cast<uint8_t*>(p) + AsmJSPageSize;
+ memcpy(data, buffer->dataPointer(), buffer->byteLength());
+
+ // Swap the new elements into the ArrayBufferObject.
+ ObjectElements *newHeader = reinterpret_cast<ObjectElements*>(data - sizeof(ObjectElements));
+ ObjectElements *oldHeader = buffer->hasDynamicElements() ? buffer->getElementsHeader()
+ : nullptr;
+ buffer->changeContents(cx, newHeader);
+ js_free(oldHeader);
+
+ // Mark the ArrayBufferObject so (1) we don't do this again, (2) we know not
+ // to js_free the header in the normal way.
+ newHeader->setIsAsmJSArrayBuffer();
+ JS_ASSERT(data == buffer->dataPointer());
+ return true;
+}
+
+void
+ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
+{
+ ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
+ JS_ASSERT(buffer.isAsmJSArrayBuffer());
+
+ uint8_t *p = buffer.dataPointer() - AsmJSPageSize ;
+ JS_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
+# ifdef XP_WIN
+ VirtualFree(p, 0, MEM_RELEASE);
+# else
+ munmap(p, AsmJSMappedSize);
+# endif
+}
+#else /* defined(JS_ION) && defined(JS_CPU_X64) */
+bool
+ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+{
+ if (buffer->isAsmJSArrayBuffer())
+ return true;
+
+ if (!ensureNonInline(cx, buffer))
+ return false;
+
+ JS_ASSERT(buffer->hasDynamicElements());
+ buffer->getElementsHeader()->setIsAsmJSArrayBuffer();
+ return true;
+}
+
+void
+ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
+{
+ fop->free_(obj->as<ArrayBufferObject>().getElementsHeader());
+}
+#endif
+
+bool
+ArrayBufferObject::neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer)
+{
+#ifdef JS_ION
+ AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread();
+ for (; act; act = act->prev()) {
+ if (act->module().maybeHeapBufferObject() == &buffer)
+ break;
+ }
+ if (!act)
+ return true;
+
+ js_ReportOverRecursed(cx);
+ return false;
+#else
+ return true;
+#endif
+}
+
+void
+ArrayBufferObject::addView(ArrayBufferViewObject *view)
+{
+ // This view should never have been associated with a buffer before
+ JS_ASSERT(view->bufferLink() == UNSET_BUFFER_LINK);
+
+ // Note that pre-barriers are not needed here because either the list was
+ // previously empty, in which case no pointer is being overwritten, or the
+ // list was nonempty and will be made weak during this call (and weak
+ // pointers cannot violate the snapshot-at-the-beginning invariant.)
+
+ ArrayBufferViewObject *viewsHead = GetViewList(this);
+ if (viewsHead == nullptr) {
+ // This ArrayBufferObject will have a single view at this point, so it
+ // is a strong pointer (it will be marked during tracing.)
+ JS_ASSERT(view->nextView() == nullptr);
+ } else {
+ view->prependToViews(viewsHead);
+ }
+
+ SetViewList(this, view);
+}
+
+ArrayBufferObject *
+ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, bool clear /* = true */)
+{
+ Rooted<ArrayBufferObject*> obj(cx, NewBuiltinClassInstance<ArrayBufferObject>(cx));
+ if (!obj)
+ return nullptr;
+ JS_ASSERT_IF(obj->isTenured(), obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT16_BACKGROUND);
+ JS_ASSERT(obj->getClass() == &class_);
+
+ js::Shape *empty = EmptyShape::getInitialShape(cx, &class_,
+ obj->getProto(), obj->getParent(), obj->getMetadata(),
+ gc::FINALIZE_OBJECT16_BACKGROUND);
+ if (!empty)
+ return nullptr;
+ obj->setLastPropertyInfallible(empty);
+
+ // ArrayBufferObjects delegate added properties to another JSObject, so
+ // their internal layout can use the object's fixed slots for storage.
+ // Set up the object to look like an array with an elements header.
+ JS_ASSERT(!obj->hasDynamicSlots());
+ JS_ASSERT(!obj->hasDynamicElements());
+
+ // The beginning stores an ObjectElements header structure holding the
+ // length. The rest of it is a flat data store for the array buffer.
+ size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER;
+
+ if (nbytes > sizeof(Value) * usableSlots) {
+ ObjectElements *header = AllocateArrayBufferContents(cx, nbytes);
+ if (!header)
+ return nullptr;
+ obj->elements = header->elements();
+
+#ifdef JSGC_GENERATIONAL
+ JSRuntime *rt = obj->runtimeFromMainThread();
+ rt->gcNursery.notifyNewElements(obj, header);
+#endif
+ } else {
+ obj->setFixedElements();
+ if (clear)
+ memset(obj->dataPointer(), 0, nbytes);
+ }
+
+ obj->initElementsHeader(obj->getElementsHeader(), nbytes);
+
+ return obj;
+}
+
+JSObject *
+ArrayBufferObject::createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
+ uint32_t begin, uint32_t end)
+{
+ JS_ASSERT(begin <= arrayBuffer->byteLength());
+ JS_ASSERT(end <= arrayBuffer->byteLength());
+ JS_ASSERT(begin <= end);
+ uint32_t length = end - begin;
+
+ if (!arrayBuffer->hasData())
+ return create(cx, 0);
+
+ JSObject *slice = create(cx, length, false);
+ if (!slice)
+ return nullptr;
+ memcpy(slice->as<ArrayBufferObject>().dataPointer(), arrayBuffer->dataPointer() + begin, length);
+ return slice;
+}
+
+bool
+ArrayBufferObject::createDataViewForThisImpl(JSContext *cx, CallArgs args)
+{
+ JS_ASSERT(IsArrayBuffer(args.thisv()));
+
+ /*
+ * This method is only called for |DataView(alienBuf, ...)| which calls
+ * this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|,
+ * ergo there must be at least two arguments.
+ */
+ JS_ASSERT(args.length() >= 2);
+
+ Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject());
+
+ Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
+
+ /*
+ * Pop off the passed-along prototype and delegate to normal DataViewObject
+ * construction.
+ */
+ CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base());
+ return DataViewObject::construct(cx, buffer, frobbedArgs, proto);
+}
+
+bool
+ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
+}
+
+/* static */ bool
+ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
+ uint8_t **data)
+{
+ // If the ArrayBuffer's elements are dynamically allocated and nothing else
+ // prevents us from stealing them, transfer ownership directly. Otherwise,
+ // the elements are small and allocated inside the ArrayBuffer object's GC
+ // header so we must make a copy.
+ ObjectElements *transferableHeader;
+ bool stolen;
+ if (buffer->hasDynamicElements() && !buffer->isAsmJSArrayBuffer()) {
+ stolen = true;
+ transferableHeader = buffer->getElementsHeader();
+ } else {
+ stolen = false;
+
+ uint32_t byteLen = buffer->byteLength();
+ transferableHeader = AllocateArrayBufferContents(cx, byteLen);
+ if (!transferableHeader)
+ return false;
+
+ initElementsHeader(transferableHeader, byteLen);
+ void *headerDataPointer = reinterpret_cast<void*>(transferableHeader->elements());
+ memcpy(headerDataPointer, buffer->dataPointer(), byteLen);
+ }
+
+ JS_ASSERT(!IsInsideNursery(cx->runtime(), transferableHeader));
+ *contents = transferableHeader;
+ *data = reinterpret_cast<uint8_t *>(transferableHeader + 1);
+
+ // Neuter the views, which may also mprotect(PROT_NONE) the buffer. So do
+ // it after copying out the data.
+ if (!ArrayBufferObject::neuterViews(cx, buffer))
+ return false;
+
+ // If the elements were taken from the neutered buffer, revert it back to
+ // using inline storage so it doesn't attempt to free the stolen elements
+ // when finalized.
+ if (stolen)
+ buffer->changeContents(cx, ObjectElements::fromElements(buffer->fixedElements()));
+
+ buffer->neuter(cx);
+ return true;
+}
+
+void
+ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
+{
+ /*
+ * If this object changes, it will get marked via the private data barrier,
+ * so it's safe to leave it Unbarriered.
+ */
+ JSObject *delegate = static_cast<JSObject*>(obj->getPrivate());
+ if (delegate) {
+ JS_SET_TRACING_LOCATION(trc, &obj->privateRef(obj->numFixedSlots()));
+ MarkObjectUnbarriered(trc, &delegate, "arraybuffer.delegate");
+ obj->setPrivateUnbarriered(delegate);
+ }
+
+ // ArrayBufferObjects need to maintain a list of possibly-weak pointers to
+ // their views. The straightforward way to update the weak pointers would
+ // be in the views' finalizers, but giving views finalizers means they
+ // cannot be swept in the background. This results in a very high
+ // performance cost. Instead, ArrayBufferObjects with a single view hold a
+ // strong pointer to the view. This can entrain garbage when the single
+ // view becomes otherwise unreachable while the buffer is still live, but
+ // this is expected to be rare. ArrayBufferObjects with 0-1 views are
+ // expected to be by far the most common cases. ArrayBufferObjects with
+ // multiple views are collected into a linked list during collection, and
+ // then swept to prune out their dead views.
+
+ ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
+ ArrayBufferViewObject *viewsHead = GetViewList(&buffer);
+ if (!viewsHead)
+ return;
+
+ // During minor collections, mark weak pointers on the buffer strongly.
+ if (trc->runtime->isHeapMinorCollecting()) {
+ MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.viewlist");
+ ArrayBufferViewObject *prior = GetViewList(&buffer);
+ for (ArrayBufferViewObject *view = prior->nextView();
+ view;
+ prior = view, view = view->nextView())
+ {
+ MarkObjectUnbarriered(trc, &view, "arraybuffer.views");
+ prior->setNextView(view);
+ }
+ return;
+ }
+
+ ArrayBufferViewObject *firstView = viewsHead;
+ if (firstView->nextView() == nullptr) {
+ // Single view: mark it, but only if we're actually doing a GC pass
+ // right now. Otherwise, the tracing pass for barrier verification will
+ // fail if we add another view and the pointer becomes weak.
+ if (IS_GC_MARKING_TRACER(trc))
+ MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.singleview");
+ } else {
+ // Multiple views: do not mark, but append buffer to list.
+ if (IS_GC_MARKING_TRACER(trc)) {
+ // obj_trace may be called multiple times before sweep(), so avoid
+ // adding this buffer to the list multiple times.
+ if (firstView->bufferLink() == UNSET_BUFFER_LINK) {
+ JS_ASSERT(obj->compartment() == firstView->compartment());
+ ArrayBufferObject **bufList = &obj->compartment()->gcLiveArrayBuffers;
+ firstView->setBufferLink(*bufList);
+ *bufList = &obj->as<ArrayBufferObject>();
+ } else {
+#ifdef DEBUG
+ bool found = false;
+ for (ArrayBufferObject *p = obj->compartment()->gcLiveArrayBuffers;
+ p;
+ p = GetViewList(p)->bufferLink())
+ {
+ if (p == obj)
+ {
+ JS_ASSERT(!found);
+ found = true;
+ }
+ }
+#endif
+ }
+ }
+ }
+}
+
+void
+ArrayBufferObject::sweep(JSCompartment *compartment)
+{
+ ArrayBufferObject *buffer = compartment->gcLiveArrayBuffers;
+ JS_ASSERT(buffer != UNSET_BUFFER_LINK);
+ compartment->gcLiveArrayBuffers = nullptr;
+
+ while (buffer) {
+ ArrayBufferViewObject *viewsHead = GetViewList(buffer);
+ JS_ASSERT(viewsHead);
+
+ ArrayBufferObject *nextBuffer = viewsHead->bufferLink();
+ JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
+ viewsHead->setBufferLink(UNSET_BUFFER_LINK);
+
+ // Rebuild the list of views of the ArrayBufferObject, discarding dead
+ // views. If there is only one view, it will have already been marked.
+ ArrayBufferViewObject *prevLiveView = nullptr;
+ ArrayBufferViewObject *view = viewsHead;
+ while (view) {
+ JS_ASSERT(buffer->compartment() == view->compartment());
+ ArrayBufferViewObject *nextView = view->nextView();
+ if (!IsObjectAboutToBeFinalized(&view)) {
+ view->setNextView(prevLiveView);
+ prevLiveView = view;
+ }
+ view = nextView;
+ }
+ SetViewList(buffer, prevLiveView);
+
+ buffer = nextBuffer;
+ }
+}
+
+void
+ArrayBufferObject::resetArrayBufferList(JSCompartment *comp)
+{
+ ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
+ JS_ASSERT(buffer != UNSET_BUFFER_LINK);
+ comp->gcLiveArrayBuffers = nullptr;
+
+ while (buffer) {
+ ArrayBufferViewObject *view = GetViewList(buffer);
+ JS_ASSERT(view);
+
+ ArrayBufferObject *nextBuffer = view->bufferLink();
+ JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
+
+ view->setBufferLink(UNSET_BUFFER_LINK);
+ buffer = nextBuffer;
+ }
+}
+
+/* static */ bool
+ArrayBufferObject::saveArrayBufferList(JSCompartment *comp, ArrayBufferVector &vector)
+{
+ ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
+ while (buffer) {
+ JS_ASSERT(buffer != UNSET_BUFFER_LINK);
+ if (!vector.append(buffer))
+ return false;
+
+ ArrayBufferViewObject *view = GetViewList(buffer);
+ JS_ASSERT(view);
+ buffer = view->bufferLink();
+ }
+ return true;
+}
+
+/* static */ void
+ArrayBufferObject::restoreArrayBufferLists(ArrayBufferVector &vector)
+{
+ for (ArrayBufferObject **p = vector.begin(); p != vector.end(); p++) {
+ ArrayBufferObject *buffer = *p;
+ JSCompartment *comp = buffer->compartment();
+ ArrayBufferViewObject *firstView = GetViewList(buffer);
+ JS_ASSERT(firstView);
+ JS_ASSERT(firstView->compartment() == comp);
+ JS_ASSERT(firstView->bufferLink() == UNSET_BUFFER_LINK);
+ firstView->setBufferLink(comp->gcLiveArrayBuffers);
+ comp->gcLiveArrayBuffers = buffer;
+ }
+}
+
+bool
+ArrayBufferObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+ MutableHandleObject objp, MutableHandleShape propp)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+
+ bool delegateResult = JSObject::lookupGeneric(cx, delegate, id, objp, propp);
+
+ /* If false, there was an error, so propagate it.
+ * Otherwise, if propp is non-null, the property
+ * was found. Otherwise it was not
+ * found so look in the prototype chain.
+ */
+ if (!delegateResult)
+ return false;
+
+ if (propp) {
+ if (objp == delegate)
+ objp.set(obj);
+ return true;
+ }
+
+ RootedObject proto(cx, obj->getProto());
+ if (!proto) {
+ objp.set(nullptr);
+ propp.set(nullptr);
+ return true;
+ }
+
+ return JSObject::lookupGeneric(cx, proto, id, objp, propp);
+}
+
+bool
+ArrayBufferObject::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+ MutableHandleObject objp, MutableHandleShape propp)
+{
+ Rooted<jsid> id(cx, NameToId(name));
+ return obj_lookupGeneric(cx, obj, id, objp, propp);
+}
+
+bool
+ArrayBufferObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+ MutableHandleObject objp, MutableHandleShape propp)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+
+ /*
+ * If false, there was an error, so propagate it.
+ * Otherwise, if propp is non-null, the property
+ * was found. Otherwise it was not
+ * found so look in the prototype chain.
+ */
+ if (!JSObject::lookupElement(cx, delegate, index, objp, propp))
+ return false;
+
+ if (propp) {
+ if (objp == delegate)
+ objp.set(obj);
+ return true;
+ }
+
+ RootedObject proto(cx, obj->getProto());
+ if (proto)
+ return JSObject::lookupElement(cx, proto, index, objp, propp);
+
+ objp.set(nullptr);
+ propp.set(nullptr);
+ return true;
+}
+
+bool
+ArrayBufferObject::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+ MutableHandleObject objp, MutableHandleShape propp)
+{
+ Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+ return obj_lookupGeneric(cx, obj, id, objp, propp);
+}
+
+bool
+ArrayBufferObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+ AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::DefineGeneric(cx, delegate, id, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_defineProperty(JSContext *cx, HandleObject obj,
+ HandlePropertyName name, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+ Rooted<jsid> id(cx, NameToId(name));
+ return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+ AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
+
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::DefineElement(cx, delegate, index, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
+{
+ Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+ return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
+}
+
+bool
+ArrayBufferObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
+ HandleId id, MutableHandleValue vp)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::GetProperty(cx, delegate, receiver, id, vp);
+}
+
+bool
+ArrayBufferObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+ HandlePropertyName name, MutableHandleValue vp)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ Rooted<jsid> id(cx, NameToId(name));
+ return baseops::GetProperty(cx, delegate, receiver, id, vp);
+}
+
+bool
+ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
+ HandleObject receiver, uint32_t index, MutableHandleValue vp)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::GetElement(cx, delegate, receiver, index, vp);
+}
+
+bool
+ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj,
+ HandleObject receiver, HandleSpecialId sid,
+ MutableHandleValue vp)
+{
+ Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+ return obj_getGeneric(cx, obj, receiver, id, vp);
+}
+
+bool
+ArrayBufferObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
+ MutableHandleValue vp, bool strict)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+
+ return baseops::SetPropertyHelper<SequentialExecution>(cx, delegate, obj, id, 0, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_setProperty(JSContext *cx, HandleObject obj,
+ HandlePropertyName name, MutableHandleValue vp, bool strict)
+{
+ Rooted<jsid> id(cx, NameToId(name));
+ return obj_setGeneric(cx, obj, id, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_setElement(JSContext *cx, HandleObject obj,
+ uint32_t index, MutableHandleValue vp, bool strict)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+
+ return baseops::SetElementHelper(cx, delegate, obj, index, 0, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_setSpecial(JSContext *cx, HandleObject obj,
+ HandleSpecialId sid, MutableHandleValue vp, bool strict)
+{
+ Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
+ return obj_setGeneric(cx, obj, id, vp, strict);
+}
+
+bool
+ArrayBufferObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
+ HandleId id, unsigned *attrsp)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::GetAttributes(cx, delegate, id, attrsp);
+}
+
+bool
+ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
+ HandleId id, unsigned *attrsp)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::SetAttributes(cx, delegate, id, attrsp);
+}
+
+bool
+ArrayBufferObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+ bool *succeeded)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::DeleteProperty(cx, delegate, name, succeeded);
+}
+
+bool
+ArrayBufferObject::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
+ bool *succeeded)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::DeleteElement(cx, delegate, index, succeeded);
+}
+
+bool
+ArrayBufferObject::obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+ bool *succeeded)
+{
+ RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
+ if (!delegate)
+ return false;
+ return baseops::DeleteSpecial(cx, delegate, sid, succeeded);
+}
+
+bool
+ArrayBufferObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
+ MutableHandleValue statep, MutableHandleId idp)
+{
+ statep.setNull();
+ return true;
+}
+
+/*
+ * ArrayBufferViewObject
+ */
+
+/*
+ * This method is used to trace TypedArrayObjects and DataViewObjects. We need
+ * a custom tracer because some of an ArrayBufferViewObject's reserved slots
+ * are weak references, and some need to be updated specially during moving
+ * GCs.
+ */
+/* static */ void
+ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
+{
+ HeapSlot &bufSlot = obj->getReservedSlotRef(BUFFER_SLOT);
+ MarkSlot(trc, &bufSlot, "typedarray.buffer");
+
+ /* 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>();
+ int32_t offset = obj->getReservedSlot(BYTEOFFSET_SLOT).toInt32();
+ obj->initPrivate(buf.dataPointer() + offset);
+ }
+
+ /* Update NEXT_VIEW_SLOT, if the view moved. */
+ IsSlotMarked(&obj->getReservedSlotRef(NEXT_VIEW_SLOT));
+}
+
+void
+ArrayBufferViewObject::prependToViews(ArrayBufferViewObject *viewsHead)
+{
+ setNextView(viewsHead);
+
+ // Move the multiview buffer list link into this view since we're
+ // prepending it to the list.
+ setBufferLink(viewsHead->bufferLink());
+ viewsHead->setBufferLink(UNSET_BUFFER_LINK);
+}
+
+void
+ArrayBufferViewObject::neuter(JSContext *cx)
+{
+ if (is<DataViewObject>())
+ as<DataViewObject>().neuter();
+ else if (is<TypedArrayObject>())
+ as<TypedArrayObject>().neuter(cx);
+ else
+ as<TypedObject>().neuter(cx);
+}
+
+/* JS Friend API */
+
+JS_FRIEND_API(bool)
+JS_IsArrayBufferViewObject(JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? obj->is<ArrayBufferViewObject>() : false;
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetArrayBufferByteLength(JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? obj->as<ArrayBufferObject>().byteLength() : 0;
+}
+
+JS_FRIEND_API(uint8_t *)
+JS_GetArrayBufferData(JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ return obj->as<ArrayBufferObject>().dataPointer();
+}
+
+JS_FRIEND_API(uint8_t *)
+JS_GetStableArrayBufferData(JSContext *cx, JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+
+ Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+ if (!ArrayBufferObject::ensureNonInline(cx, buffer))
+ return nullptr;
+
+ return buffer->dataPointer();
+}
+
+JS_FRIEND_API(bool)
+JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj)
+{
+ if (!obj->is<ArrayBufferObject>()) {
+ JS_ReportError(cx, "ArrayBuffer object required");
+ return false;
+ }
+
+ Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+ if (!ArrayBufferObject::neuterViews(cx, buffer))
+ return false;
+ buffer->neuter(cx);
+ return true;
+}
+
+JS_FRIEND_API(JSObject *)
+JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
+{
+ JS_ASSERT(nbytes <= INT32_MAX);
+ return ArrayBufferObject::create(cx, nbytes);
+}
+
+JS_PUBLIC_API(JSObject *)
+JS_NewArrayBufferWithContents(JSContext *cx, void *contents)
+{
+ JS_ASSERT(contents);
+ JSObject *obj = ArrayBufferObject::create(cx, 0);
+ if (!obj)
+ return nullptr;
+ js::ObjectElements *elements = reinterpret_cast<js::ObjectElements *>(contents);
+ obj->setDynamicElements(elements);
+ JS_ASSERT(GetViewList(&obj->as<ArrayBufferObject>()) == nullptr);
+
+#ifdef JSGC_GENERATIONAL
+ cx->runtime()->gcNursery.notifyNewElements(obj, elements);
+#endif
+ return obj;
+}
+
+JS_PUBLIC_API(bool)
+JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes,
+ void **contents, uint8_t **data)
+{
+ js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes);
+ if (!header)
+ return false;
+
+ ArrayBufferObject::updateElementsHeader(header, nbytes);
+
+ *contents = header;
+ *data = reinterpret_cast<uint8_t*>(header->elements());
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+JS_ReallocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void **contents, uint8_t **data)
+{
+ js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes, *contents);
+ if (!header)
+ return false;
+
+ ArrayBufferObject::initElementsHeader(header, nbytes);
+
+ *contents = header;
+ *data = reinterpret_cast<uint8_t*>(header->elements());
+ return true;
+}
+
+JS_FRIEND_API(bool)
+JS_IsArrayBufferObject(JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ return obj ? obj->is<ArrayBufferObject>() : false;
+}
+
+JS_PUBLIC_API(bool)
+JS_StealArrayBufferContents(JSContext *cx, HandleObject objArg, void **contents, uint8_t **data)
+{
+ JSObject *obj = CheckedUnwrap(objArg);
+ if (!obj)
+ return false;
+
+ if (!obj->is<ArrayBufferObject>()) {
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+ return false;
+ }
+
+ Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+ if (!ArrayBufferObject::stealContents(cx, buffer, contents, data))
+ return false;
+
+ return true;
+}
+
+JS_FRIEND_API(void *)
+JS_GetArrayBufferViewData(JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
+ : obj->as<TypedArrayObject>().viewData();
+}
+
+JS_FRIEND_API(JSObject *)
+JS_GetArrayBufferViewBuffer(JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return nullptr;
+ return obj->as<ArrayBufferViewObject>().bufferObject();
+}
+
+JS_FRIEND_API(uint32_t)
+JS_GetArrayBufferViewByteLength(JSObject *obj)
+{
+ obj = CheckedUnwrap(obj);
+ if (!obj)
+ return 0;
+ return obj->is<DataViewObject>()
+ ? obj->as<DataViewObject>().byteLength()
+ : obj->as<TypedArrayObject>().byteLength();
+}
+
+JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
+{
+ if (!(obj = CheckedUnwrap(obj)))
+ return nullptr;
+ if (!(obj->is<ArrayBufferViewObject>()))
+ return nullptr;
+
+ *length = obj->is<DataViewObject>()
+ ? obj->as<DataViewObject>().byteLength()
+ : obj->as<TypedArrayObject>().byteLength();
+
+ *data = static_cast<uint8_t*>(obj->is<DataViewObject>()
+ ? obj->as<DataViewObject>().dataPointer()
+ : obj->as<TypedArrayObject>().viewData());
+ return obj;
+}
+
+JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
+{
+ if (!(obj = CheckedUnwrap(obj)))
+ return nullptr;
+ if (!obj->is<ArrayBufferObject>())
+ return nullptr;
+
+ *length = obj->as<ArrayBufferObject>().byteLength();
+ *data = obj->as<ArrayBufferObject>().dataPointer();
+
+ return obj;
+}
+
new file mode 100644
--- /dev/null
+++ b/js/src/vm/ArrayBufferObject.h
@@ -0,0 +1,317 @@
+/* -*- 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_ArrayBufferObject_h
+#define vm_ArrayBufferObject_h
+
+#include "jsobj.h"
+
+#include "builtin/TypedObjectConstants.h"
+#include "vm/Runtime.h"
+
+typedef struct JSProperty JSProperty;
+
+namespace js {
+
+class ArrayBufferViewObject;
+
+// The inheritance hierarchy for the various classes relating to typed arrays
+// is as follows.
+//
+// - JSObject
+// - ArrayBufferObject
+// - ArrayBufferViewObject
+// - DataViewObject
+// - TypedArrayObject (declared in vm/TypedArrayObject.h)
+// - TypedArrayObjectTemplate
+// - Int8ArrayObject
+// - Uint8ArrayObject
+// - ...
+// - TypedObject (declared in builtin/TypedObject.h)
+//
+// Note that |TypedArrayObjectTemplate| is just an implementation
+// detail that makes implementing its various subclasses easier.
+
+typedef Vector<ArrayBufferObject *, 0, SystemAllocPolicy> ArrayBufferVector;
+
+/*
+ * ArrayBufferObject
+ *
+ * This class holds the underlying raw buffer that the various
+ * ArrayBufferViewObject subclasses (DataViewObject and the TypedArrays)
+ * access. It can be created explicitly and passed to an ArrayBufferViewObject
+ * subclass, or can be created implicitly by constructing a TypedArrayObject
+ * with a size.
+ */
+class ArrayBufferObject : public JSObject
+{
+ static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
+ static bool fun_slice_impl(JSContext *cx, CallArgs args);
+
+ public:
+ 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_slice(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);
+
+ static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, bool clear = true);
+
+ static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
+ uint32_t begin, uint32_t end);
+
+ static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
+ static bool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);
+
+ template<typename T>
+ static bool createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args);
+
+ template<typename T>
+ static bool createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp);
+
+ static void obj_trace(JSTracer *trc, JSObject *obj);
+
+ static bool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+ MutableHandleObject objp, MutableHandleShape propp);
+ static bool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+ MutableHandleObject objp, MutableHandleShape propp);
+ static bool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+ MutableHandleObject objp, MutableHandleShape propp);
+ static bool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+ MutableHandleObject objp, MutableHandleShape propp);
+
+ static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+ static bool obj_defineProperty(JSContext *cx, HandleObject obj,
+ HandlePropertyName name, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+ static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+ static bool obj_defineSpecial(JSContext *cx, HandleObject obj,
+ HandleSpecialId sid, HandleValue v,
+ PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
+
+ static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
+ HandleId id, MutableHandleValue vp);
+
+ static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
+ HandlePropertyName name, MutableHandleValue vp);
+
+ static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
+ uint32_t index, MutableHandleValue vp);
+
+ static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
+ HandleSpecialId sid, MutableHandleValue vp);
+
+ static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
+ MutableHandleValue vp, bool strict);
+ static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+ MutableHandleValue vp, bool strict);
+ static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
+ MutableHandleValue vp, bool strict);
+ static bool obj_setSpecial(JSContext *cx, HandleObject obj,
+ HandleSpecialId sid, MutableHandleValue vp, bool strict);
+
+ static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
+ HandleId id, unsigned *attrsp);
+ static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
+ HandleId id, unsigned *attrsp);
+
+ static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
+ bool *succeeded);
+ static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
+ bool *succeeded);
+ static bool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+ bool *succeeded);
+
+ static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
+ MutableHandleValue statep, MutableHandleId idp);
+
+ static void sweep(JSCompartment *rt);
+
+ static void resetArrayBufferList(JSCompartment *rt);
+ static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
+ static void restoreArrayBufferLists(ArrayBufferVector &vector);
+
+ static bool stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
+ uint8_t **data);
+
+ static void updateElementsHeader(js::ObjectElements *header, uint32_t bytes) {
+ header->initializedLength = bytes;
+
+ // NB: one or both of these fields is clobbered by GetViewList to store
+ // the 'views' link. Set them to 0 to effectively initialize 'views'
+ // to nullptr.
+ header->length = 0;
+ header->capacity = 0;
+ }
+
+ static void initElementsHeader(js::ObjectElements *header, uint32_t bytes) {
+ header->flags = 0;
+ updateElementsHeader(header, bytes);
+ }
+
+ static uint32_t headerInitializedLength(const js::ObjectElements *header) {
+ return header->initializedLength;
+ }
+
+ void addView(ArrayBufferViewObject *view);
+
+ void changeContents(JSContext *cx, ObjectElements *newHeader);
+
+ /*
+ * Ensure data is not stored inline in the object. Used when handing back a
+ * GC-safe pointer.
+ */
+ static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer);
+
+ uint32_t byteLength() const {
+ return getElementsHeader()->initializedLength;
+ }
+
+ /*
+ * Neuter all views of an ArrayBuffer.
+ */
+ static bool neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer);
+
+ inline uint8_t * dataPointer() const {
+ return (uint8_t *) elements;
+ }
+
+ /*
+ * Discard the ArrayBuffer contents. For asm.js buffers, at least, should
+ * be called after neuterViews().
+ */
+ void neuter(JSContext *cx);
+
+ /*
+ * Check if the arrayBuffer contains any data. This will return false for
+ * ArrayBuffer.prototype and neutered ArrayBuffers.
+ */
+ bool hasData() const {
+ return getClass() == &class_;
+ }
+
+ bool isAsmJSArrayBuffer() const {
+ return getElementsHeader()->isAsmJSArrayBuffer();
+ }
+ bool isNeutered() const {
+ return getElementsHeader()->isNeuteredBuffer();
+ }
+ static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
+ static bool neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
+ static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
+};
+
+/*
+ * ArrayBufferViewObject
+ *
+ * Common definitions shared by all ArrayBufferViews.
+ */
+
+class ArrayBufferViewObject : public JSObject
+{
+ protected:
+ /* Offset of view in underlying ArrayBufferObject */
+ static const size_t BYTEOFFSET_SLOT = JS_TYPEDOBJ_SLOT_BYTEOFFSET;
+
+ /* Byte length of view */
+ static const size_t BYTELENGTH_SLOT = JS_TYPEDOBJ_SLOT_BYTELENGTH;
+
+ /* Underlying ArrayBufferObject */
+ static const size_t BUFFER_SLOT = JS_TYPEDOBJ_SLOT_OWNER;
+
+ /* ArrayBufferObjects point to a linked list of views, chained through this slot */
+ static const size_t NEXT_VIEW_SLOT = JS_TYPEDOBJ_SLOT_NEXT_VIEW;
+
+ /*
+ * When ArrayBufferObjects are traced during GC, they construct a linked
+ * list of ArrayBufferObjects with more than one view, chained through this
+ * slot of the first view of each ArrayBufferObject.
+ */
+ static const size_t NEXT_BUFFER_SLOT = JS_TYPEDOBJ_SLOT_NEXT_BUFFER;
+
+ public:
+ JSObject *bufferObject() const {
+ return &getFixedSlot(BUFFER_SLOT).toObject();
+ }
+
+ ArrayBufferObject *bufferLink() {
+ return static_cast<ArrayBufferObject*>(getFixedSlot(NEXT_BUFFER_SLOT).toPrivate());
+ }
+
+ inline void setBufferLink(ArrayBufferObject *buffer);
+
+ ArrayBufferViewObject *nextView() const {
+ return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());
+ }
+
+ inline void setNextView(ArrayBufferViewObject *view);
+
+ void prependToViews(ArrayBufferViewObject *viewsHead);
+
+ void neuter(JSContext *cx);
+
+ static void trace(JSTracer *trc, JSObject *obj);
+};
+
+bool
+ToClampedIndex(JSContext *cx, HandleValue v, uint32_t length, uint32_t *out);
+
+inline void
+PostBarrierTypedArrayObject(JSObject *obj)
+{
+#ifdef JSGC_GENERATIONAL
+ JS_ASSERT(obj);
+ JSRuntime *rt = obj->runtimeFromMainThread();
+ if (!rt->isHeapBusy() && !IsInsideNursery(rt, obj))
+ rt->gcStoreBuffer.putWholeCell(obj);
+#endif
+}
+
+inline void
+InitArrayBufferViewDataPointer(ArrayBufferViewObject *obj, ArrayBufferObject *buffer, size_t byteOffset)
+{
+ /*
+ * N.B. The base of the array's data is stored in the object's
+ * private data rather than a slot to avoid alignment restrictions
+ * on private Values.
+ */
+ obj->initPrivate(buffer->dataPointer() + byteOffset);
+ PostBarrierTypedArrayObject(obj);
+}
+
+MOZ_ALWAYS_INLINE bool
+IsArrayBuffer(HandleValue v)
+{
+ return v.isObject() && v.toObject().is<ArrayBufferObject>();
+}
+
+inline void
+ArrayBufferViewObject::setBufferLink(ArrayBufferObject *buffer)
+{
+ setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(buffer));
+ PostBarrierTypedArrayObject(this);
+}
+
+inline void
+ArrayBufferViewObject::setNextView(ArrayBufferViewObject *view)
+{
+ setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(view));
+ PostBarrierTypedArrayObject(this);
+}
+
+} // namespace js
+
+#endif // vm_ArrayBufferObject_h
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -2166,21 +2166,21 @@ intrinsic_SetForkJoinTargetRegionPar(For
// the middle of another. This is because the guarding code
// assumes that handles, which never straddle across elements,
// will either be contained entirely within the target region or
// be contained entirely without of the region, and not straddling
// the region nor encompassing it.
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(argc == 3);
- JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedDatum>());
+ JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());
JS_ASSERT(args[1].isInt32());
JS_ASSERT(args[2].isInt32());
- uint8_t *mem = args[0].toObject().as<TypedDatum>().typedMem();
+ uint8_t *mem = args[0].toObject().as<TypedObject>().typedMem();
int32_t start = args[1].toInt32();
int32_t end = args[2].toInt32();
cx->targetRegionStart = mem + start;
cx->targetRegionEnd = mem + end;
return true;
}
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -693,40 +693,37 @@ static const JSFunctionSpec intrinsic_fu
JS_FNINFO("ForkJoinGetSlice",
intrinsic_ForkJoinGetSlice,
&intrinsic_ForkJoinGetSlice_jitInfo, 1, 0),
JS_FNINFO("InParallelSection",
intrinsic_InParallelSection,
&intrinsic_InParallelSection_jitInfo, 0, 0),
// See builtin/TypedObject.h for descriptors of the typedobj functions.
- JS_FN("NewTypedHandle",
- js::NewTypedHandle,
+ JS_FN("NewOpaqueTypedObject",
+ js::NewOpaqueTypedObject,
1, 0),
- JS_FN("NewDerivedTypedDatum",
- js::NewDerivedTypedDatum,
+ JS_FN("NewDerivedTypedObject",
+ js::NewDerivedTypedObject,
3, 0),
- JS_FNINFO("AttachHandle",
- JSNativeThreadSafeWrapper<js::AttachHandle>,
- &js::AttachHandleJitInfo, 5, 0),
+ JS_FNINFO("AttachTypedObject",
+ JSNativeThreadSafeWrapper<js::AttachTypedObject>,
+ &js::AttachTypedObjectJitInfo, 5, 0),
JS_FNINFO("ObjectIsTypeDescr",
JSNativeThreadSafeWrapper<js::ObjectIsTypeDescr>,
&js::ObjectIsTypeDescrJitInfo, 5, 0),
- JS_FNINFO("ObjectIsTypeRepresentation",
- JSNativeThreadSafeWrapper<js::ObjectIsTypeRepresentation>,
- &js::ObjectIsTypeRepresentationJitInfo, 5, 0),
- JS_FNINFO("ObjectIsTypedObject",
- JSNativeThreadSafeWrapper<js::ObjectIsTypedObject>,
- &js::ObjectIsTypedObjectJitInfo, 5, 0),
- JS_FNINFO("ObjectIsTypedHandle",
- JSNativeThreadSafeWrapper<js::ObjectIsTypedHandle>,
- &js::ObjectIsTypedHandleJitInfo, 5, 0),
- JS_FN("NewHandle",
- js::NewTypedHandle,
- 1, 0),
+ JS_FNINFO("ObjectIsTransparentTypedObject",
+ JSNativeThreadSafeWrapper<js::ObjectIsTransparentTypedObject>,
+ &js::ObjectIsTransparentTypedObjectJitInfo, 5, 0),
+ JS_FNINFO("TypedObjectIsAttached",
+ JSNativeThreadSafeWrapper<js::TypedObjectIsAttached>,
+ &js::TypedObjectIsAttachedJitInfo, 1, 0),
+ JS_FNINFO("ObjectIsOpaqueTypedObject",
+ JSNativeThreadSafeWrapper<js::ObjectIsOpaqueTypedObject>,
+ &js::ObjectIsOpaqueTypedObjectJitInfo, 5, 0),
JS_FNINFO("ClampToUint8",
JSNativeThreadSafeWrapper<js::ClampToUint8>,
&js::ClampToUint8JitInfo, 1, 0),
JS_FNINFO("Memcpy",
JSNativeThreadSafeWrapper<js::Memcpy>,
&js::MemcpyJitInfo, 5, 0),
JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
JS_FN("GetFloat32x4TypeDescr", js::GetFloat32x4TypeDescr, 0, 0),
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -38,41 +38,25 @@
#include "vm/WrapperObject.h"
#include "jsatominlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "vm/Shape-inl.h"
-#if JS_USE_NEW_OBJECT_REPRESENTATION
-// See the comment above OldObjectRepresentationHack.
-# error "TypedArray support for new object representation unimplemented."
-#endif
-
using namespace js;
using namespace js::gc;
using namespace js::types;
using mozilla::IsNaN;
using mozilla::PodCopy;
using JS::CanonicalizeNaN;
using JS::GenericNaN;
-/*
- * Allocate array buffers with the maximum number of fixed slots marked as
- * reserved, so that the fixed slots may be used for the buffer's contents.
- * The last fixed slot is kept for the object's private data.
- */
-static const uint8_t ARRAYBUFFER_RESERVED_SLOTS = JSObject::MAX_FIXED_SLOTS - 1;
-
-// Sentinel value used to initialize ArrayBufferViewObjects' NEXT_BUFFER_SLOTs
-// to show that they have not yet been added to any ArrayBufferObject list.
-js::ArrayBufferObject * const UNSET_BUFFER_LINK = reinterpret_cast<js::ArrayBufferObject*>(0x2);
-
static bool
ValueIsLength(const Value &v, uint32_t *len)
{
if (v.isInt32()) {
int32_t i = v.toInt32();
if (i < 0)
return false;
*len = i;
@@ -91,1092 +75,16 @@ ValueIsLength(const Value &v, uint32_t *
*len = length;
return true;
}
return false;
}
/*
- * Convert |v| to an array index for an array of length |length| per
- * the Typed Array Specification section 7.0, |subarray|. If successful,
- * the output value is in the range [0, length].
- */
-static bool
-ToClampedIndex(JSContext *cx, HandleValue v, uint32_t length, uint32_t *out)
-{
- int32_t result;
- if (!ToInt32(cx, v, &result))
- return false;
- if (result < 0) {
- result += length;
- if (result < 0)
- result = 0;
- } else if (uint32_t(result) > length) {
- result = length;
- }
- *out = uint32_t(result);
- return true;
-}
-
-/*
- * ArrayBufferObject
- *
- * This class holds the underlying raw buffer that the TypedArrayObject classes
- * access. It can be created explicitly and passed to a TypedArrayObject, or
- * can be created implicitly by constructing a TypedArrayObject with a size.
- */
-
-MOZ_ALWAYS_INLINE bool
-IsArrayBuffer(HandleValue v)
-{
- return v.isObject() && v.toObject().hasClass(&ArrayBufferObject::class_);
-}
-
-MOZ_ALWAYS_INLINE bool
-ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
-{
- JS_ASSERT(IsArrayBuffer(args.thisv()));
- args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
- return true;
-}
-
-bool
-ArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
-}
-
-bool
-ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
-{
- JS_ASSERT(IsArrayBuffer(args.thisv()));
-
- Rooted<ArrayBufferObject*> thisObj(cx, &args.thisv().toObject().as<ArrayBufferObject>());
-
- // these are the default values
- uint32_t length = thisObj->byteLength();
- uint32_t begin = 0, end = length;
-
- if (args.length() > 0) {
- if (!ToClampedIndex(cx, args[0], length, &begin))
- return false;
-
- if (args.length() > 1) {
- if (!ToClampedIndex(cx, args[1], length, &end))
- return false;
- }
- }
-
- if (begin > end)
- begin = end;
-
- JSObject *nobj = createSlice(cx, thisObj, begin, end);
- if (!nobj)
- return false;
- args.rval().setObject(*nobj);
- return true;
-}
-
-bool
-ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsArrayBuffer, fun_slice_impl>(cx, args);
-}
-
-/*
- * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
- */
-bool
-ArrayBufferObject::fun_isView(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- args.rval().setBoolean(args.get(0).isObject() &&
- JS_IsArrayBufferViewObject(&args.get(0).toObject()));
- return true;
-}
-
-/*
- * new ArrayBuffer(byteLength)
- */
-bool
-ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
-{
- int32_t nbytes = 0;
- CallArgs args = CallArgsFromVp(argc, vp);
- if (argc > 0 && !ToInt32(cx, args[0], &nbytes))
- return false;
-
- if (nbytes < 0) {
- /*
- * We're just not going to support arrays that are bigger than what will fit
- * as an integer value; if someone actually ever complains (validly), then we
- * can fix.
- */
- JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
- return false;
- }
-
- JSObject *bufobj = create(cx, uint32_t(nbytes));
- if (!bufobj)
- return false;
- args.rval().setObject(*bufobj);
- return true;
-}
-
-/*
- * Note that some callers are allowed to pass in a nullptr cx, so we allocate
- * with the cx if available and fall back to the runtime. If oldptr is given,
- * it's expected to be a previously-allocated ObjectElements* pointer that we
- * then realloc.
- */
-static ObjectElements *
-AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr)
-{
- uint32_t size = nbytes + sizeof(ObjectElements);
- ObjectElements *newheader;
-
- // if oldptr is given, then we need to do a realloc
- if (oldptr) {
- ObjectElements *oldheader = static_cast<ObjectElements *>(oldptr);
- uint32_t oldnbytes = ArrayBufferObject::headerInitializedLength(oldheader);
-
- void *p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, size) : js_realloc(oldptr, size);
- newheader = static_cast<ObjectElements *>(p);
-
- // if we grew the array, we need to set the new bytes to 0
- if (newheader && nbytes > oldnbytes)
- memset(reinterpret_cast<uint8_t*>(newheader->elements()) + oldnbytes, 0, nbytes - oldnbytes);
- } else {
- void *p = maybecx ? maybecx->runtime()->callocCanGC(size) : js_calloc(size);
- newheader = static_cast<ObjectElements *>(p);
- }
- if (!newheader) {
- if (maybecx)
- js_ReportOutOfMemory(maybecx);
- return nullptr;
- }
-
- ArrayBufferObject::updateElementsHeader(newheader, nbytes);
-
- return newheader;
-}
-
-static inline void
-PostBarrierTypedArrayObject(JSObject *obj)
-{
-#ifdef JSGC_GENERATIONAL
- JS_ASSERT(obj);
- JSRuntime *rt = obj->runtimeFromMainThread();
- if (!rt->isHeapBusy() && !IsInsideNursery(rt, obj))
- rt->gcStoreBuffer.putWholeCell(obj);
-#endif
-}
-
-// The list of views must be stored somewhere in the ArrayBufferObject, but
-// the slots are already being used for the element storage and the private
-// field is used for a delegate object. The ObjectElements header has space
-// for it, but I don't want to mess around with adding unions to it with
-// JS_USE_NEW_OBJECT_REPRESENTATION pending, since it will solve this much
-// more cleanly.
-struct OldObjectRepresentationHack {
- uint32_t flags;
- uint32_t initializedLength;
- EncapsulatedPtr<ArrayBufferViewObject> views;
-};
-
-static ArrayBufferViewObject *
-GetViewList(ArrayBufferObject *obj)
-{
- return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
-}
-
-static void
-SetViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
-{
- reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views = viewsHead;
- PostBarrierTypedArrayObject(obj);
-}
-
-static void
-InitViewList(ArrayBufferObject *obj, ArrayBufferViewObject *viewsHead)
-{
- reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views.init(viewsHead);
- PostBarrierTypedArrayObject(obj);
-}
-
-static EncapsulatedPtr<ArrayBufferViewObject> &
-GetViewListRef(ArrayBufferObject *obj)
-{
- JS_ASSERT(obj->runtimeFromMainThread()->isHeapBusy());
- return reinterpret_cast<OldObjectRepresentationHack*>(obj->getElementsHeader())->views;
-}
-
-/* static */ bool
-ArrayBufferObject::neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
- ArrayBufferViewObject *view;
- size_t numViews = 0;
- for (view = GetViewList(buffer); view; view = view->nextView()) {
- numViews++;
- view->neuter(cx);
-
- // Notify compiled jit code that the base pointer has moved.
- MarkObjectStateChange(cx, view);
- }
-
- // neuterAsmJSArrayBuffer adjusts state specific to the ArrayBuffer data
- // itself, but it only affects the behavior of views
- if (buffer->isAsmJSArrayBuffer()) {
- if (!ArrayBufferObject::neuterAsmJSArrayBuffer(cx, *buffer))
- return false;
- }
-
- // Remove buffer from the list of buffers with > 1 view.
- if (numViews > 1 && GetViewList(buffer)->bufferLink() != UNSET_BUFFER_LINK) {
- ArrayBufferObject *prev = buffer->compartment()->gcLiveArrayBuffers;
- if (prev == buffer) {
- buffer->compartment()->gcLiveArrayBuffers = GetViewList(prev)->bufferLink();
- } else {
- for (ArrayBufferObject *b = GetViewList(prev)->bufferLink();
- b;
- b = GetViewList(b)->bufferLink())
- {
- if (b == buffer) {
- GetViewList(prev)->setBufferLink(GetViewList(b)->bufferLink());
- break;
- }
- prev = b;
- }
- }
- }
-
- return true;
-}
-
-void
-ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
-{
- JS_ASSERT(!isAsmJSArrayBuffer());
-
- // Grab out data before invalidating it.
- uint32_t byteLengthCopy = byteLength();
- uintptr_t oldDataPointer = uintptr_t(dataPointer());
- ArrayBufferViewObject *viewListHead = GetViewList(this);
-
- // Update all views.
- uintptr_t newDataPointer = uintptr_t(newHeader->elements());
- for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
- uintptr_t newDataPtr = uintptr_t(view->getPrivate()) - oldDataPointer + newDataPointer;
- view->setPrivate(reinterpret_cast<uint8_t*>(newDataPtr));
-
- // Notify compiled jit code that the base pointer has moved.
- MarkObjectStateChange(cx, view);
- }
-
- // The list of views in the old header is reachable if the contents are
- // being transferred, so null it out
- SetViewList(this, nullptr);
-
-#ifdef JSGC_GENERATIONAL
- ObjectElements *oldHeader = ObjectElements::fromElements(elements);
- JS_ASSERT(oldHeader != newHeader);
- JSRuntime *rt = runtimeFromMainThread();
- if (hasDynamicElements())
- rt->gcNursery.notifyRemovedElements(this, oldHeader);
-#endif
-
- elements = newHeader->elements();
-
-#ifdef JSGC_GENERATIONAL
- if (hasDynamicElements())
- rt->gcNursery.notifyNewElements(this, newHeader);
-#endif
-
- initElementsHeader(newHeader, byteLengthCopy);
- InitViewList(this, viewListHead);
-}
-
-void
-ArrayBufferObject::neuter(JSContext *cx)
-{
- JS_ASSERT(cx);
- if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
- ObjectElements *oldHeader = getElementsHeader();
- changeContents(cx, ObjectElements::fromElements(fixedElements()));
-
- FreeOp fop(cx->runtime(), false);
- fop.free_(oldHeader);
- }
-
- uint32_t byteLen = 0;
- updateElementsHeader(getElementsHeader(), byteLen);
-
- getElementsHeader()->setIsNeuteredBuffer();
-}
-
-/* static */ bool
-ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
- if (buffer->hasDynamicElements())
- return true;
-
- ObjectElements *newHeader = AllocateArrayBufferContents(cx, buffer->byteLength());
- if (!newHeader)
- return false;
-
- void *newHeaderDataPointer = reinterpret_cast<void*>(newHeader->elements());
- memcpy(newHeaderDataPointer, buffer->dataPointer(), buffer->byteLength());
-
- buffer->changeContents(cx, newHeader);
- 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
-//
-JS_STATIC_ASSERT(sizeof(ObjectElements) < AsmJSPageSize);
-JS_STATIC_ASSERT(AsmJSAllocationGranularity == AsmJSPageSize);
-static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
-
-bool
-ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
- if (buffer->isAsmJSArrayBuffer())
- return true;
-
- // Get the entire reserved region (with all pages inaccessible).
- void *p;
-# ifdef XP_WIN
- p = VirtualAlloc(nullptr, AsmJSMappedSize, MEM_RESERVE, PAGE_NOACCESS);
- if (!p)
- return false;
-# else
- p = mmap(nullptr, AsmJSMappedSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
- if (p == MAP_FAILED)
- return false;
-# endif
-
- // Enable access to the valid region.
- JS_ASSERT(buffer->byteLength() % AsmJSAllocationGranularity == 0);
-# ifdef XP_WIN
- if (!VirtualAlloc(p, AsmJSPageSize + buffer->byteLength(), MEM_COMMIT, PAGE_READWRITE)) {
- VirtualFree(p, 0, MEM_RELEASE);
- return false;
- }
-# else
- if (mprotect(p, AsmJSPageSize + buffer->byteLength(), PROT_READ | PROT_WRITE)) {
- munmap(p, AsmJSMappedSize);
- return false;
- }
-# endif
-
- // Copy over the current contents of the typed array.
- uint8_t *data = reinterpret_cast<uint8_t*>(p) + AsmJSPageSize;
- memcpy(data, buffer->dataPointer(), buffer->byteLength());
-
- // Swap the new elements into the ArrayBufferObject.
- ObjectElements *newHeader = reinterpret_cast<ObjectElements*>(data - sizeof(ObjectElements));
- ObjectElements *oldHeader = buffer->hasDynamicElements() ? buffer->getElementsHeader()
- : nullptr;
- buffer->changeContents(cx, newHeader);
- js_free(oldHeader);
-
- // Mark the ArrayBufferObject so (1) we don't do this again, (2) we know not
- // to js_free the header in the normal way.
- newHeader->setIsAsmJSArrayBuffer();
- JS_ASSERT(data == buffer->dataPointer());
- return true;
-}
-
-void
-ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
-{
- ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
- JS_ASSERT(buffer.isAsmJSArrayBuffer());
-
- uint8_t *p = buffer.dataPointer() - AsmJSPageSize ;
- JS_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
-# ifdef XP_WIN
- VirtualFree(p, 0, MEM_RELEASE);
-# else
- munmap(p, AsmJSMappedSize);
-# endif
-}
-#else /* defined(JS_ION) && defined(JS_CPU_X64) */
-bool
-ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
- if (buffer->isAsmJSArrayBuffer())
- return true;
-
- if (!ensureNonInline(cx, buffer))
- return false;
-
- JS_ASSERT(buffer->hasDynamicElements());
- buffer->getElementsHeader()->setIsAsmJSArrayBuffer();
- return true;
-}
-
-void
-ArrayBufferObject::releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj)
-{
- fop->free_(obj->as<ArrayBufferObject>().getElementsHeader());
-}
-#endif
-
-bool
-ArrayBufferObject::neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer)
-{
-#ifdef JS_ION
- AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread();
- for (; act; act = act->prev()) {
- if (act->module().maybeHeapBufferObject() == &buffer)
- break;
- }
- if (!act)
- return true;
-
- js_ReportOverRecursed(cx);
- return false;
-#else
- return true;
-#endif
-}
-
-void
-ArrayBufferObject::addView(ArrayBufferViewObject *view)
-{
- // This view should never have been associated with a buffer before
- JS_ASSERT(view->bufferLink() == UNSET_BUFFER_LINK);
-
- // Note that pre-barriers are not needed here because either the list was
- // previously empty, in which case no pointer is being overwritten, or the
- // list was nonempty and will be made weak during this call (and weak
- // pointers cannot violate the snapshot-at-the-beginning invariant.)
-
- ArrayBufferViewObject *viewsHead = GetViewList(this);
- if (viewsHead == nullptr) {
- // This ArrayBufferObject will have a single view at this point, so it
- // is a strong pointer (it will be marked during tracing.)
- JS_ASSERT(view->nextView() == nullptr);
- } else {
- view->prependToViews(viewsHead);
- }
-
- SetViewList(this, view);
-}
-
-ArrayBufferObject *
-ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, bool clear /* = true */)
-{
- RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
- if (!obj)
- return nullptr;
- JS_ASSERT_IF(obj->isTenured(), obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT16_BACKGROUND);
- JS_ASSERT(obj->getClass() == &class_);
-
- js::Shape *empty = EmptyShape::getInitialShape(cx, &class_,
- obj->getProto(), obj->getParent(), obj->getMetadata(),
- gc::FINALIZE_OBJECT16_BACKGROUND);
- if (!empty)
- return nullptr;
- obj->setLastPropertyInfallible(empty);
-
- // ArrayBufferObjects delegate added properties to another JSObject, so
- // their internal layout can use the object's fixed slots for storage.
- // Set up the object to look like an array with an elements header.
- JS_ASSERT(!obj->hasDynamicSlots());
- JS_ASSERT(!obj->hasDynamicElements());
-
- // The beginning stores an ObjectElements header structure holding the
- // length. The rest of it is a flat data store for the array buffer.
- size_t usableSlots = ARRAYBUFFER_RESERVED_SLOTS - ObjectElements::VALUES_PER_HEADER;
-
- Handle<ArrayBufferObject*> buffer = obj.as<ArrayBufferObject>();
-
- if (nbytes > sizeof(Value) * usableSlots) {
- ObjectElements *header = AllocateArrayBufferContents(cx, nbytes);
- if (!header)
- return nullptr;
- buffer->elements = header->elements();
-
-#ifdef JSGC_GENERATIONAL
- JSRuntime *rt = buffer->runtimeFromMainThread();
- rt->gcNursery.notifyNewElements(buffer, header);
-#endif
- } else {
- buffer->setFixedElements();
- if (clear)
- memset(buffer->dataPointer(), 0, nbytes);
- }
-
- buffer->initElementsHeader(buffer->getElementsHeader(), nbytes);
-
- return buffer;
-}
-
-JSObject *
-ArrayBufferObject::createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
- uint32_t begin, uint32_t end)
-{
- JS_ASSERT(begin <= arrayBuffer->byteLength());
- JS_ASSERT(end <= arrayBuffer->byteLength());
- JS_ASSERT(begin <= end);
- uint32_t length = end - begin;
-
- if (!arrayBuffer->hasData())
- return create(cx, 0);
-
- JSObject *slice = create(cx, length, false);
- if (!slice)
- return nullptr;
- memcpy(slice->as<ArrayBufferObject>().dataPointer(), arrayBuffer->dataPointer() + begin, length);
- return slice;
-}
-
-bool
-ArrayBufferObject::createDataViewForThisImpl(JSContext *cx, CallArgs args)
-{
- JS_ASSERT(IsArrayBuffer(args.thisv()));
-
- /*
- * This method is only called for |DataView(alienBuf, ...)| which calls
- * this as |createDataViewForThis.call(alienBuf, ..., DataView.prototype)|,
- * ergo there must be at least two arguments.
- */
- JS_ASSERT(args.length() >= 2);
-
- Rooted<JSObject*> proto(cx, &args[args.length() - 1].toObject());
-
- Rooted<JSObject*> buffer(cx, &args.thisv().toObject());
-
- /*
- * Pop off the passed-along prototype and delegate to normal DataViewObject
- * construction.
- */
- CallArgs frobbedArgs = CallArgsFromVp(args.length() - 1, args.base());
- return DataViewObject::construct(cx, buffer, frobbedArgs, proto);
-}
-
-bool
-ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
-}
-
-/* static */ bool
-ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
- uint8_t **data)
-{
- // If the ArrayBuffer's elements are dynamically allocated and nothing else
- // prevents us from stealing them, transfer ownership directly. Otherwise,
- // the elements are small and allocated inside the ArrayBuffer object's GC
- // header so we must make a copy.
- ObjectElements *transferableHeader;
- bool stolen;
- if (buffer->hasDynamicElements() && !buffer->isAsmJSArrayBuffer()) {
- stolen = true;
- transferableHeader = buffer->getElementsHeader();
- } else {
- stolen = false;
-
- uint32_t byteLen = buffer->byteLength();
- transferableHeader = AllocateArrayBufferContents(cx, byteLen);
- if (!transferableHeader)
- return false;
-
- initElementsHeader(transferableHeader, byteLen);
- void *headerDataPointer = reinterpret_cast<void*>(transferableHeader->elements());
- memcpy(headerDataPointer, buffer->dataPointer(), byteLen);
- }
-
- JS_ASSERT(!IsInsideNursery(cx->runtime(), transferableHeader));
- *contents = transferableHeader;
- *data = reinterpret_cast<uint8_t *>(transferableHeader + 1);
-
- // Neuter the views, which may also mprotect(PROT_NONE) the buffer. So do
- // it after copying out the data.
- if (!ArrayBufferObject::neuterViews(cx, buffer))
- return false;
-
- // If the elements were taken from the neutered buffer, revert it back to
- // using inline storage so it doesn't attempt to free the stolen elements
- // when finalized.
- if (stolen)
- buffer->changeContents(cx, ObjectElements::fromElements(buffer->fixedElements()));
-
- buffer->neuter(cx);
- return true;
-}
-
-void
-ArrayBufferObject::obj_trace(JSTracer *trc, JSObject *obj)
-{
- /*
- * If this object changes, it will get marked via the private data barrier,
- * so it's safe to leave it Unbarriered.
- */
- JSObject *delegate = static_cast<JSObject*>(obj->getPrivate());
- if (delegate) {
- JS_SET_TRACING_LOCATION(trc, &obj->privateRef(obj->numFixedSlots()));
- MarkObjectUnbarriered(trc, &delegate, "arraybuffer.delegate");
- obj->setPrivateUnbarriered(delegate);
- }
-
- // ArrayBufferObjects need to maintain a list of possibly-weak pointers to
- // their views. The straightforward way to update the weak pointers would
- // be in the views' finalizers, but giving views finalizers means they
- // cannot be swept in the background. This results in a very high
- // performance cost. Instead, ArrayBufferObjects with a single view hold a
- // strong pointer to the view. This can entrain garbage when the single
- // view becomes otherwise unreachable while the buffer is still live, but
- // this is expected to be rare. ArrayBufferObjects with 0-1 views are
- // expected to be by far the most common cases. ArrayBufferObjects with
- // multiple views are collected into a linked list during collection, and
- // then swept to prune out their dead views.
-
- ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
- ArrayBufferViewObject *viewsHead = GetViewList(&buffer);
- if (!viewsHead)
- return;
-
- // During minor collections, mark weak pointers on the buffer strongly.
- if (trc->runtime->isHeapMinorCollecting()) {
- MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.viewlist");
- ArrayBufferViewObject *prior = GetViewList(&buffer);
- for (ArrayBufferViewObject *view = prior->nextView();
- view;
- prior = view, view = view->nextView())
- {
- MarkObjectUnbarriered(trc, &view, "arraybuffer.views");
- prior->setNextView(view);
- }
- return;
- }
-
- ArrayBufferViewObject *firstView = viewsHead;
- if (firstView->nextView() == nullptr) {
- // Single view: mark it, but only if we're actually doing a GC pass
- // right now. Otherwise, the tracing pass for barrier verification will
- // fail if we add another view and the pointer becomes weak.
- if (IS_GC_MARKING_TRACER(trc))
- MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.singleview");
- } else {
- // Multiple views: do not mark, but append buffer to list.
- if (IS_GC_MARKING_TRACER(trc)) {
- // obj_trace may be called multiple times before sweep(), so avoid
- // adding this buffer to the list multiple times.
- if (firstView->bufferLink() == UNSET_BUFFER_LINK) {
- JS_ASSERT(obj->compartment() == firstView->compartment());
- ArrayBufferObject **bufList = &obj->compartment()->gcLiveArrayBuffers;
- firstView->setBufferLink(*bufList);
- *bufList = &obj->as<ArrayBufferObject>();
- } else {
-#ifdef DEBUG
- bool found = false;
- for (ArrayBufferObject *p = obj->compartment()->gcLiveArrayBuffers;
- p;
- p = GetViewList(p)->bufferLink())
- {
- if (p == obj)
- {
- JS_ASSERT(!found);
- found = true;
- }
- }
-#endif
- }
- }
- }
-}
-
-void
-ArrayBufferObject::sweep(JSCompartment *compartment)
-{
- ArrayBufferObject *buffer = compartment->gcLiveArrayBuffers;
- JS_ASSERT(buffer != UNSET_BUFFER_LINK);
- compartment->gcLiveArrayBuffers = nullptr;
-
- while (buffer) {
- ArrayBufferViewObject *viewsHead = GetViewList(buffer);
- JS_ASSERT(viewsHead);
-
- ArrayBufferObject *nextBuffer = viewsHead->bufferLink();
- JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
- viewsHead->setBufferLink(UNSET_BUFFER_LINK);
-
- // Rebuild the list of views of the ArrayBufferObject, discarding dead
- // views. If there is only one view, it will have already been marked.
- ArrayBufferViewObject *prevLiveView = nullptr;
- ArrayBufferViewObject *view = viewsHead;
- while (view) {
- JS_ASSERT(buffer->compartment() == view->compartment());
- ArrayBufferViewObject *nextView = view->nextView();
- if (!IsObjectAboutToBeFinalized(&view)) {
- view->setNextView(prevLiveView);
- prevLiveView = view;
- }
- view = nextView;
- }
- SetViewList(buffer, prevLiveView);
-
- buffer = nextBuffer;
- }
-}
-
-void
-ArrayBufferObject::resetArrayBufferList(JSCompartment *comp)
-{
- ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
- JS_ASSERT(buffer != UNSET_BUFFER_LINK);
- comp->gcLiveArrayBuffers = nullptr;
-
- while (buffer) {
- ArrayBufferViewObject *view = GetViewList(buffer);
- JS_ASSERT(view);
-
- ArrayBufferObject *nextBuffer = view->bufferLink();
- JS_ASSERT(nextBuffer != UNSET_BUFFER_LINK);
-
- view->setBufferLink(UNSET_BUFFER_LINK);
- buffer = nextBuffer;
- }
-}
-
-/* static */ bool
-ArrayBufferObject::saveArrayBufferList(JSCompartment *comp, ArrayBufferVector &vector)
-{
- ArrayBufferObject *buffer = comp->gcLiveArrayBuffers;
- while (buffer) {
- JS_ASSERT(buffer != UNSET_BUFFER_LINK);
- if (!vector.append(buffer))
- return false;
-
- ArrayBufferViewObject *view = GetViewList(buffer);
- JS_ASSERT(view);
- buffer = view->bufferLink();
- }
- return true;
-}
-
-/* static */ void
-ArrayBufferObject::restoreArrayBufferLists(ArrayBufferVector &vector)
-{
- for (ArrayBufferObject **p = vector.begin(); p != vector.end(); p++) {
- ArrayBufferObject *buffer = *p;
- JSCompartment *comp = buffer->compartment();
- ArrayBufferViewObject *firstView = GetViewList(buffer);
- JS_ASSERT(firstView);
- JS_ASSERT(firstView->compartment() == comp);
- JS_ASSERT(firstView->bufferLink() == UNSET_BUFFER_LINK);
- firstView->setBufferLink(comp->gcLiveArrayBuffers);
- comp->gcLiveArrayBuffers = buffer;
- }
-}
-
-bool
-ArrayBufferObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
-
- bool delegateResult = JSObject::lookupGeneric(cx, delegate, id, objp, propp);
-
- /* If false, there was an error, so propagate it.
- * Otherwise, if propp is non-null, the property
- * was found. Otherwise it was not
- * found so look in the prototype chain.
- */
- if (!delegateResult)
- return false;
-
- if (propp) {
- if (objp == delegate)
- objp.set(obj);
- return true;
- }
-
- RootedObject proto(cx, obj->getProto());
- if (!proto) {
- objp.set(nullptr);
- propp.set(nullptr);
- return true;
- }
-
- return JSObject::lookupGeneric(cx, proto, id, objp, propp);
-}
-
-bool
-ArrayBufferObject::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
- MutableHandleObject objp, MutableHandleShape propp)
-{
- Rooted<jsid> id(cx, NameToId(name));
- return obj_lookupGeneric(cx, obj, id, objp, propp);
-}
-
-bool
-ArrayBufferObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
- MutableHandleObject objp, MutableHandleShape propp)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
-
- /*
- * If false, there was an error, so propagate it.
- * Otherwise, if propp is non-null, the property
- * was found. Otherwise it was not
- * found so look in the prototype chain.
- */
- if (!JSObject::lookupElement(cx, delegate, index, objp, propp))
- return false;
-
- if (propp) {
- if (objp == delegate)
- objp.set(obj);
- return true;
- }
-
- RootedObject proto(cx, obj->getProto());
- if (proto)
- return JSObject::lookupElement(cx, proto, index, objp, propp);
-
- objp.set(nullptr);
- propp.set(nullptr);
- return true;
-}
-
-bool
-ArrayBufferObject::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
- MutableHandleObject objp, MutableHandleShape propp)
-{
- Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
- return obj_lookupGeneric(cx, obj, id, objp, propp);
-}
-
-bool
-ArrayBufferObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
- AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
-
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::DefineGeneric(cx, delegate, id, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_defineProperty(JSContext *cx, HandleObject obj,
- HandlePropertyName name, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
- Rooted<jsid> id(cx, NameToId(name));
- return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
- AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
-
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::DefineElement(cx, delegate, index, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
-{
- Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
- return obj_defineGeneric(cx, obj, id, v, getter, setter, attrs);
-}
-
-bool
-ArrayBufferObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
- HandleId id, MutableHandleValue vp)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::GetProperty(cx, delegate, receiver, id, vp);
-}
-
-bool
-ArrayBufferObject::obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
- HandlePropertyName name, MutableHandleValue vp)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- Rooted<jsid> id(cx, NameToId(name));
- return baseops::GetProperty(cx, delegate, receiver, id, vp);
-}
-
-bool
-ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
- HandleObject receiver, uint32_t index, MutableHandleValue vp)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::GetElement(cx, delegate, receiver, index, vp);
-}
-
-bool
-ArrayBufferObject::obj_getSpecial(JSContext *cx, HandleObject obj,
- HandleObject receiver, HandleSpecialId sid,
- MutableHandleValue vp)
-{
- Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
- return obj_getGeneric(cx, obj, receiver, id, vp);
-}
-
-bool
-ArrayBufferObject::obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
- MutableHandleValue vp, bool strict)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
-
- return baseops::SetPropertyHelper<SequentialExecution>(cx, delegate, obj, id, 0, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_setProperty(JSContext *cx, HandleObject obj,
- HandlePropertyName name, MutableHandleValue vp, bool strict)
-{
- Rooted<jsid> id(cx, NameToId(name));
- return obj_setGeneric(cx, obj, id, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_setElement(JSContext *cx, HandleObject obj,
- uint32_t index, MutableHandleValue vp, bool strict)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
-
- return baseops::SetElementHelper(cx, delegate, obj, index, 0, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_setSpecial(JSContext *cx, HandleObject obj,
- HandleSpecialId sid, MutableHandleValue vp, bool strict)
-{
- Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
- return obj_setGeneric(cx, obj, id, vp, strict);
-}
-
-bool
-ArrayBufferObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
- HandleId id, unsigned *attrsp)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::GetAttributes(cx, delegate, id, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_setGenericAttributes(JSContext *cx, HandleObject obj,
- HandleId id, unsigned *attrsp)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::SetAttributes(cx, delegate, id, attrsp);
-}
-
-bool
-ArrayBufferObject::obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
- bool *succeeded)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::DeleteProperty(cx, delegate, name, succeeded);
-}
-
-bool
-ArrayBufferObject::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
- bool *succeeded)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::DeleteElement(cx, delegate, index, succeeded);
-}
-
-bool
-ArrayBufferObject::obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
- bool *succeeded)
-{
- RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
- if (!delegate)
- return false;
- return baseops::DeleteSpecial(cx, delegate, sid, succeeded);
-}
-
-bool
-ArrayBufferObject::obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
- MutableHandleValue statep, MutableHandleId idp)
-{
- statep.setNull();
- return true;
-}
-
-/*
- * ArrayBufferViewObject
- */
-
-inline void
-ArrayBufferViewObject::setBufferLink(ArrayBufferObject *buffer)
-{
- setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(buffer));
- PostBarrierTypedArrayObject(this);
-}
-
-inline void
-ArrayBufferViewObject::setNextView(ArrayBufferViewObject *view)
-{
- setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(view));
- PostBarrierTypedArrayObject(this);
-}
-
-/*
* TypedArrayObject
*
* The non-templated base class for the specific typed implementations.
* This class holds all the member variables that are used by
* the subclasses.
*/
inline bool
@@ -1347,67 +255,31 @@ js::ToDoubleForTypedArray(JSContext *cx,
// to a float array and then read back as integer. To work around this, we
// always canonicalize NaN values in more-deterministic builds.
*d = CanonicalizeNaN(*d);
#endif
return true;
}
-/*
- * This method is used to trace TypedArrayObjects and DataViewObjects. We need
- * a custom tracer because some of an ArrayBufferViewObject's reserved slots
- * are weak references, and some need to be updated specially during moving
- * GCs.
- */
-/* static */ void
-ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
-{
- HeapSlot &bufSlot = obj->getReservedSlotRef(BUFFER_SLOT);
- MarkSlot(trc, &bufSlot, "typedarray.buffer");
-
- /* 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>();
- int32_t offset = obj->getReservedSlot(BYTEOFFSET_SLOT).toInt32();
- obj->initPrivate(buf.dataPointer() + offset);
- }
-
- /* Update NEXT_VIEW_SLOT, if the view moved. */
- IsSlotMarked(&obj->getReservedSlotRef(NEXT_VIEW_SLOT));
-}
-
template<typename NativeType> static inline const int TypeIDOfType();
template<> inline const int TypeIDOfType<int8_t>() { return ScalarTypeDescr::TYPE_INT8; }
template<> inline const int TypeIDOfType<uint8_t>() { return ScalarTypeDescr::TYPE_UINT8; }
template<> inline const int TypeIDOfType<int16_t>() { return ScalarTypeDescr::TYPE_INT16; }
template<> inline const int TypeIDOfType<uint16_t>() { return ScalarTypeDescr::TYPE_UINT16; }
template<> inline const int TypeIDOfType<int32_t>() { return ScalarTypeDescr::TYPE_INT32; }
template<> inline const int TypeIDOfType<uint32_t>() { return ScalarTypeDescr::TYPE_UINT32; }
template<> inline const int TypeIDOfType<float>() { return ScalarTypeDescr::TYPE_FLOAT32; }
template<> inline const int TypeIDOfType<double>() { return ScalarTypeDescr::TYPE_FLOAT64; }
template<> inline const int TypeIDOfType<uint8_clamped>() { return ScalarTypeDescr::TYPE_UINT8_CLAMPED; }
template<typename ElementType>
static inline JSObject *
NewArray(JSContext *cx, uint32_t nelements);
-static inline void
-InitArrayBufferViewDataPointer(JSObject *obj, ArrayBufferObject *buffer, size_t byteOffset)
-{
- /*
- * N.B. The base of the array's data is stored in the object's
- * private data rather than a slot to avoid alignment restrictions
- * on private Values.
- */
- obj->initPrivate(buffer->dataPointer() + byteOffset);
- PostBarrierTypedArrayObject(obj);
-}
-
namespace {
template<typename NativeType>
class TypedArrayObjectTemplate : public TypedArrayObject
{
public:
typedef NativeType ThisType;
typedef TypedArrayObjectTemplate<NativeType> ThisTypedArrayObject;
@@ -2618,36 +1490,16 @@ ArrayBufferObject::createTypedArrayFromB
template<typename T>
bool
ArrayBufferObject::createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, createTypedArrayFromBufferImpl<T> >(cx, args);
}
-void
-ArrayBufferViewObject::prependToViews(ArrayBufferViewObject *viewsHead)
-{
- setNextView(viewsHead);
-
- // Move the multiview buffer list link into this view since we're
- // prepending it to the list.
- setBufferLink(viewsHead->bufferLink());
- viewsHead->setBufferLink(UNSET_BUFFER_LINK);
-}
-
-void
-ArrayBufferViewObject::neuter(JSContext *cx)
-{
- if (is<DataViewObject>())
- as<DataViewObject>().neuter();
- else
- as<TypedArrayObject>().neuter(cx);
-}
-
// this default implementation is only valid for integer types
// less than 32-bits in size.
template<typename NativeType>
void
TypedArrayObjectTemplate<NativeType>::copyIndexToValue(JSObject *tarray, uint32_t index,
MutableHandleValue vp)
{
JS_STATIC_ASSERT(sizeof(NativeType) < 4);
@@ -2762,17 +1614,17 @@ DataViewObject::create(JSContext *cx, ui
}
DataViewObject &dvobj = obj->as<DataViewObject>();
dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength));
dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
dvobj.setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
dvobj.setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(UNSET_BUFFER_LINK));
- InitArrayBufferViewDataPointer(obj, arrayBuffer, byteOffset);
+ InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset);
JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
// Verify that the private slot is at the expected place
JS_ASSERT(dvobj.numFixedSlots() == DATA_SLOT);
arrayBuffer->as<ArrayBufferObject>().addView(&dvobj);
return &dvobj;
@@ -3404,94 +2256,16 @@ TypedArrayObject::copyTypedArrayElement(
}
}
/***
*** JS impl
***/
/*
- * ArrayBufferObject (base)
- */
-
-const Class ArrayBufferObject::protoClass = {
- "ArrayBufferPrototype",
- JSCLASS_HAS_PRIVATE |
- JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
- JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub
-};
-
-const Class ArrayBufferObject::class_ = {
- "ArrayBuffer",
- JSCLASS_HAS_PRIVATE |
- JSCLASS_IMPLEMENTS_BARRIERS |
- Class::NON_NATIVE |
- JSCLASS_HAS_RESERVED_SLOTS(ARRAYBUFFER_RESERVED_SLOTS) |
- JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer),
- JS_PropertyStub, /* addProperty */
- JS_DeletePropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- nullptr, /* 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 */
- }
-};
-
-const JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
- JS_FN("slice", ArrayBufferObject::fun_slice, 2, JSFUN_GENERIC_NATIVE),
- JS_FS_END
-};
-
-const JSFunctionSpec ArrayBufferObject::jsstaticfuncs[] = {
- JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
- JS_FS_END
-};
-
-/*
* TypedArrayObject boilerplate
*/
#ifndef RELEASE_BUILD
# define IMPL_TYPED_ARRAY_STATICS(_typedArray) \
const JSFunctionSpec _typedArray##Object::jsfuncs[] = { \
JS_SELF_HOSTED_FN("@@iterator", "ArrayValues", 0, 0), \
JS_FN("subarray", _typedArray##Object::fun_subarray, 2, JSFUN_GENERIC_NATIVE), \
@@ -3984,153 +2758,22 @@ bool
js::IsTypedArrayBuffer(HandleValue v)
{
return v.isObject() && v.toObject().is<ArrayBufferObject>();
}
/* JS Friend API */
JS_FRIEND_API(bool)
-JS_IsArrayBufferObject(JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- return obj ? obj->is<ArrayBufferObject>() : false;
-}
-
-JS_FRIEND_API(bool)
JS_IsTypedArrayObject(JSObject *obj)
{
obj = CheckedUnwrap(obj);
return obj ? obj->is<TypedArrayObject>() : false;
}
-JS_FRIEND_API(bool)
-JS_IsArrayBufferViewObject(JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- return obj ? obj->is<ArrayBufferViewObject>() : false;
-}
-
-JS_FRIEND_API(uint32_t)
-JS_GetArrayBufferByteLength(JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- return obj ? obj->as<ArrayBufferObject>().byteLength() : 0;
-}
-
-JS_FRIEND_API(uint8_t *)
-JS_GetArrayBufferData(JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- if (!obj)
- return nullptr;
- return obj->as<ArrayBufferObject>().dataPointer();
-}
-
-JS_FRIEND_API(uint8_t *)
-JS_GetStableArrayBufferData(JSContext *cx, JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- if (!obj)
- return nullptr;
-
- Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
- if (!ArrayBufferObject::ensureNonInline(cx, buffer))
- return nullptr;
-
- return buffer->dataPointer();
-}
-
-JS_FRIEND_API(bool)
-JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj)
-{
- if (!obj->is<ArrayBufferObject>()) {
- JS_ReportError(cx, "ArrayBuffer object required");
- return false;
- }
-
- Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
- if (!ArrayBufferObject::neuterViews(cx, buffer))
- return false;
- buffer->neuter(cx);
- return true;
-}
-
-JS_FRIEND_API(JSObject *)
-JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes)
-{
- JS_ASSERT(nbytes <= INT32_MAX);
- return ArrayBufferObject::create(cx, nbytes);
-}
-
-JS_PUBLIC_API(JSObject *)
-JS_NewArrayBufferWithContents(JSContext *cx, void *contents)
-{
- JS_ASSERT(contents);
- JSObject *obj = ArrayBufferObject::create(cx, 0);
- if (!obj)
- return nullptr;
- js::ObjectElements *elements = reinterpret_cast<js::ObjectElements *>(contents);
- obj->setDynamicElements(elements);
- JS_ASSERT(GetViewList(&obj->as<ArrayBufferObject>()) == nullptr);
-
-#ifdef JSGC_GENERATIONAL
- cx->runtime()->gcNursery.notifyNewElements(obj, elements);
-#endif
- return obj;
-}
-
-JS_PUBLIC_API(bool)
-JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes,
- void **contents, uint8_t **data)
-{
- js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes);
- if (!header)
- return false;
-
- ArrayBufferObject::updateElementsHeader(header, nbytes);
-
- *contents = header;
- *data = reinterpret_cast<uint8_t*>(header->elements());
- return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_ReallocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void **contents, uint8_t **data)
-{
- js::ObjectElements *header = AllocateArrayBufferContents(maybecx, nbytes, *contents);
- if (!header)
- return false;
-
- ArrayBufferObject::initElementsHeader(header, nbytes);
-
- *contents = header;
- *data = reinterpret_cast<uint8_t*>(header->elements());
- return true;
-}
-
-JS_PUBLIC_API(bool)
-JS_StealArrayBufferContents(JSContext *cx, HandleObject objArg, void **contents, uint8_t **data)
-{
- JSObject *obj = CheckedUnwrap(objArg);
- if (!obj)
- return false;
-
- if (!obj->is<ArrayBufferObject>()) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
- return false;
- }
-
- Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
- if (!ArrayBufferObject::stealContents(cx, buffer, contents, data))
- return false;
-
- return true;
-}
-
JS_FRIEND_API(uint32_t)
JS_GetTypedArrayLength(JSObject *obj)
{
obj = CheckedUnwrap(obj);
if (!obj)
return 0;
return obj->as<TypedArrayObject>().length();
}
@@ -4294,70 +2937,8 @@ JS_GetDataViewData(JSObject *obj)
JS_FRIEND_API(uint32_t)
JS_GetDataViewByteLength(JSObject *obj)
{
obj = CheckedUnwrap(obj);
if (!obj)
return 0;
return obj->as<DataViewObject>().byteLength();
}
-
-JS_FRIEND_API(void *)
-JS_GetArrayBufferViewData(JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- if (!obj)
- return nullptr;
- return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
- : obj->as<TypedArrayObject>().viewData();
-}
-
-JS_FRIEND_API(JSObject *)
-JS_GetArrayBufferViewBuffer(JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- if (!obj)
- return nullptr;
- return obj->as<ArrayBufferViewObject>().bufferObject();
-}
-
-JS_FRIEND_API(uint32_t)
-JS_GetArrayBufferViewByteLength(JSObject *obj)
-{
- obj = CheckedUnwrap(obj);
- if (!obj)
- return 0;
- return obj->is<DataViewObject>()
- ? obj->as<DataViewObject>().byteLength()
- : obj->as<TypedArrayObject>().byteLength();
-}
-
-JS_FRIEND_API(JSObject *)
-JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data)
-{
- if (!(obj = CheckedUnwrap(obj)))
- return nullptr;
- if (!(obj->is<ArrayBufferViewObject>()))
- return nullptr;
-
- *length = obj->is<DataViewObject>()
- ? obj->as<DataViewObject>().byteLength()
- : obj->as<TypedArrayObject>().byteLength();
-
- *data = static_cast<uint8_t*>(obj->is<DataViewObject>()
- ? obj->as<DataViewObject>().dataPointer()
- : obj->as<TypedArrayObject>().viewData());
- return obj;
-}
-
-JS_FRIEND_API(JSObject *)
-JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
-{
- if (!(obj = CheckedUnwrap(obj)))
- return nullptr;
- if (!obj->is<ArrayBufferObject>())
- return nullptr;
-
- *length = obj->as<ArrayBufferObject>().byteLength();
- *data = obj->as<ArrayBufferObject>().dataPointer();
-
- return obj;
-}
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -7,289 +7,39 @@
#ifndef vm_TypedArrayObject_h
#define vm_TypedArrayObject_h
#include "jsobj.h"
#include "builtin/TypedObject.h"
#include "gc/Barrier.h"
#include "js/Class.h"
+#include "vm/ArrayBufferObject.h"
typedef struct JSProperty JSProperty;
namespace js {
-typedef Vector<ArrayBufferObject *, 0, SystemAllocPolicy> ArrayBufferVector;
-
-// The inheritance hierarchy for the various classes relating to typed arrays
-// is as follows.
-//
-// - JSObject
-// - ArrayBufferObject
-// - ArrayBufferViewObject
-// - DataViewObject
-// - TypedArrayObject
-// - TypedArrayObjectTemplate
-// - Int8ArrayObject
-// - Uint8ArrayObject
-// - ...
-//
-// Note that |TypedArrayObjectTemplate| is just an implementation detail that
-// makes implementing its various subclasses easier.
-
-class ArrayBufferViewObject;
-
-/*
- * ArrayBufferObject
- *
- * This class holds the underlying raw buffer that the various
- * ArrayBufferViewObject subclasses (DataViewObject and the TypedArrays)
- * access. It can be created explicitly and passed to an ArrayBufferViewObject
- * subclass, or can be created implicitly by constructing a TypedArrayObject
- * with a size.
- */
-class ArrayBufferObject : public JSObject
-{
- static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
- static bool fun_slice_impl(JSContext *cx, CallArgs args);
-
- public:
- 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_slice(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);
-
- static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, bool clear = true);
-
- static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
- uint32_t begin, uint32_t end);
-
- static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
- static bool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);
-
- template<typename T>
- static bool createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args);
-
- template<typename T>
- static bool createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp);
-
- static void obj_trace(JSTracer *trc, JSObject *obj);
-
- static bool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
- MutableHandleObject objp, MutableHandleShape propp);
- static bool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
- MutableHandleObject objp, MutableHandleShape propp);
- static bool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
- MutableHandleObject objp, MutableHandleShape propp);
- static bool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
- MutableHandleObject objp, MutableHandleShape propp);
-
- static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
- static bool obj_defineProperty(JSContext *cx, HandleObject obj,
- HandlePropertyName name, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
- static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
- static bool obj_defineSpecial(JSContext *cx, HandleObject obj,
- HandleSpecialId sid, HandleValue v,
- PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
-
- static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
- HandleId id, MutableHandleValue vp);
-
- static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
- HandlePropertyName name, MutableHandleValue vp);
-
- static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
- uint32_t index, MutableHandleValue vp);
-
- static bool obj_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver,
- HandleSpecialId sid, MutableHandleValue vp);
-
- static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
- MutableHandleValue vp, bool strict);
- static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
- MutableHandleValue vp, bool strict);
- static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
- MutableHandleValue vp, bool strict);
- static bool obj_setSpecial(JSContext *cx, HandleObject obj,
- HandleSpecialId sid, MutableHandleValue vp, bool strict);
-
- static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
- HandleId id, unsigned *attrsp);
- static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
- HandleId id, unsigned *attrsp);
-
- static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
- bool *succeeded);
- static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
- bool *succeeded);
- static bool obj_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
- bool *succeeded);
-
- static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
- MutableHandleValue statep, MutableHandleId idp);
-
- static void sweep(JSCompartment *rt);
-
- static void resetArrayBufferList(JSCompartment *rt);
- static bool saveArrayBufferList(JSCompartment *c, ArrayBufferVector &vector);
- static void restoreArrayBufferLists(ArrayBufferVector &vector);
-
- static bool stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer, void **contents,
- uint8_t **data);
-
- static void updateElementsHeader(js::ObjectElements *header, uint32_t bytes) {
- header->initializedLength = bytes;
-
- // NB: one or both of these fields is clobbered by GetViewList to store
- // the 'views' link. Set them to 0 to effectively initialize 'views'
- // to nullptr.
- header->length = 0;
- header->capacity = 0;
- }
-
- static void initElementsHeader(js::ObjectElements *header, uint32_t bytes) {
- header->flags = 0;
- updateElementsHeader(header, bytes);
- }
-
- static uint32_t headerInitializedLength(const js::ObjectElements *header) {
- return header->initializedLength;
- }
-
- void addView(ArrayBufferViewObject *view);
-
- void changeContents(JSContext *cx, ObjectElements *newHeader);
-
- /*
- * Ensure data is not stored inline in the object. Used when handing back a
- * GC-safe pointer.
- */
- static bool ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer);
-
- uint32_t byteLength() const {
- return getElementsHeader()->initializedLength;
- }
-
- /*
- * Neuter all views of an ArrayBuffer.
- */
- static bool neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer);
-
- inline uint8_t * dataPointer() const {
- return (uint8_t *) elements;
- }
-
- /*
- * Discard the ArrayBuffer contents. For asm.js buffers, at least, should
- * be called after neuterViews().
- */
- void neuter(JSContext *cx);
-
- /*
- * Check if the arrayBuffer contains any data. This will return false for
- * ArrayBuffer.prototype and neutered ArrayBuffers.
- */
- bool hasData() const {
- return getClass() == &class_;
- }
-
- bool isAsmJSArrayBuffer() const {
- return getElementsHeader()->isAsmJSArrayBuffer();
- }
- bool isNeutered() const {
- return getElementsHeader()->isNeuteredBuffer();
- }
- static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
- static bool neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
- static void releaseAsmJSArrayBuffer(FreeOp *fop, JSObject *obj);
-};
-
-/*
- * ArrayBufferViewObject
- *
- * Common definitions shared by all ArrayBufferViews.
- */
-
-class ArrayBufferViewObject : public JSObject
-{
- protected:
- /* Offset of view in underlying ArrayBufferObject */
- static const size_t BYTEOFFSET_SLOT = 0;
-
- /* Byte length of view */
- static const size_t BYTELENGTH_SLOT = 1;
-
- /* Underlying ArrayBufferObject */
- static const size_t BUFFER_SLOT = 2;
-
- /* ArrayBufferObjects point to a linked list of views, chained through this slot */
- static const size_t NEXT_VIEW_SLOT = 3;
-
- /*
- * When ArrayBufferObjects are traced during GC, they construct a linked
- * list of ArrayBufferObjects with more than one view, chained through this
- * slot of the first view of each ArrayBufferObject.
- */
- static const size_t NEXT_BUFFER_SLOT = 4;
-
- static const size_t NUM_SLOTS = 5;
-
- public:
- JSObject *bufferObject() const {
- return &getFixedSlot(BUFFER_SLOT).toObject();
- }
-
- ArrayBufferObject *bufferLink() {
- return static_cast<ArrayBufferObject*>(getFixedSlot(NEXT_BUFFER_SLOT).toPrivate());
- }
-
- inline void setBufferLink(ArrayBufferObject *buffer);
-
- ArrayBufferViewObject *nextView() const {
- return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());
- }
-
- inline void setNextView(ArrayBufferViewObject *view);
-
- void prependToViews(ArrayBufferViewObject *viewsHead);
-
- void neuter(JSContext *cx);
-
- static void trace(JSTracer *trc, JSObject *obj);
-};
-
/*
* TypedArrayObject
*
* The non-templated base class for the specific typed implementations.
* This class holds all the member variables that are used by
* the subclasses.
*/
class TypedArrayObject : public ArrayBufferViewObject
{
protected:
// Typed array properties stored in slots, beyond those shared by all
// ArrayBufferViews.
- static const size_t LENGTH_SLOT = ArrayBufferViewObject::NUM_SLOTS;
- static const size_t TYPE_SLOT = ArrayBufferViewObject::NUM_SLOTS + 1;
- static const size_t RESERVED_SLOTS = ArrayBufferViewObject::NUM_SLOTS + 2;
- static const size_t DATA_SLOT = 7; // private slot, based on alloc kind
+ static const size_t LENGTH_SLOT = JS_TYPEDOBJ_SLOT_LENGTH;
+ static const size_t TYPE_SLOT = JS_TYPEDOBJ_SLOT_TYPE_DESCR;
+ static const size_t RESERVED_SLOTS = JS_TYPEDOBJ_SLOTS;
+ static const size_t DATA_SLOT = JS_TYPEDOBJ_SLOT_DATA;
public:
static const Class classes[ScalarTypeDescr::TYPE_MAX];
static const Class protoClasses[ScalarTypeDescr::TYPE_MAX];
static bool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
MutableHandleObject objp, MutableHandleShape propp);
static bool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
@@ -415,18 +165,18 @@ TypedArrayShift(ArrayBufferView::ViewTyp
return 3;
default:;
}
MOZ_ASSUME_UNREACHABLE("Unexpected array type");
}
class DataViewObject : public ArrayBufferViewObject
{
- static const size_t RESERVED_SLOTS = ArrayBufferViewObject::NUM_SLOTS;
- static const size_t DATA_SLOT = 7; // private slot, based on alloc kind
+ static const size_t RESERVED_SLOTS = JS_DATAVIEW_SLOTS;
+ static const size_t DATA_SLOT = JS_TYPEDOBJ_SLOT_DATA;
private:
static const Class protoClass;
static bool is(HandleValue v) {
return v.isObject() && v.toObject().hasClass(&class_);
}
@@ -562,25 +312,28 @@ ClampIntForUint8Array(int32_t x)
return 0;
if (x > 255)
return 255;
return x;
}
bool ToDoubleForTypedArray(JSContext *cx, JS::HandleValue vp, double *d);
+extern js::ArrayBufferObject * const UNSET_BUFFER_LINK;
+
} // namespace js
template <>
inline bool
JSObject::is<js::TypedArrayObject>() const
{
return js::IsTypedArrayClass(getClass());
}
template <>
inline bool
JSObject::is<js::ArrayBufferViewObject>() const
{
- return is<js::DataViewObject>() || is<js::TypedArrayObject>();
+ return is<js::DataViewObject>() || is<js::TypedArrayObject>() ||
+ IsTypedObjectClass(getClass());
}
#endif /* vm_TypedArrayObject_h */
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -18,20 +18,20 @@ SandboxBroker::SandboxBroker()
if (!sBrokerService) {
sBrokerService = sandbox::SandboxFactory::GetBrokerServices();
if (sBrokerService) {
sandbox::ResultCode result = sBrokerService->Init();
if (result != sandbox::SBOX_ALL_OK) {
sBrokerService = nullptr;
}
}
+ }
- // We'll start to increase the restrictions over time.
- mPolicy = sBrokerService->CreatePolicy();
- }
+ // We'll start to increase the restrictions over time.
+ mPolicy = sBrokerService->CreatePolicy();
}
bool
SandboxBroker::AllowPipe(const wchar_t *aPath)
{
return mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, aPath);
}
@@ -50,16 +50,19 @@ SandboxBroker::LaunchApp(const wchar_t *
// Medium integrity, unrestricted, in the same window station, within the
// same desktop, and has no job object.
// We'll start to increase the restrictions over time.
mPolicy->SetJobLevel(sandbox::JOB_NONE, 0);
mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
sandbox::USER_RESTRICTED_SAME_ACCESS);
mPolicy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_UNTRUSTED);
+ // Set an alternate Desktop within a new window station
+ mPolicy->SetAlternateDesktop(false);
+
// Ceate the sandboxed process
PROCESS_INFORMATION targetInfo;
sandbox::ResultCode result;
result = sBrokerService->SpawnTarget(aPath, aArguments, mPolicy, &targetInfo);
// The sandboxed process is started in a suspended state, resumeit now that
// we'eve set things up.
ResumeThread(targetInfo.hThread);
--- a/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h
+++ b/xpcom/reflect/xptcall/src/md/unix/xptc_gcc_x86_unix.h
@@ -10,10 +10,8 @@
//
#ifdef MOZ_NEED_LEADING_UNDERSCORE
#define SYMBOL_UNDERSCORE "_"
#else
#define SYMBOL_UNDERSCORE
#endif
-
-#define ATTRIBUTE_USED __attribute__ ((__used__))
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_alpha_openbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_alpha_openbsd.cpp
@@ -6,17 +6,17 @@
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
/* Prototype specifies unmangled function name and disables unused warning */
static nsresult
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint64_t* args)
-__asm__("PrepareAndDispatch") __attribute__((used));
+__asm__("PrepareAndDispatch") ATTRIBUTE_USED;
static nsresult
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint64_t* args)
{
const uint8_t PARAM_BUFFER_COUNT = 16;
const uint8_t NUM_ARG_REGS = 6-1; // -1 for "this" pointer
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_openbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_amd64_openbsd.cpp
@@ -23,17 +23,17 @@ const uint32_t FPR_COUNT = 8;
//
// - 'args[]' contains the arguments passed on stack
// - 'gpregs[]' contains the arguments passed in integer registers
// - 'fpregs[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase * self, uint32_t methodIndex,
uint64_t * args, uint64_t * gpregs, double *fpregs)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
uint32_t paramCount;
uint32_t i;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp
@@ -7,31 +7,19 @@
#include "xptcprivate.h"
#include "xptiprivate.h"
#if !defined(__arm__) && !(defined(LINUX) || defined(ANDROID))
#error "This code is for Linux ARM only. Please check if it works for you, too.\nDepends strongly on gcc behaviour."
#endif
-#ifdef __GNUC__
-/* This tells gcc3.4+ not to optimize away symbols.
- * @see http://gcc.gnu.org/gcc-3.4/changes.html
- */
-#define DONT_DROP_OR_WARN __attribute__((used))
-#else
-/* This tells older gccs not to warn about unused vairables.
- * @see http://docs.freebsd.org/info/gcc/gcc.info.Variable_Attributes.html
- */
-#define DONT_DROP_OR_WARN __attribute__((unused))
-#endif
-
/* Specify explicitly a symbol for this function, don't try to guess the c++ mangled symbol. */
static nsresult PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args) asm("_PrepareAndDispatch")
-DONT_DROP_OR_WARN;
+ATTRIBUTE_USED;
#ifdef __ARM_EABI__
#define DOUBLEWORD_ALIGN(p) ((uint32_t *)((((uint32_t)(p)) + 7) & 0xfffffff8))
#else
#define DOUBLEWORD_ALIGN(p) (p)
#endif
// Apple's iOS toolchain is lame and does not support .cfi directives.
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_netbsd.cpp
@@ -2,17 +2,17 @@
/* 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/. */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
-nsresult
+nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
nsIInterfaceInfo* iface_info = nullptr;
const nsXPTMethodInfo* info;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_openbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm_openbsd.cpp
@@ -19,17 +19,17 @@
*/
#define DONT_DROP_OR_WARN __attribute__((unused))
#endif
/* Specify explicitly a symbol for this function, don't try to guess the c++ mangled symbol. */
static nsresult PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args) asm("_PrepareAndDispatch")
DONT_DROP_OR_WARN;
-static nsresult
+static nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
uint8_t paramCount;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf32.cpp
@@ -11,17 +11,17 @@
#include <stddef.h>
#include <stdlib.h>
// "This code is for IA64 only"
/* Implement shared vtbl methods. */
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex,
uint64_t* intargs, uint64_t* floatargs, uint64_t* restargs)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ipf64.cpp
@@ -12,17 +12,17 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
// "This code is for IA64 only"
/* Implement shared vtbl methods. */
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex,
uint64_t* intargs, uint64_t* floatargs, uint64_t* restargs)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_alpha.cpp
@@ -6,17 +6,17 @@
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
/* Prototype specifies unmangled function name and disables unused warning */
static nsresult
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint64_t* args)
-__asm__("PrepareAndDispatch") __attribute__((used));
+__asm__("PrepareAndDispatch") ATTRIBUTE_USED;
static nsresult
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint64_t* args)
{
const uint8_t PARAM_BUFFER_COUNT = 16;
const uint8_t NUM_ARG_REGS = 6-1; // -1 for "this" pointer
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_m68k.cpp
@@ -4,17 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
extern "C" {
- nsresult
+ nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
uint8_t paramCount;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390.cpp
@@ -4,17 +4,17 @@
* 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/. */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
-static nsresult
+static nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex,
uint32_t* a_gpr, uint64_t *a_fpr, uint32_t *a_ov)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_linux_s390x.cpp
@@ -4,17 +4,17 @@
* 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/. */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
-static nsresult
+static nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex,
uint64_t* a_gpr, uint64_t *a_fpr, uint64_t *a_ov)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips.cpp
@@ -10,17 +10,17 @@
#include <stdint.h>
/*
* This is for MIPS O32 ABI
* Args contains a0-3 and then the stack.
* Because a0 is 'this', we want to skip it
*/
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
args++; // always skip over a0
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips64.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_mips64.cpp
@@ -15,17 +15,17 @@
*
* When we're called, the "gp" registers are stored in gprData and
* the "fp" registers are stored in fprData. There are 8 regs
* available which correspond to the first 7 parameters of the
* function and the "this" pointer. If there are additional parms,
* they are stored on the stack at address "args".
*
*/
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint64_t* args,
uint64_t *gprData, double *fprData)
{
#define PARAM_BUFFER_COUNT 16
#define PARAM_GPR_COUNT 7
#define PARAM_FPR_COUNT 7
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_netbsd_m68k.cpp
@@ -7,17 +7,17 @@
#include "xptcprivate.h"
#if !defined(__NetBSD__) || !defined(__m68k__)
#error This code is for NetBSD/m68k only
#endif
extern "C" {
- static nsresult
+ static nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
nsIInterfaceInfo* iface_info = nullptr;
const nsXPTMethodInfo* info;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_pa32.cpp
@@ -9,17 +9,17 @@
#include "xptcprivate.h"
#include "xptiprivate.h"
#if _HPUX
#error "This code is for HP-PA RISC 32 bit mode only"
#endif
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex,
uint32_t* args, uint32_t* floatargs)
{
typedef struct {
uint32_t hi;
uint32_t lo;
} DU;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc64_linux.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc64_linux.cpp
@@ -27,17 +27,17 @@
//
// - 'args[]' contains the arguments passed on stack
// - 'gprData[]' contains the arguments passed in integer registers
// - 'fprData[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
#include <stdio.h>
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self,
uint64_t methodIndex,
uint64_t* args,
uint64_t *gprData,
double *fprData)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix.cpp
@@ -11,17 +11,17 @@
#if defined(AIX)
/*
For PPC (AIX & MAC), the first 8 integral and the first 13 f.p. parameters
arrive in a separate chunk of data that has been loaded from the registers.
The args pointer has been set to the start of the parameters BEYOND the ones
arriving in registers
*/
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args, uint32_t *gprData, double *fprData)
{
typedef struct {
uint32_t hi;
uint32_t lo; // have to move 64 bit entities as 32 bit halves since
} DU; // stack slots are not guaranteed 16 byte aligned
#define PARAM_BUFFER_COUNT 16
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_aix64.cpp
@@ -10,17 +10,17 @@
#if defined(AIX)
/*
For PPC (AIX & MAC), the first 8 integral and the first 13 f.p. parameters
arrive in a separate chunk of data that has been loaded from the registers.
The args pointer has been set to the start of the parameters BEYOND the ones
arriving in registers
*/
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint64_t methodIndex, uint64_t* args, uint64_t *gprData, double *fprData)
{
#define PARAM_BUFFER_COUNT 16
#define PARAM_GPR_COUNT 7
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_linux.cpp
@@ -26,17 +26,17 @@
//
// - 'args[]' contains the arguments passed on stack
// - 'gprData[]' contains the arguments passed in integer registers
// - 'fprData[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self,
uint32_t methodIndex,
uint32_t* args,
uint32_t *gprData,
double *fprData)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_netbsd.cpp
@@ -22,17 +22,17 @@
//
// - 'args[]' contains the arguments passed on stack
// - 'gprData[]' contains the arguments passed in integer registers
// - 'fprData[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self,
uint32_t methodIndex,
uint32_t* args,
uint32_t *gprData,
double *fprData)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_openbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_openbsd.cpp
@@ -23,17 +23,17 @@
//
// - 'args[]' contains the arguments passed on stack
// - 'gprData[]' contains the arguments passed in integer registers
// - 'fprData[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self,
uint32_t methodIndex,
uint32_t* args,
uint32_t *gprData,
double *fprData)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_ppc_rhapsody.cpp
@@ -30,17 +30,17 @@
* stack without any special padding.
*
* See also xptcstubs_asm_ppc_darwin.s.m4:_SharedStub.
*
* ABI reference:
* http://developer.apple.com/documentation/DeveloperTools/Conceptual/
* MachORuntime/PowerPCConventions/chapter_3_section_1.html */
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(
nsXPTCStubBase *self,
uint32_t methodIndex,
uint32_t *argsStack,
uint32_t *argsGPR,
double *argsFPR) {
#define PARAM_BUFFER_COUNT 16
#define PARAM_FPR_COUNT 13
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc64_openbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc64_openbsd.cpp
@@ -6,17 +6,17 @@
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
#if defined(sparc) || defined(__sparc__)
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint64_t methodIndex, uint64_t* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_netbsd.cpp
@@ -4,17 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#if defined(sparc) || defined(__sparc__)
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
typedef struct {
uint32_t hi;
uint32_t lo;
} DU; // have to move 64 bit entities as 32 bit halves since
// stack slots are not guaranteed 16 byte aligned
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_openbsd.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_openbsd.cpp
@@ -4,17 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#if defined(sparc) || defined(__sparc__)
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
typedef struct {
uint32_t hi;
uint32_t lo;
} DU; // have to move 64 bit entities as 32 bit halves since
// stack slots are not guaranteed 16 byte aligned
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparc_solaris.cpp
@@ -5,17 +5,17 @@
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
#if defined(sparc) || defined(__sparc__)
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
typedef struct {
uint32_t hi;
uint32_t lo;
} DU; // have to move 64 bit entities as 32 bit halves since
// stack slots are not guaranteed 16 byte aligned
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_sparcv9_solaris.cpp
@@ -6,17 +6,17 @@
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
#if defined(sparc) || defined(__sparc__)
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint64_t methodIndex, uint64_t* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_darwin.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_darwin.cpp
@@ -25,17 +25,17 @@ const uint32_t FPR_COUNT = 8;
//
// - 'args[]' contains the arguments passed on stack
// - 'gpregs[]' contains the arguments passed in integer registers
// - 'fpregs[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase * self, uint32_t methodIndex,
uint64_t * args, uint64_t * gpregs, double *fpregs)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
uint32_t paramCount;
uint32_t i;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_linux.cpp
@@ -25,17 +25,17 @@ const uint32_t FPR_COUNT = 8;
//
// - 'args[]' contains the arguments passed on stack
// - 'gpregs[]' contains the arguments passed in integer registers
// - 'fpregs[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase * self, uint32_t methodIndex,
uint64_t * args, uint64_t * gpregs, double *fpregs)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
uint32_t paramCount;
uint32_t i;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_64_solaris.cpp
@@ -25,17 +25,17 @@ const uint32_t FPR_COUNT = 8;
//
// - 'args[]' contains the arguments passed on stack
// - 'gpregs[]' contains the arguments passed in integer registers
// - 'fpregs[]' contains the arguments passed in floating point registers
//
// The parameters are mapped into an array of type 'nsXPTCMiniVariant'
// and then the method gets called.
-extern "C" nsresult
+extern "C" nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase * self, uint32_t methodIndex,
uint64_t * args, uint64_t * gpregs, double *fpregs)
{
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
uint32_t paramCount;
uint32_t i;
--- a/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp
+++ b/xpcom/reflect/xptcall/src/md/unix/xptcstubs_x86_solaris.cpp
@@ -4,17 +4,17 @@
* 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/. */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
-nsresult
+nsresult ATTRIBUTE_USED
PrepareAndDispatch(nsXPTCStubBase* self, uint32_t methodIndex, uint32_t* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = nullptr;
const nsXPTMethodInfo* info;
uint8_t paramCount;
--- a/xpcom/reflect/xptcall/src/md/win32/xptcstubs_x86_64_gnu.cpp
+++ b/xpcom/reflect/xptcall/src/md/win32/xptcstubs_x86_64_gnu.cpp
@@ -11,17 +11,17 @@
* This is for Windows 64 bit (x86_64) using GCC syntax
* Code was copied from the MSVC version.
*/
#if !defined(_AMD64_) || !defined(__GNUC__)
# error xptcstubs_x86_64_gnu.cpp being used unexpectedly
#endif
-extern "C" nsresult
+extern "C" nsresult __attribute__((__used__))
PrepareAndDispatch(nsXPTCStubBase * self, uint32_t methodIndex,
uint64_t * args, uint64_t * gprData, double *fprData)
{
#define PARAM_BUFFER_COUNT 16
//
// "this" pointer is first parameter, so parameter count is 3.
//
#define PARAM_GPR_COUNT 3
--- a/xpcom/reflect/xptcall/src/xptcprivate.h
+++ b/xpcom/reflect/xptcall/src/xptcprivate.h
@@ -53,9 +53,15 @@ public:
xptiInterfaceEntry* mEntry;
~nsXPTCStubBase() { }
};
#undef STUB_ENTRY
#undef SENTINEL_ENTRY
+#if defined(__clang__) || defined(__GNUC__)
+#define ATTRIBUTE_USED __attribute__ ((__used__))
+#else
+#define ATTRIBUTE_USED
+#endif
+
#endif /* xptcprivate_h___ */