mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-02 08:41:34 +00:00
1072 lines
37 KiB
C++
1072 lines
37 KiB
C++
/* -*- 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 builtin_TypedObject_h
|
|
#define builtin_TypedObject_h
|
|
|
|
#include "jsobj.h"
|
|
#include "jsweakmap.h"
|
|
|
|
#include "builtin/TypedObjectConstants.h"
|
|
#include "js/Conversions.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
|
|
* create *type objects* (no relation to the type objects used in TI)
|
|
* that define the type layout. For example, a statement like:
|
|
*
|
|
* var PointType = new StructType({x: uint8, y: uint8});
|
|
*
|
|
* would create a type object PointType that is a struct with
|
|
* two fields, each of uint8 type.
|
|
*
|
|
* This comment typically assumes familiary with the API. For more
|
|
* info on the API itself, see the Harmony wiki page at
|
|
* http://wiki.ecmascript.org/doku.php?id=harmony:typed_objects or the
|
|
* ES6 spec (not finalized at the time of this writing).
|
|
*
|
|
* - Initialization:
|
|
*
|
|
* Currently, all "globals" related to typed objects are packaged
|
|
* within a single "module" object `TypedObject`. This module has its
|
|
* own js::Class and when that class is initialized, we also create
|
|
* and define all other values (in `js::InitTypedObjectModuleClass()`).
|
|
*
|
|
* - Type objects, meta type objects, and type representations:
|
|
*
|
|
* There are a number of pre-defined type objects, one for each
|
|
* scalar type (`uint8` etc). Each of these has its own class_,
|
|
* defined in `DefineNumericClass()`.
|
|
*
|
|
* There are also meta type objects (`ArrayType`, `StructType`).
|
|
* These constructors are not themselves type objects but rather the
|
|
* means for the *user* to construct new typed objects.
|
|
*
|
|
* 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 objects:
|
|
*
|
|
* A typed object is an instance of a *type object* (note the past participle).
|
|
* Typed objects can be either transparent or opaque, depending on whether
|
|
* their underlying buffer can be accessed. Transparent and opaque typed
|
|
* objects have different classes, and can have different physical layouts.
|
|
* The following layouts are possible:
|
|
*
|
|
* InlineTypedObject: Typed objects whose data immediately follows the object's
|
|
* header are inline typed objects. The buffer for these objects is created
|
|
* lazily and stored via the compartment's LazyArrayBufferTable, and points
|
|
* back into the object's internal data.
|
|
*
|
|
* OutlineTypedObject: Typed objects whose data is owned by another object,
|
|
* which can be either an array buffer or an inline typed object. Outline
|
|
* typed objects may be attached or unattached. An unattached typed object
|
|
* has no data associated with it. When first created, objects are always
|
|
* attached, but they can become unattached if their buffer is neutered.
|
|
*
|
|
* 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 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.
|
|
*/
|
|
|
|
namespace js {
|
|
|
|
/*
|
|
* Helper method for converting a double into other scalar
|
|
* types in the same way that JavaScript would. In particular,
|
|
* simple C casting from double to int32_t gets things wrong
|
|
* for values like 0xF0000000.
|
|
*/
|
|
template <typename T>
|
|
static T ConvertScalar(double d)
|
|
{
|
|
if (TypeIsFloatingPoint<T>()) {
|
|
return T(d);
|
|
} else if (TypeIsUnsigned<T>()) {
|
|
uint32_t n = JS::ToUint32(d);
|
|
return T(n);
|
|
} else {
|
|
int32_t n = JS::ToInt32(d);
|
|
return T(n);
|
|
}
|
|
}
|
|
|
|
namespace type {
|
|
|
|
enum Kind {
|
|
Scalar = JS_TYPEREPR_SCALAR_KIND,
|
|
Reference = JS_TYPEREPR_REFERENCE_KIND,
|
|
Simd = JS_TYPEREPR_SIMD_KIND,
|
|
Struct = JS_TYPEREPR_STRUCT_KIND,
|
|
Array = JS_TYPEREPR_ARRAY_KIND
|
|
};
|
|
|
|
} // namespace type
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Typed Prototypes
|
|
|
|
class SimpleTypeDescr;
|
|
class ComplexTypeDescr;
|
|
class SimdTypeDescr;
|
|
class StructTypeDescr;
|
|
class TypedProto;
|
|
|
|
/*
|
|
* The prototype for a typed object.
|
|
*/
|
|
class TypedProto : public NativeObject
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
};
|
|
|
|
class TypeDescr : public NativeObject
|
|
{
|
|
public:
|
|
TypedProto& typedProto() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_TYPROTO).toObject().as<TypedProto>();
|
|
}
|
|
|
|
JSAtom& stringRepr() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_STRING_REPR).toString()->asAtom();
|
|
}
|
|
|
|
type::Kind kind() const {
|
|
return (type::Kind) getReservedSlot(JS_DESCR_SLOT_KIND).toInt32();
|
|
}
|
|
|
|
bool opaque() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_OPAQUE).toBoolean();
|
|
}
|
|
|
|
bool transparent() const {
|
|
return !opaque();
|
|
}
|
|
|
|
int32_t alignment() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
|
|
}
|
|
|
|
int32_t size() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
|
|
}
|
|
|
|
// Whether id is an 'own' property of objects with this descriptor.
|
|
bool hasProperty(const JSAtomState& names, jsid id);
|
|
|
|
// Type descriptors may contain a list of their references for use during
|
|
// scanning. Marking code is optimized to use this list to mark inline
|
|
// typed objects, rather than the slower trace hook. This list is only
|
|
// specified when (a) the descriptor is short enough that it can fit in an
|
|
// InlineTypedObject, and (b) the descriptor contains at least one
|
|
// reference. Otherwise its value is undefined.
|
|
//
|
|
// The list is three consecutive arrays of int32_t offsets, with each array
|
|
// terminated by -1. The arrays store offsets of string, object, and value
|
|
// references in the descriptor, in that order.
|
|
bool hasTraceList() const {
|
|
return !getFixedSlot(JS_DESCR_SLOT_TRACE_LIST).isUndefined();
|
|
}
|
|
const int32_t* traceList() const {
|
|
MOZ_ASSERT(hasTraceList());
|
|
return reinterpret_cast<int32_t*>(getFixedSlot(JS_DESCR_SLOT_TRACE_LIST).toPrivate());
|
|
}
|
|
|
|
void initInstances(const JSRuntime* rt, uint8_t* mem, size_t length);
|
|
void traceInstances(JSTracer* trace, uint8_t* mem, size_t length);
|
|
|
|
static void finalize(FreeOp* fop, JSObject* obj);
|
|
};
|
|
|
|
typedef Handle<TypeDescr*> HandleTypeDescr;
|
|
|
|
class SimpleTypeDescr : public TypeDescr
|
|
{
|
|
};
|
|
|
|
// Type for scalar type constructors like `uint8`. All such type
|
|
// constructors share a common js::Class and JSFunctionSpec. Scalar
|
|
// types are non-opaque (their storage is visible unless combined with
|
|
// an opaque reference type.)
|
|
class ScalarTypeDescr : public SimpleTypeDescr
|
|
{
|
|
public:
|
|
typedef Scalar::Type Type;
|
|
|
|
static const type::Kind Kind = type::Scalar;
|
|
static const bool Opaque = false;
|
|
static int32_t size(Type t);
|
|
static int32_t alignment(Type t);
|
|
static const char* typeName(Type type);
|
|
|
|
static const Class class_;
|
|
static const JSFunctionSpec typeObjectMethods[];
|
|
|
|
Type type() const {
|
|
// Make sure the values baked into TypedObjectConstants.h line up with
|
|
// the Scalar::Type enum. We don't define Scalar::Type directly in
|
|
// terms of these constants to avoid making TypedObjectConstants.h a
|
|
// public header file.
|
|
static_assert(Scalar::Int8 == JS_SCALARTYPEREPR_INT8,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Uint8 == JS_SCALARTYPEREPR_UINT8,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Int16 == JS_SCALARTYPEREPR_INT16,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Uint16 == JS_SCALARTYPEREPR_UINT16,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Int32 == JS_SCALARTYPEREPR_INT32,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Uint32 == JS_SCALARTYPEREPR_UINT32,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Float32 == JS_SCALARTYPEREPR_FLOAT32,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Float64 == JS_SCALARTYPEREPR_FLOAT64,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Uint8Clamped == JS_SCALARTYPEREPR_UINT8_CLAMPED,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Float32x4 == JS_SCALARTYPEREPR_FLOAT32X4,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
static_assert(Scalar::Int32x4 == JS_SCALARTYPEREPR_INT32X4,
|
|
"TypedObjectConstants.h must be consistent with Scalar::Type");
|
|
|
|
return Type(getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32());
|
|
}
|
|
|
|
static bool call(JSContext* cx, unsigned argc, Value* vp);
|
|
};
|
|
|
|
// Enumerates the cases of ScalarTypeDescr::Type which have
|
|
// unique C representation. In particular, omits Uint8Clamped since it
|
|
// is just a Uint8.
|
|
#define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_) \
|
|
macro_(Scalar::Int8, int8_t, int8) \
|
|
macro_(Scalar::Uint8, uint8_t, uint8) \
|
|
macro_(Scalar::Int16, int16_t, int16) \
|
|
macro_(Scalar::Uint16, uint16_t, uint16) \
|
|
macro_(Scalar::Int32, int32_t, int32) \
|
|
macro_(Scalar::Uint32, uint32_t, uint32) \
|
|
macro_(Scalar::Float32, float, float32) \
|
|
macro_(Scalar::Float64, double, float64)
|
|
|
|
// Must be in same order as the enum ScalarTypeDescr::Type:
|
|
#define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_) \
|
|
JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_) \
|
|
macro_(Scalar::Uint8Clamped, uint8_t, uint8Clamped)
|
|
|
|
// Type for reference type constructors like `Any`, `String`, and
|
|
// `Object`. All such type constructors share a common js::Class and
|
|
// JSFunctionSpec. All these types are opaque.
|
|
class ReferenceTypeDescr : public SimpleTypeDescr
|
|
{
|
|
public:
|
|
// Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
|
|
enum Type {
|
|
TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
|
|
TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
|
|
TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
|
|
};
|
|
static const int32_t TYPE_MAX = TYPE_STRING + 1;
|
|
static const char* typeName(Type type);
|
|
|
|
static const type::Kind Kind = type::Reference;
|
|
static const bool Opaque = true;
|
|
static const Class class_;
|
|
static int32_t size(Type t);
|
|
static int32_t alignment(Type t);
|
|
static const JSFunctionSpec typeObjectMethods[];
|
|
|
|
ReferenceTypeDescr::Type type() const {
|
|
return (ReferenceTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
|
|
}
|
|
|
|
const char* typeName() const {
|
|
return typeName(type());
|
|
}
|
|
|
|
static bool call(JSContext* cx, unsigned argc, Value* vp);
|
|
};
|
|
|
|
#define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_) \
|
|
macro_(ReferenceTypeDescr::TYPE_ANY, HeapValue, Any) \
|
|
macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
|
|
macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
|
|
|
|
// Type descriptors whose instances are objects and hence which have
|
|
// an associated `prototype` property.
|
|
class ComplexTypeDescr : public TypeDescr
|
|
{
|
|
public:
|
|
// Returns the prototype that instances of this type descriptor
|
|
// will have.
|
|
TypedProto& instancePrototype() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_TYPROTO).toObject().as<TypedProto>();
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Type descriptors `int8x16`, `int16x8`, `int32x4`, `float32x4` and `float64x2`
|
|
*/
|
|
class SimdTypeDescr : public ComplexTypeDescr
|
|
{
|
|
public:
|
|
enum Type {
|
|
Int8x16 = JS_SIMDTYPEREPR_INT8X16,
|
|
Int16x8 = JS_SIMDTYPEREPR_INT16X8,
|
|
Int32x4 = JS_SIMDTYPEREPR_INT32X4,
|
|
Float32x4 = JS_SIMDTYPEREPR_FLOAT32X4,
|
|
Float64x2 = JS_SIMDTYPEREPR_FLOAT64X2,
|
|
LAST_TYPE = Float64x2
|
|
};
|
|
|
|
static const type::Kind Kind = type::Simd;
|
|
static const bool Opaque = false;
|
|
static const Class class_;
|
|
static int32_t size(Type t);
|
|
static int32_t alignment(Type t);
|
|
|
|
SimdTypeDescr::Type type() const {
|
|
uint32_t t = uint32_t(getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32());
|
|
MOZ_ASSERT(t <= LAST_TYPE);
|
|
return SimdTypeDescr::Type(t);
|
|
}
|
|
|
|
static bool call(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool is(const Value& v);
|
|
};
|
|
|
|
bool IsTypedObjectClass(const Class* clasp); // Defined below
|
|
bool IsTypedObjectArray(JSObject& obj);
|
|
|
|
bool CreateUserSizeAndAlignmentProperties(JSContext* cx, HandleTypeDescr obj);
|
|
|
|
class ArrayTypeDescr;
|
|
|
|
/*
|
|
* 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 NativeObject
|
|
{
|
|
private:
|
|
// Helper for creating a new ArrayType object.
|
|
//
|
|
// - `arrayTypePrototype` - prototype for the new object to be created
|
|
// - `elementType` - type object for the elements in the array
|
|
// - `stringRepr` - canonical string representation for the array
|
|
// - `size` - length of the array
|
|
static ArrayTypeDescr* create(JSContext* cx,
|
|
HandleObject arrayTypePrototype,
|
|
HandleTypeDescr elementType,
|
|
HandleAtom stringRepr,
|
|
int32_t size,
|
|
int32_t length);
|
|
|
|
public:
|
|
// Properties and methods to be installed on ArrayType.prototype,
|
|
// and hence inherited by all array type objects:
|
|
static const JSPropertySpec typeObjectProperties[];
|
|
static const JSFunctionSpec typeObjectMethods[];
|
|
|
|
// Properties and methods to be installed on ArrayType.prototype.prototype,
|
|
// and hence inherited by all array *typed* objects:
|
|
static const JSPropertySpec typedObjectProperties[];
|
|
static const JSFunctionSpec typedObjectMethods[];
|
|
|
|
// This is the function that gets called when the user
|
|
// does `new ArrayType(elem)`. It produces an array type object.
|
|
static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
|
};
|
|
|
|
/*
|
|
* Type descriptor created by `new ArrayType(type, n)`
|
|
*/
|
|
class ArrayTypeDescr : public ComplexTypeDescr
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
static const type::Kind Kind = type::Array;
|
|
|
|
TypeDescr& elementType() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<TypeDescr>();
|
|
}
|
|
|
|
int32_t length() const {
|
|
return getReservedSlot(JS_DESCR_SLOT_ARRAY_LENGTH).toInt32();
|
|
}
|
|
|
|
static int32_t offsetOfLength() {
|
|
return getFixedSlotOffset(JS_DESCR_SLOT_ARRAY_LENGTH);
|
|
}
|
|
};
|
|
|
|
/*
|
|
* Properties and methods of the `StructType` meta type object. There
|
|
* is no `class_` field because `StructType` is just a native
|
|
* constructor function.
|
|
*/
|
|
class StructMetaTypeDescr : public NativeObject
|
|
{
|
|
private:
|
|
static JSObject* create(JSContext* cx, HandleObject structTypeGlobal,
|
|
HandleObject fields);
|
|
|
|
public:
|
|
// Properties and methods to be installed on StructType.prototype,
|
|
// and hence inherited by all struct type objects:
|
|
static const JSPropertySpec typeObjectProperties[];
|
|
static const JSFunctionSpec typeObjectMethods[];
|
|
|
|
// Properties and methods to be installed on StructType.prototype.prototype,
|
|
// and hence inherited by all struct *typed* objects:
|
|
static const JSPropertySpec typedObjectProperties[];
|
|
static const JSFunctionSpec typedObjectMethods[];
|
|
|
|
// This is the function that gets called when the user
|
|
// does `new StructType(...)`. It produces a struct type object.
|
|
static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
|
};
|
|
|
|
class StructTypeDescr : public ComplexTypeDescr
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
|
|
// Returns the number of fields defined in this struct.
|
|
size_t fieldCount() const;
|
|
size_t maybeForwardedFieldCount() const;
|
|
|
|
// Set `*out` to the index of the field named `id` and returns true,
|
|
// or return false if no such field exists.
|
|
bool fieldIndex(jsid id, size_t* out) const;
|
|
|
|
// Return the name of the field at index `index`.
|
|
JSAtom& fieldName(size_t index) const;
|
|
|
|
// Return the type descr of the field at index `index`.
|
|
TypeDescr& fieldDescr(size_t index) const;
|
|
TypeDescr& maybeForwardedFieldDescr(size_t index) const;
|
|
|
|
// Return the offset of the field at index `index`.
|
|
size_t fieldOffset(size_t index) const;
|
|
size_t maybeForwardedFieldOffset(size_t index) const;
|
|
|
|
private:
|
|
ArrayObject& fieldInfoObject(size_t slot) const {
|
|
return getReservedSlot(slot).toObject().as<ArrayObject>();
|
|
}
|
|
};
|
|
|
|
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 NativeObject {
|
|
public:
|
|
enum Slot {
|
|
ArrayTypePrototype,
|
|
StructTypePrototype,
|
|
SlotCount
|
|
};
|
|
|
|
static const Class class_;
|
|
};
|
|
|
|
/* Base type for transparent and opaque typed objects. */
|
|
class TypedObject : public JSObject
|
|
{
|
|
static const bool IsTypedObjectClass = true;
|
|
|
|
static bool obj_getArrayElement(JSContext* cx,
|
|
Handle<TypedObject*> typedObj,
|
|
Handle<TypeDescr*> typeDescr,
|
|
uint32_t index,
|
|
MutableHandleValue vp);
|
|
|
|
protected:
|
|
HeapPtrShape shape_;
|
|
|
|
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
|
|
HandleId id, MutableHandleObject objp,
|
|
MutableHandleShape propp);
|
|
|
|
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
|
|
Handle<JSPropertyDescriptor> desc,
|
|
ObjectOpResult& result);
|
|
|
|
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
|
|
|
|
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
|
|
HandleId id, MutableHandleValue vp);
|
|
|
|
static bool obj_getElement(JSContext* cx, HandleObject obj, HandleValue receiver,
|
|
uint32_t index, MutableHandleValue vp);
|
|
|
|
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
|
HandleValue receiver, ObjectOpResult& result);
|
|
|
|
static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
|
|
MutableHandle<JSPropertyDescriptor> desc);
|
|
|
|
static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
|
|
ObjectOpResult& result);
|
|
|
|
static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
|
|
bool enumerableOnly);
|
|
|
|
public:
|
|
TypedProto& typedProto() const {
|
|
return getProto()->as<TypedProto>();
|
|
}
|
|
|
|
TypeDescr& typeDescr() const {
|
|
return group()->typeDescr();
|
|
}
|
|
|
|
int32_t offset() const;
|
|
int32_t length() const;
|
|
uint8_t* typedMem() const;
|
|
uint8_t* typedMemBase() const;
|
|
bool isAttached() const;
|
|
bool maybeForwardedIsAttached() const;
|
|
|
|
int32_t size() const {
|
|
return typeDescr().size();
|
|
}
|
|
|
|
uint8_t* typedMem(size_t offset) const {
|
|
// It seems a bit surprising that one might request an offset
|
|
// == size(), but it can happen when taking the "address of" a
|
|
// 0-sized value. (In other words, we maintain the invariant
|
|
// that `offset + size <= size()` -- this is always checked in
|
|
// the caller's side.)
|
|
MOZ_ASSERT(offset <= (size_t) size());
|
|
return typedMem() + offset;
|
|
}
|
|
|
|
inline bool opaque() const;
|
|
|
|
// 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,
|
|
gc::InitialHeap heap = gc::DefaultHeap);
|
|
|
|
// User-accessible constructor (`new TypeDescriptor(...)`). Note that the
|
|
// callee here is the type descriptor.
|
|
static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/* Accessors for self hosted code. */
|
|
static bool GetBuffer(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool GetByteOffset(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
Shape** addressOfShapeFromGC() { return shape_.unsafeUnbarrieredForTracing(); }
|
|
};
|
|
|
|
typedef Handle<TypedObject*> HandleTypedObject;
|
|
|
|
class OutlineTypedObject : public TypedObject
|
|
{
|
|
// The object which owns the data this object points to. Because this
|
|
// pointer is managed in tandem with |data|, this is not a HeapPtr and
|
|
// barriers are managed directly.
|
|
JSObject* owner_;
|
|
|
|
// Data pointer to some offset in the owner's contents.
|
|
uint8_t* data_;
|
|
|
|
void setOwnerAndData(JSObject* owner, uint8_t* data);
|
|
|
|
public:
|
|
// JIT accessors.
|
|
static size_t offsetOfData() { return offsetof(OutlineTypedObject, data_); }
|
|
static size_t offsetOfOwner() { return offsetof(OutlineTypedObject, owner_); }
|
|
|
|
JSObject& owner() const {
|
|
MOZ_ASSERT(owner_);
|
|
return *owner_;
|
|
}
|
|
|
|
JSObject* maybeOwner() const {
|
|
return owner_;
|
|
}
|
|
|
|
uint8_t* outOfLineTypedMem() const {
|
|
return data_;
|
|
}
|
|
|
|
void setData(uint8_t* data) {
|
|
data_ = data;
|
|
}
|
|
|
|
// Helper for createUnattached()
|
|
static OutlineTypedObject* createUnattachedWithClass(JSContext* cx,
|
|
const Class* clasp,
|
|
HandleTypeDescr type,
|
|
int32_t length,
|
|
gc::InitialHeap heap = gc::DefaultHeap);
|
|
|
|
// 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
|
|
static OutlineTypedObject* createUnattached(JSContext* cx, HandleTypeDescr type,
|
|
int32_t length, gc::InitialHeap heap = gc::DefaultHeap);
|
|
|
|
// 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 OutlineTypedObject* createDerived(JSContext* cx,
|
|
HandleTypeDescr type,
|
|
Handle<TypedObject*> typedContents,
|
|
int32_t offset);
|
|
|
|
// Use this method when `buffer` is the owner of the memory.
|
|
void attach(JSContext* cx, ArrayBufferObject& buffer, int32_t offset);
|
|
|
|
// Otherwise, use this to attach to memory referenced by another typedObj.
|
|
void attach(JSContext* cx, TypedObject& typedObj, int32_t offset);
|
|
|
|
// Invoked when array buffer is transferred elsewhere
|
|
void neuter(void* newData);
|
|
|
|
static void obj_trace(JSTracer* trace, JSObject* object);
|
|
};
|
|
|
|
// Class for a transparent typed object whose owner is an array buffer.
|
|
class OutlineTransparentTypedObject : public OutlineTypedObject
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
|
|
ArrayBufferObject* getOrCreateBuffer(JSContext* cx);
|
|
};
|
|
|
|
// Class for an opaque typed object whose owner may be either an array buffer
|
|
// or an opaque inlined typed object.
|
|
class OutlineOpaqueTypedObject : public OutlineTypedObject
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
};
|
|
|
|
// Class for a typed object whose data is allocated inline.
|
|
class InlineTypedObject : public TypedObject
|
|
{
|
|
// Start of the inline data, which immediately follows the shape and type.
|
|
uint8_t data_[1];
|
|
|
|
public:
|
|
static const size_t MaximumSize = JSObject::MAX_BYTE_SIZE - sizeof(TypedObject);
|
|
|
|
static gc::AllocKind allocKindForTypeDescriptor(TypeDescr* descr) {
|
|
size_t nbytes = descr->size();
|
|
MOZ_ASSERT(nbytes <= MaximumSize);
|
|
|
|
return gc::GetGCObjectKindForBytes(nbytes + sizeof(TypedObject));
|
|
}
|
|
|
|
uint8_t* inlineTypedMem() const {
|
|
return (uint8_t*) &data_;
|
|
}
|
|
|
|
static void obj_trace(JSTracer* trace, JSObject* object);
|
|
static void objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src);
|
|
|
|
static size_t offsetOfDataStart() {
|
|
return offsetof(InlineTypedObject, data_);
|
|
}
|
|
|
|
static InlineTypedObject* create(JSContext* cx, HandleTypeDescr descr,
|
|
gc::InitialHeap heap = gc::DefaultHeap);
|
|
static InlineTypedObject* createCopy(JSContext* cx, Handle<InlineTypedObject*> templateObject,
|
|
gc::InitialHeap heap);
|
|
};
|
|
|
|
// Class for a transparent typed object with inline data, which may have a
|
|
// lazily allocated array buffer.
|
|
class InlineTransparentTypedObject : public InlineTypedObject
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
|
|
ArrayBufferObject* getOrCreateBuffer(JSContext* cx);
|
|
};
|
|
|
|
// Class for an opaque typed object with inline data and no array buffer.
|
|
class InlineOpaqueTypedObject : public InlineTypedObject
|
|
{
|
|
public:
|
|
static const Class class_;
|
|
};
|
|
|
|
/*
|
|
* Usage: NewOpaqueTypedObject(typeObj)
|
|
*
|
|
* Constructs a new, unattached instance of `Handle`.
|
|
*/
|
|
bool NewOpaqueTypedObject(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: NewDerivedTypedObject(typeObj, owner, offset)
|
|
*
|
|
* Constructs a new, unattached instance of `Handle`.
|
|
*/
|
|
bool NewDerivedTypedObject(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: AttachTypedObject(typedObj, newDatum, newOffset)
|
|
*
|
|
* Moves `typedObj` to point at the memory referenced by `newDatum` with
|
|
* the offset `newOffset`.
|
|
*/
|
|
bool AttachTypedObject(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: SetTypedObjectOffset(typedObj, offset)
|
|
*
|
|
* Changes the offset for `typedObj` within its buffer to `offset`.
|
|
* `typedObj` must already be attached.
|
|
*/
|
|
bool SetTypedObjectOffset(JSContext*, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: ObjectIsTypeDescr(obj)
|
|
*
|
|
* True if `obj` is a type object.
|
|
*/
|
|
bool ObjectIsTypeDescr(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: ObjectIsTypedObject(obj)
|
|
*
|
|
* True if `obj` is a transparent or opaque typed object.
|
|
*/
|
|
bool ObjectIsTypedObject(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: ObjectIsOpaqueTypedObject(obj)
|
|
*
|
|
* True if `obj` is an opaque typed object.
|
|
*/
|
|
bool ObjectIsOpaqueTypedObject(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: ObjectIsTransparentTypedObject(obj)
|
|
*
|
|
* True if `obj` is a transparent typed object.
|
|
*/
|
|
bool ObjectIsTransparentTypedObject(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/* Predicates on type descriptor objects. In all cases, 'obj' must be a type descriptor. */
|
|
|
|
bool TypeDescrIsSimpleType(JSContext*, unsigned argc, Value* vp);
|
|
|
|
bool TypeDescrIsArrayType(JSContext*, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: TypedObjectIsAttached(obj)
|
|
*
|
|
* Given a TypedObject `obj`, returns true if `obj` is
|
|
* "attached" (i.e., its data pointer is nullptr).
|
|
*/
|
|
bool TypedObjectIsAttached(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: TypedObjectTypeDescr(obj)
|
|
*
|
|
* Given a TypedObject `obj`, returns the object's type descriptor.
|
|
*/
|
|
bool TypedObjectTypeDescr(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: ClampToUint8(v)
|
|
*
|
|
* Same as the C function ClampDoubleToUint8. `v` must be a number.
|
|
*/
|
|
bool ClampToUint8(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: GetTypedObjectModule()
|
|
*
|
|
* Returns the global "typed object" module, which provides access
|
|
* to the various builtin type descriptors. These are currently
|
|
* exported as immutable properties so it is safe for self-hosted code
|
|
* 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
|
|
* been initialized for this to be safe.
|
|
*/
|
|
bool GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: GetFloat64x2TypeDescr()
|
|
*
|
|
* Returns the float64x2 type object. SIMD pseudo-module must have
|
|
* been initialized for this to be safe.
|
|
*/
|
|
bool GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: GetInt8x16TypeDescr()
|
|
*
|
|
* Returns the int8x16 type object. SIMD pseudo-module must have
|
|
* been initialized for this to be safe.
|
|
*/
|
|
bool GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: GetInt16x8TypeDescr()
|
|
*
|
|
* Returns the int16x8 type object. SIMD pseudo-module must have
|
|
* been initialized for this to be safe.
|
|
*/
|
|
bool GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
/*
|
|
* Usage: GetInt32x4TypeDescr()
|
|
*
|
|
* 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)
|
|
* ...
|
|
* Store_float32(targetDatum, targetOffset, value)
|
|
* Store_float64(targetDatum, targetOffset, value)
|
|
*
|
|
* Intrinsic function. Stores `value` into the memory referenced by
|
|
* `targetDatum` at the offset `targetOffset`.
|
|
*
|
|
* Assumes (and asserts) that:
|
|
* - `targetDatum` is attached
|
|
* - `targetOffset` is a valid offset within the bounds of `targetDatum`
|
|
* - `value` is a number
|
|
*/
|
|
#define JS_STORE_SCALAR_CLASS_DEFN(_constant, T, _name) \
|
|
class StoreScalar##T { \
|
|
public: \
|
|
static bool Func(JSContext* cx, unsigned argc, Value* vp); \
|
|
static const JSJitInfo JitInfo; \
|
|
};
|
|
|
|
/*
|
|
* Usage: Store_Any(targetDatum, targetOffset, fieldName, value)
|
|
* Store_Object(targetDatum, targetOffset, fieldName, value)
|
|
* Store_string(targetDatum, targetOffset, fieldName, value)
|
|
*
|
|
* Intrinsic function. Stores `value` into the memory referenced by
|
|
* `targetDatum` at the offset `targetOffset`.
|
|
*
|
|
* Assumes (and asserts) that:
|
|
* - `targetDatum` is attached
|
|
* - `targetOffset` is a valid offset within the bounds of `targetDatum`
|
|
* - `value` is an object or null (`Store_Object`) or string (`Store_string`).
|
|
*/
|
|
#define JS_STORE_REFERENCE_CLASS_DEFN(_constant, T, _name) \
|
|
class StoreReference##T { \
|
|
private: \
|
|
static bool store(JSContext* cx, T* heap, const Value& v, \
|
|
TypedObject* obj, jsid id); \
|
|
\
|
|
public: \
|
|
static bool Func(JSContext* cx, unsigned argc, Value* vp); \
|
|
static const JSJitInfo JitInfo; \
|
|
};
|
|
|
|
/*
|
|
* Usage: LoadScalar(targetDatum, targetOffset, value)
|
|
*
|
|
* Intrinsic function. Loads value (which must be an int32 or uint32)
|
|
* by `scalarTypeRepr` (which must be a type repr obj) and loads the
|
|
* value at the memory for `targetDatum` at offset `targetOffset`.
|
|
* `targetDatum` must be attached.
|
|
*/
|
|
#define JS_LOAD_SCALAR_CLASS_DEFN(_constant, T, _name) \
|
|
class LoadScalar##T { \
|
|
public: \
|
|
static bool Func(JSContext* cx, unsigned argc, Value* vp); \
|
|
static const JSJitInfo JitInfo; \
|
|
};
|
|
|
|
/*
|
|
* Usage: LoadReference(targetDatum, targetOffset, value)
|
|
*
|
|
* Intrinsic function. Stores value (which must be an int32 or uint32)
|
|
* by `scalarTypeRepr` (which must be a type repr obj) and stores the
|
|
* value at the memory for `targetDatum` at offset `targetOffset`.
|
|
* `targetDatum` must be attached.
|
|
*/
|
|
#define JS_LOAD_REFERENCE_CLASS_DEFN(_constant, T, _name) \
|
|
class LoadReference##T { \
|
|
private: \
|
|
static void load(T* heap, MutableHandleValue v); \
|
|
\
|
|
public: \
|
|
static bool Func(JSContext* cx, unsigned argc, Value* vp); \
|
|
static const JSJitInfo JitInfo; \
|
|
};
|
|
|
|
// 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_ == &OutlineTransparentTypedObject::class_ ||
|
|
class_ == &InlineTransparentTypedObject::class_ ||
|
|
class_ == &OutlineOpaqueTypedObject::class_ ||
|
|
class_ == &InlineOpaqueTypedObject::class_;
|
|
}
|
|
|
|
inline bool
|
|
IsOpaqueTypedObjectClass(const Class* class_)
|
|
{
|
|
return class_ == &OutlineOpaqueTypedObject::class_ ||
|
|
class_ == &InlineOpaqueTypedObject::class_;
|
|
}
|
|
|
|
inline bool
|
|
IsOutlineTypedObjectClass(const Class* class_)
|
|
{
|
|
return class_ == &OutlineOpaqueTypedObject::class_ ||
|
|
class_ == &OutlineTransparentTypedObject::class_;
|
|
}
|
|
|
|
inline bool
|
|
IsInlineTypedObjectClass(const Class* class_)
|
|
{
|
|
return class_ == &InlineOpaqueTypedObject::class_ ||
|
|
class_ == &InlineTransparentTypedObject::class_;
|
|
}
|
|
|
|
inline const Class*
|
|
GetOutlineTypedObjectClass(bool opaque)
|
|
{
|
|
return opaque ? &OutlineOpaqueTypedObject::class_ : &OutlineTransparentTypedObject::class_;
|
|
}
|
|
|
|
inline bool
|
|
IsSimpleTypeDescrClass(const Class* clasp)
|
|
{
|
|
return clasp == &ScalarTypeDescr::class_ ||
|
|
clasp == &ReferenceTypeDescr::class_;
|
|
}
|
|
|
|
inline bool
|
|
IsComplexTypeDescrClass(const Class* clasp)
|
|
{
|
|
return clasp == &StructTypeDescr::class_ ||
|
|
clasp == &ArrayTypeDescr::class_ ||
|
|
clasp == &SimdTypeDescr::class_;
|
|
}
|
|
|
|
inline bool
|
|
IsTypeDescrClass(const Class* clasp)
|
|
{
|
|
return IsSimpleTypeDescrClass(clasp) ||
|
|
IsComplexTypeDescrClass(clasp);
|
|
}
|
|
|
|
inline bool
|
|
TypedObject::opaque() const
|
|
{
|
|
return IsOpaqueTypedObjectClass(getClass());
|
|
}
|
|
|
|
JSObject*
|
|
InitTypedObjectModuleObject(JSContext* cx, JS::HandleObject obj);
|
|
|
|
} // namespace js
|
|
|
|
template <>
|
|
inline bool
|
|
JSObject::is<js::SimpleTypeDescr>() const
|
|
{
|
|
return IsSimpleTypeDescrClass(getClass());
|
|
}
|
|
|
|
template <>
|
|
inline bool
|
|
JSObject::is<js::ComplexTypeDescr>() const
|
|
{
|
|
return IsComplexTypeDescrClass(getClass());
|
|
}
|
|
|
|
template <>
|
|
inline bool
|
|
JSObject::is<js::TypeDescr>() const
|
|
{
|
|
return IsTypeDescrClass(getClass());
|
|
}
|
|
|
|
template <>
|
|
inline bool
|
|
JSObject::is<js::TypedObject>() const
|
|
{
|
|
return IsTypedObjectClass(getClass());
|
|
}
|
|
|
|
template <>
|
|
inline bool
|
|
JSObject::is<js::OutlineTypedObject>() const
|
|
{
|
|
return getClass() == &js::OutlineTransparentTypedObject::class_ ||
|
|
getClass() == &js::OutlineOpaqueTypedObject::class_;
|
|
}
|
|
|
|
template <>
|
|
inline bool
|
|
JSObject::is<js::InlineTypedObject>() const
|
|
{
|
|
return getClass() == &js::InlineTransparentTypedObject::class_ ||
|
|
getClass() == &js::InlineOpaqueTypedObject::class_;
|
|
}
|
|
|
|
#endif /* builtin_TypedObject_h */
|