js/src/builtin/TypedObject.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef builtin_TypedObject_h
     8 #define builtin_TypedObject_h
    10 #include "jsobj.h"
    12 #include "builtin/TypedObjectConstants.h"
    13 #include "vm/ArrayBufferObject.h"
    15 /*
    16  * -------------
    17  * Typed Objects
    18  * -------------
    19  *
    20  * Typed objects are a special kind of JS object where the data is
    21  * given well-structured form. To use a typed object, users first
    22  * create *type objects* (no relation to the type objects used in TI)
    23  * that define the type layout. For example, a statement like:
    24  *
    25  *    var PointType = new StructType({x: uint8, y: uint8});
    26  *
    27  * would create a type object PointType that is a struct with
    28  * two fields, each of uint8 type.
    29  *
    30  * This comment typically assumes familiary with the API.  For more
    31  * info on the API itself, see the Harmony wiki page at
    32  * http://wiki.ecmascript.org/doku.php?id=harmony:typed_objects or the
    33  * ES6 spec (not finalized at the time of this writing).
    34  *
    35  * - Initialization:
    36  *
    37  * Currently, all "globals" related to typed objects are packaged
    38  * within a single "module" object `TypedObject`. This module has its
    39  * own js::Class and when that class is initialized, we also create
    40  * and define all other values (in `js_InitTypedObjectModuleClass()`).
    41  *
    42  * - Type objects, meta type objects, and type representations:
    43  *
    44  * There are a number of pre-defined type objects, one for each
    45  * scalar type (`uint8` etc). Each of these has its own class_,
    46  * defined in `DefineNumericClass()`.
    47  *
    48  * There are also meta type objects (`ArrayType`, `StructType`).
    49  * These constructors are not themselves type objects but rather the
    50  * means for the *user* to construct new typed objects.
    51  *
    52  * Each type object is associated with a *type representation* (see
    53  * TypeRepresentation.h). Type representations are canonical versions
    54  * of type objects. We attach them to TI type objects and (eventually)
    55  * use them for shape guards etc. They are purely internal to the
    56  * engine and are not exposed to end users (though self-hosted code
    57  * sometimes accesses them).
    58  *
    59  * - Typed objects:
    60  *
    61  * A typed object is an instance of a *type object* (note the past
    62  * participle). There is one class for *transparent* typed objects and
    63  * one for *opaque* typed objects. These classes are equivalent in
    64  * basically every way, except that requesting the backing buffer of
    65  * an opaque typed object yields null. We use distinct js::Classes to
    66  * avoid the need for an extra slot in every typed object.
    67  *
    68  * Note that whether a typed object is opaque is not directly
    69  * connected to its type. That is, opaque types are *always*
    70  * represented by opaque typed objects, but you may have opaque typed
    71  * objects for transparent types too. This can occur for two reasons:
    72  * (1) a transparent type may be embedded within an opaque type or (2)
    73  * users can choose to convert transparent typed objects into opaque
    74  * ones to avoid giving access to the buffer itself.
    75  *
    76  * Typed objects (no matter their class) are non-native objects that
    77  * fully override the property accessors etc. The overridden accessor
    78  * methods are the same in each and are defined in methods of
    79  * TypedObject.
    80  *
    81  * Typed objects may be attached or unattached. An unattached typed
    82  * object has no memory associated with it; it is basically a null
    83  * pointer. When first created, objects are always attached, but they
    84  * can become unattached if their buffer is neutered (note that this
    85  * implies that typed objects of opaque types can never be unattached).
    86  *
    87  * When a new typed object instance is created, fresh memory is
    88  * allocated and set as that typed object's private field. The object
    89  * is then considered the *owner* of that memory: when the object is
    90  * collected, its finalizer will free the memory. The fact that an
    91  * object `o` owns its memory is indicated by setting its reserved
    92  * slot JS_TYPEDOBJ_SLOT_OWNER to `o` (a trivial cycle, in other
    93  * words).
    94  *
    95  * Later, *derived* typed objects can be created, typically via an
    96  * access like `o.f` where `f` is some complex (non-scalar) type, but
    97  * also explicitly via Handle objects. In those cases, the memory
    98  * pointer of the derived object is set to alias the owner's memory
    99  * pointer, and the owner slot for the derived object is set to the
   100  * owner object, thus ensuring that the owner is not collected while
   101  * the derived object is alive. We always maintain the invariant that
   102  * JS_TYPEDOBJ_SLOT_OWNER is the true owner of the memory, meaning
   103  * that there is a shallow tree. This prevents an access pattern like
   104  * `a.b.c.d` from keeping all the intermediate objects alive.
   105  */
   107 namespace js {
   109 /*
   110  * Helper method for converting a double into other scalar
   111  * types in the same way that JavaScript would. In particular,
   112  * simple C casting from double to int32_t gets things wrong
   113  * for values like 0xF0000000.
   114  */
   115 template <typename T>
   116 static T ConvertScalar(double d)
   117 {
   118     if (TypeIsFloatingPoint<T>()) {
   119         return T(d);
   120     } else if (TypeIsUnsigned<T>()) {
   121         uint32_t n = ToUint32(d);
   122         return T(n);
   123     } else {
   124         int32_t n = ToInt32(d);
   125         return T(n);
   126     }
   127 }
   129 /*
   130  * The prototype for a typed object. Currently, carries a link to the
   131  * type descriptor. Eventually will carry most of the type information
   132  * we want.
   133  */
   134 class TypedProto : public JSObject
   135 {
   136   public:
   137     static const Class class_;
   139     inline void initTypeDescrSlot(TypeDescr &descr);
   141     TypeDescr &typeDescr() const {
   142         return getReservedSlot(JS_TYPROTO_SLOT_DESCR).toObject().as<TypeDescr>();
   143     }
   144 };
   146 class TypeDescr : public JSObject
   147 {
   148   public:
   149     // This is *intentionally* not defined so as to produce link
   150     // errors if a is<FooTypeDescr>() etc goes wrong. Otherwise, the
   151     // default implementation resolves this to a reference to
   152     // FooTypeDescr::class_ which resolves to
   153     // JSObject::class_. Debugging the resulting errors leads to much
   154     // fun and rejoicing.
   155     static const Class class_;
   157     enum Kind {
   158         Scalar = JS_TYPEREPR_SCALAR_KIND,
   159         Reference = JS_TYPEREPR_REFERENCE_KIND,
   160         X4 = JS_TYPEREPR_X4_KIND,
   161         Struct = JS_TYPEREPR_STRUCT_KIND,
   162         SizedArray = JS_TYPEREPR_SIZED_ARRAY_KIND,
   163         UnsizedArray = JS_TYPEREPR_UNSIZED_ARRAY_KIND,
   164     };
   166     static bool isSized(Kind kind) {
   167         return kind > JS_TYPEREPR_MAX_UNSIZED_KIND;
   168     }
   170     JSAtom &stringRepr() const {
   171         return getReservedSlot(JS_DESCR_SLOT_STRING_REPR).toString()->asAtom();
   172     }
   174     TypeDescr::Kind kind() const {
   175         return (TypeDescr::Kind) getReservedSlot(JS_DESCR_SLOT_KIND).toInt32();
   176     }
   178     bool opaque() const {
   179         return getReservedSlot(JS_DESCR_SLOT_OPAQUE).toBoolean();
   180     }
   182     bool transparent() const {
   183         return !opaque();
   184     }
   186     int32_t alignment() {
   187         return getReservedSlot(JS_DESCR_SLOT_ALIGNMENT).toInt32();
   188     }
   189 };
   191 typedef Handle<TypeDescr*> HandleTypeDescr;
   193 class SizedTypeDescr : public TypeDescr
   194 {
   195   public:
   196     int32_t size() {
   197         return getReservedSlot(JS_DESCR_SLOT_SIZE).toInt32();
   198     }
   200     void initInstances(const JSRuntime *rt, uint8_t *mem, size_t length);
   201     void traceInstances(JSTracer *trace, uint8_t *mem, size_t length);
   202 };
   204 typedef Handle<SizedTypeDescr*> HandleSizedTypeDescr;
   206 class SimpleTypeDescr : public SizedTypeDescr
   207 {
   208 };
   210 // Type for scalar type constructors like `uint8`. All such type
   211 // constructors share a common js::Class and JSFunctionSpec. Scalar
   212 // types are non-opaque (their storage is visible unless combined with
   213 // an opaque reference type.)
   214 class ScalarTypeDescr : public SimpleTypeDescr
   215 {
   216   public:
   217     // Must match order of JS_FOR_EACH_SCALAR_TYPE_REPR below
   218     enum Type {
   219         TYPE_INT8 = JS_SCALARTYPEREPR_INT8,
   220         TYPE_UINT8 = JS_SCALARTYPEREPR_UINT8,
   221         TYPE_INT16 = JS_SCALARTYPEREPR_INT16,
   222         TYPE_UINT16 = JS_SCALARTYPEREPR_UINT16,
   223         TYPE_INT32 = JS_SCALARTYPEREPR_INT32,
   224         TYPE_UINT32 = JS_SCALARTYPEREPR_UINT32,
   225         TYPE_FLOAT32 = JS_SCALARTYPEREPR_FLOAT32,
   226         TYPE_FLOAT64 = JS_SCALARTYPEREPR_FLOAT64,
   228         /*
   229          * Special type that's a uint8_t, but assignments are clamped to 0 .. 255.
   230          * Treat the raw data type as a uint8_t.
   231          */
   232         TYPE_UINT8_CLAMPED = JS_SCALARTYPEREPR_UINT8_CLAMPED,
   233     };
   234     static const int32_t TYPE_MAX = TYPE_UINT8_CLAMPED + 1;
   236     static const TypeDescr::Kind Kind = TypeDescr::Scalar;
   237     static const bool Opaque = false;
   238     static int32_t size(Type t);
   239     static int32_t alignment(Type t);
   240     static const char *typeName(Type type);
   242     static const Class class_;
   243     static const JSFunctionSpec typeObjectMethods[];
   245     ScalarTypeDescr::Type type() const {
   246         return (ScalarTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
   247     }
   249     static bool call(JSContext *cx, unsigned argc, Value *vp);
   250 };
   252 // Enumerates the cases of ScalarTypeDescr::Type which have
   253 // unique C representation. In particular, omits Uint8Clamped since it
   254 // is just a Uint8.
   255 #define JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                     \
   256     macro_(ScalarTypeDescr::TYPE_INT8,    int8_t,   int8)            \
   257     macro_(ScalarTypeDescr::TYPE_UINT8,   uint8_t,  uint8)           \
   258     macro_(ScalarTypeDescr::TYPE_INT16,   int16_t,  int16)           \
   259     macro_(ScalarTypeDescr::TYPE_UINT16,  uint16_t, uint16)          \
   260     macro_(ScalarTypeDescr::TYPE_INT32,   int32_t,  int32)           \
   261     macro_(ScalarTypeDescr::TYPE_UINT32,  uint32_t, uint32)          \
   262     macro_(ScalarTypeDescr::TYPE_FLOAT32, float,    float32)         \
   263     macro_(ScalarTypeDescr::TYPE_FLOAT64, double,   float64)
   265 // Must be in same order as the enum ScalarTypeDescr::Type:
   266 #define JS_FOR_EACH_SCALAR_TYPE_REPR(macro_)                                    \
   267     JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(macro_)                           \
   268     macro_(ScalarTypeDescr::TYPE_UINT8_CLAMPED, uint8_t, uint8Clamped)
   270 // Type for reference type constructors like `Any`, `String`, and
   271 // `Object`. All such type constructors share a common js::Class and
   272 // JSFunctionSpec. All these types are opaque.
   273 class ReferenceTypeDescr : public SimpleTypeDescr
   274 {
   275   public:
   276     // Must match order of JS_FOR_EACH_REFERENCE_TYPE_REPR below
   277     enum Type {
   278         TYPE_ANY = JS_REFERENCETYPEREPR_ANY,
   279         TYPE_OBJECT = JS_REFERENCETYPEREPR_OBJECT,
   280         TYPE_STRING = JS_REFERENCETYPEREPR_STRING,
   281     };
   282     static const int32_t TYPE_MAX = TYPE_STRING + 1;
   283     static const char *typeName(Type type);
   285     static const TypeDescr::Kind Kind = TypeDescr::Reference;
   286     static const bool Opaque = true;
   287     static const Class class_;
   288     static int32_t size(Type t);
   289     static int32_t alignment(Type t);
   290     static const JSFunctionSpec typeObjectMethods[];
   292     ReferenceTypeDescr::Type type() const {
   293         return (ReferenceTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
   294     }
   296     const char *typeName() const {
   297         return typeName(type());
   298     }
   300     static bool call(JSContext *cx, unsigned argc, Value *vp);
   301 };
   303 #define JS_FOR_EACH_REFERENCE_TYPE_REPR(macro_)                    \
   304     macro_(ReferenceTypeDescr::TYPE_ANY,    HeapValue, Any)        \
   305     macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
   306     macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
   308 // Type descriptors whose instances are objects and hence which have
   309 // an associated `prototype` property.
   310 class ComplexTypeDescr : public SizedTypeDescr
   311 {
   312   public:
   313     // Returns the prototype that instances of this type descriptor
   314     // will have.
   315     TypedProto &instancePrototype() const {
   316         return getReservedSlot(JS_DESCR_SLOT_TYPROTO).toObject().as<TypedProto>();
   317     }
   318 };
   320 /*
   321  * Type descriptors `float32x4` and `int32x4`
   322  */
   323 class X4TypeDescr : public ComplexTypeDescr
   324 {
   325   public:
   326     enum Type {
   327         TYPE_INT32 = JS_X4TYPEREPR_INT32,
   328         TYPE_FLOAT32 = JS_X4TYPEREPR_FLOAT32,
   329     };
   331     static const TypeDescr::Kind Kind = TypeDescr::X4;
   332     static const bool Opaque = false;
   333     static const Class class_;
   334     static int32_t size(Type t);
   335     static int32_t alignment(Type t);
   337     X4TypeDescr::Type type() const {
   338         return (X4TypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
   339     }
   341     static bool call(JSContext *cx, unsigned argc, Value *vp);
   342     static bool is(const Value &v);
   343 };
   345 #define JS_FOR_EACH_X4_TYPE_REPR(macro_)                             \
   346     macro_(X4TypeDescr::TYPE_INT32, int32_t, int32)                  \
   347     macro_(X4TypeDescr::TYPE_FLOAT32, float, float32)
   349 bool IsTypedObjectClass(const Class *clasp); // Defined below
   350 bool IsTypedObjectArray(JSObject& obj);
   352 bool CreateUserSizeAndAlignmentProperties(JSContext *cx, HandleTypeDescr obj);
   354 /*
   355  * Properties and methods of the `ArrayType` meta type object. There
   356  * is no `class_` field because `ArrayType` is just a native
   357  * constructor function.
   358  */
   359 class ArrayMetaTypeDescr : public JSObject
   360 {
   361   private:
   362     friend class UnsizedArrayTypeDescr;
   364     // Helper for creating a new ArrayType object, either sized or unsized.
   365     // The template parameter `T` should be either `UnsizedArrayTypeDescr`
   366     // or `SizedArrayTypeDescr`.
   367     //
   368     // - `arrayTypePrototype` - prototype for the new object to be created,
   369     //                          either ArrayType.prototype or
   370     //                          unsizedArrayType.__proto__ depending on
   371     //                          whether this is a sized or unsized array
   372     // - `elementType` - type object for the elements in the array
   373     // - `stringRepr` - canonical string representation for the array
   374     // - `size` - length of the array (0 if unsized)
   375     template<class T>
   376     static T *create(JSContext *cx,
   377                      HandleObject arrayTypePrototype,
   378                      HandleSizedTypeDescr elementType,
   379                      HandleAtom stringRepr,
   380                      int32_t size);
   382   public:
   383     // Properties and methods to be installed on ArrayType.prototype,
   384     // and hence inherited by all array type objects:
   385     static const JSPropertySpec typeObjectProperties[];
   386     static const JSFunctionSpec typeObjectMethods[];
   388     // Properties and methods to be installed on ArrayType.prototype.prototype,
   389     // and hence inherited by all array *typed* objects:
   390     static const JSPropertySpec typedObjectProperties[];
   391     static const JSFunctionSpec typedObjectMethods[];
   393     // This is the function that gets called when the user
   394     // does `new ArrayType(elem)`. It produces an array type object.
   395     static bool construct(JSContext *cx, unsigned argc, Value *vp);
   396 };
   398 /*
   399  * Type descriptor created by `new ArrayType(typeObj)`
   400  *
   401  * These have a prototype, and hence *could* be a subclass of
   402  * `ComplexTypeDescr`, but it would require some reshuffling of the
   403  * hierarchy, and it's not worth the trouble since they will be going
   404  * away as part of bug 973238.
   405  */
   406 class UnsizedArrayTypeDescr : public TypeDescr
   407 {
   408   public:
   409     static const Class class_;
   410     static const TypeDescr::Kind Kind = TypeDescr::UnsizedArray;
   412     // This is the sized method on unsized array type objects.  It
   413     // produces a sized variant.
   414     static bool dimension(JSContext *cx, unsigned int argc, jsval *vp);
   416     SizedTypeDescr &elementType() {
   417         return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
   418     }
   419 };
   421 /*
   422  * Type descriptor created by `unsizedArrayTypeObj.dimension()`
   423  */
   424 class SizedArrayTypeDescr : public ComplexTypeDescr
   425 {
   426   public:
   427     static const Class class_;
   428     static const TypeDescr::Kind Kind = TypeDescr::SizedArray;
   430     SizedTypeDescr &elementType() {
   431         return getReservedSlot(JS_DESCR_SLOT_ARRAY_ELEM_TYPE).toObject().as<SizedTypeDescr>();
   432     }
   434     int32_t length() {
   435         return getReservedSlot(JS_DESCR_SLOT_SIZED_ARRAY_LENGTH).toInt32();
   436     }
   437 };
   439 /*
   440  * Properties and methods of the `StructType` meta type object. There
   441  * is no `class_` field because `StructType` is just a native
   442  * constructor function.
   443  */
   444 class StructMetaTypeDescr : public JSObject
   445 {
   446   private:
   447     static JSObject *create(JSContext *cx, HandleObject structTypeGlobal,
   448                             HandleObject fields);
   450   public:
   451     // Properties and methods to be installed on StructType.prototype,
   452     // and hence inherited by all struct type objects:
   453     static const JSPropertySpec typeObjectProperties[];
   454     static const JSFunctionSpec typeObjectMethods[];
   456     // Properties and methods to be installed on StructType.prototype.prototype,
   457     // and hence inherited by all struct *typed* objects:
   458     static const JSPropertySpec typedObjectProperties[];
   459     static const JSFunctionSpec typedObjectMethods[];
   461     // This is the function that gets called when the user
   462     // does `new StructType(...)`. It produces a struct type object.
   463     static bool construct(JSContext *cx, unsigned argc, Value *vp);
   464 };
   466 class StructTypeDescr : public ComplexTypeDescr
   467 {
   468   public:
   469     static const Class class_;
   471     // Returns the number of fields defined in this struct.
   472     size_t fieldCount();
   474     // Set `*out` to the index of the field named `id` and returns true,
   475     // or return false if no such field exists.
   476     bool fieldIndex(jsid id, size_t *out);
   478     // Return the name of the field at index `index`.
   479     JSAtom &fieldName(size_t index);
   481     // Return the type descr of the field at index `index`.
   482     SizedTypeDescr &fieldDescr(size_t index);
   484     // Return the offset of the field at index `index`.
   485     int32_t fieldOffset(size_t index);
   486 };
   488 typedef Handle<StructTypeDescr*> HandleStructTypeDescr;
   490 /*
   491  * This object exists in order to encapsulate the typed object types
   492  * somewhat, rather than sticking them all into the global object.
   493  * Eventually it will go away and become a module.
   494  */
   495 class TypedObjectModuleObject : public JSObject {
   496   public:
   497     enum Slot {
   498         ArrayTypePrototype,
   499         StructTypePrototype,
   500         SlotCount
   501     };
   503     static const Class class_;
   504 };
   506 /*
   507  * Base type for typed objects and handles. Basically any type whose
   508  * contents consist of typed memory.
   509  */
   510 class TypedObject : public ArrayBufferViewObject
   511 {
   512   private:
   513     static const bool IsTypedObjectClass = true;
   515     template<class T>
   516     static bool obj_getArrayElement(JSContext *cx,
   517                                     Handle<TypedObject*> typedObj,
   518                                     Handle<TypeDescr*> typeDescr,
   519                                     uint32_t index,
   520                                     MutableHandleValue vp);
   522     template<class T>
   523     static bool obj_setArrayElement(JSContext *cx,
   524                                     Handle<TypedObject*> typedObj,
   525                                     Handle<TypeDescr*> typeDescr,
   526                                     uint32_t index,
   527                                     MutableHandleValue vp);
   529   protected:
   530     static void obj_trace(JSTracer *trace, JSObject *object);
   532     static bool obj_lookupGeneric(JSContext *cx, HandleObject obj,
   533                                   HandleId id, MutableHandleObject objp,
   534                                   MutableHandleShape propp);
   536     static bool obj_lookupProperty(JSContext *cx, HandleObject obj,
   537                                    HandlePropertyName name,
   538                                    MutableHandleObject objp,
   539                                    MutableHandleShape propp);
   541     static bool obj_lookupElement(JSContext *cx, HandleObject obj,
   542                                   uint32_t index, MutableHandleObject objp,
   543                                   MutableHandleShape propp);
   545     static bool obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue v,
   546                                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
   548     static bool obj_defineProperty(JSContext *cx, HandleObject obj,
   549                                    HandlePropertyName name, HandleValue v,
   550                                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
   552     static bool obj_defineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue v,
   553                                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
   555     static bool obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
   556                                HandleId id, MutableHandleValue vp);
   558     static bool obj_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver,
   559                                 HandlePropertyName name, MutableHandleValue vp);
   561     static bool obj_getElement(JSContext *cx, HandleObject obj, HandleObject receiver,
   562                                uint32_t index, MutableHandleValue vp);
   564     static bool obj_getUnsizedArrayElement(JSContext *cx, HandleObject obj, HandleObject receiver,
   565                                          uint32_t index, MutableHandleValue vp);
   567     static bool obj_setGeneric(JSContext *cx, HandleObject obj, HandleId id,
   568                                MutableHandleValue vp, bool strict);
   569     static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
   570                                 MutableHandleValue vp, bool strict);
   571     static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
   572                                MutableHandleValue vp, bool strict);
   574     static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
   575                                          HandleId id, unsigned *attrsp);
   576     static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
   577                                          HandleId id, unsigned *attrsp);
   579     static bool obj_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
   580                                    bool *succeeded);
   581     static bool obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
   582                                   bool *succeeded);
   584     static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
   585                               MutableHandleValue statep, MutableHandleId idp);
   587   public:
   588     static size_t offsetOfOwnerSlot();
   590     // Each typed object contains a void* pointer pointing at the
   591     // binary data that it represents. (That data may be owned by this
   592     // object or this object may alias data owned by someone else.)
   593     // This function returns the offset in bytes within the object
   594     // where the `void*` pointer can be found. It is intended for use
   595     // by the JIT.
   596     static size_t offsetOfDataSlot();
   598     // Offset of the byte offset slot.
   599     static size_t offsetOfByteOffsetSlot();
   601     // Helper for createUnattached()
   602     static TypedObject *createUnattachedWithClass(JSContext *cx,
   603                                                  const Class *clasp,
   604                                                  HandleTypeDescr type,
   605                                                  int32_t length);
   607     // Creates an unattached typed object or handle (depending on the
   608     // type parameter T). Note that it is only legal for unattached
   609     // handles to escape to the end user; for non-handles, the caller
   610     // should always invoke one of the `attach()` methods below.
   611     //
   612     // Arguments:
   613     // - type: type object for resulting object
   614     // - length: 0 unless this is an array, otherwise the length
   615     static TypedObject *createUnattached(JSContext *cx, HandleTypeDescr type,
   616                                         int32_t length);
   618     // Creates a typedObj that aliases the memory pointed at by `owner`
   619     // at the given offset. The typedObj will be a handle iff type is a
   620     // handle and a typed object otherwise.
   621     static TypedObject *createDerived(JSContext *cx,
   622                                       HandleSizedTypeDescr type,
   623                                       Handle<TypedObject*> typedContents,
   624                                       int32_t offset);
   626     // Creates a new typed object whose memory is freshly allocated
   627     // and initialized with zeroes (or, in the case of references, an
   628     // appropriate default value).
   629     static TypedObject *createZeroed(JSContext *cx,
   630                                      HandleTypeDescr typeObj,
   631                                      int32_t length);
   633     // User-accessible constructor (`new TypeDescriptor(...)`)
   634     // used for sized types. Note that the callee here is the *type descriptor*,
   635     // not the typedObj.
   636     static bool constructSized(JSContext *cx, unsigned argc, Value *vp);
   638     // As `constructSized`, but for unsized array types.
   639     static bool constructUnsized(JSContext *cx, unsigned argc, Value *vp);
   641     // Use this method when `buffer` is the owner of the memory.
   642     void attach(ArrayBufferObject &buffer, int32_t offset);
   644     // Otherwise, use this to attach to memory referenced by another typedObj.
   645     void attach(TypedObject &typedObj, int32_t offset);
   647     // Invoked when array buffer is transferred elsewhere
   648     void neuter(void *newData);
   650     int32_t offset() const {
   651         return getReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET).toInt32();
   652     }
   654     ArrayBufferObject &owner() const {
   655         return getReservedSlot(JS_TYPEDOBJ_SLOT_OWNER).toObject().as<ArrayBufferObject>();
   656     }
   658     TypeDescr &typeDescr() const {
   659         return getReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR).toObject().as<TypeDescr>();
   660     }
   662     uint8_t *typedMem() const {
   663         return (uint8_t*) getPrivate();
   664     }
   666     int32_t byteLength() const {
   667         return getReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH).toInt32();
   668     }
   670     int32_t length() const {
   671         return getReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH).toInt32();
   672     }
   674     int32_t size() const {
   675         switch (typeDescr().kind()) {
   676           case TypeDescr::Scalar:
   677           case TypeDescr::X4:
   678           case TypeDescr::Reference:
   679           case TypeDescr::Struct:
   680           case TypeDescr::SizedArray:
   681             return typeDescr().as<SizedTypeDescr>().size();
   683           case TypeDescr::UnsizedArray: {
   684             SizedTypeDescr &elementType = typeDescr().as<UnsizedArrayTypeDescr>().elementType();
   685             return elementType.size() * length();
   686           }
   687         }
   688         MOZ_ASSUME_UNREACHABLE("unhandled typerepresentation kind");
   689     }
   691     uint8_t *typedMem(size_t offset) const {
   692         // It seems a bit surprising that one might request an offset
   693         // == size(), but it can happen when taking the "address of" a
   694         // 0-sized value. (In other words, we maintain the invariant
   695         // that `offset + size <= size()` -- this is always checked in
   696         // the caller's side.)
   697         JS_ASSERT(offset <= (size_t) size());
   698         return typedMem() + offset;
   699     }
   700 };
   702 typedef Handle<TypedObject*> HandleTypedObject;
   704 class TransparentTypedObject : public TypedObject
   705 {
   706   public:
   707     static const Class class_;
   708 };
   710 typedef Handle<TransparentTypedObject*> HandleTransparentTypedObject;
   712 class OpaqueTypedObject : public TypedObject
   713 {
   714   public:
   715     static const Class class_;
   716     static const JSFunctionSpec handleStaticMethods[];
   717 };
   719 /*
   720  * Usage: NewOpaqueTypedObject(typeObj)
   721  *
   722  * Constructs a new, unattached instance of `Handle`.
   723  */
   724 bool NewOpaqueTypedObject(JSContext *cx, unsigned argc, Value *vp);
   726 /*
   727  * Usage: NewDerivedTypedObject(typeObj, owner, offset)
   728  *
   729  * Constructs a new, unattached instance of `Handle`.
   730  */
   731 bool NewDerivedTypedObject(JSContext *cx, unsigned argc, Value *vp);
   733 /*
   734  * Usage: AttachTypedObject(typedObj, newDatum, newOffset)
   735  *
   736  * Moves `typedObj` to point at the memory referenced by `newDatum` with
   737  * the offset `newOffset`.
   738  */
   739 bool AttachTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
   740 extern const JSJitInfo AttachTypedObjectJitInfo;
   742 /*
   743  * Usage: SetTypedObjectOffset(typedObj, offset)
   744  *
   745  * Changes the offset for `typedObj` within its buffer to `offset`.
   746  * `typedObj` must already be attached.
   747  */
   748 bool intrinsic_SetTypedObjectOffset(JSContext *cx, unsigned argc, Value *vp);
   749 bool SetTypedObjectOffset(ThreadSafeContext *, unsigned argc, Value *vp);
   750 extern const JSJitInfo intrinsic_SetTypedObjectOffsetJitInfo;
   752 /*
   753  * Usage: ObjectIsTypeDescr(obj)
   754  *
   755  * True if `obj` is a type object.
   756  */
   757 bool ObjectIsTypeDescr(ThreadSafeContext *cx, unsigned argc, Value *vp);
   758 extern const JSJitInfo ObjectIsTypeDescrJitInfo;
   760 /*
   761  * Usage: ObjectIsTypedObject(obj)
   762  *
   763  * True if `obj` is a transparent or opaque typed object.
   764  */
   765 bool ObjectIsTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
   766 extern const JSJitInfo ObjectIsTypedObjectJitInfo;
   768 /*
   769  * Usage: ObjectIsOpaqueTypedObject(obj)
   770  *
   771  * True if `obj` is an opaque typed object.
   772  */
   773 bool ObjectIsOpaqueTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
   774 extern const JSJitInfo ObjectIsOpaqueTypedObjectJitInfo;
   776 /*
   777  * Usage: ObjectIsTransparentTypedObject(obj)
   778  *
   779  * True if `obj` is a transparent typed object.
   780  */
   781 bool ObjectIsTransparentTypedObject(ThreadSafeContext *cx, unsigned argc, Value *vp);
   782 extern const JSJitInfo ObjectIsTransparentTypedObjectJitInfo;
   784 /* Predicates on type descriptor objects.  In all cases, 'obj' must be a type descriptor. */
   786 bool TypeDescrIsSimpleType(ThreadSafeContext *, unsigned argc, Value *vp);
   787 extern const JSJitInfo TypeDescrIsSimpleTypeJitInfo;
   789 bool TypeDescrIsArrayType(ThreadSafeContext *, unsigned argc, Value *vp);
   790 extern const JSJitInfo TypeDescrIsArrayTypeJitInfo;
   792 bool TypeDescrIsSizedArrayType(ThreadSafeContext *, unsigned argc, Value *vp);
   793 extern const JSJitInfo TypeDescrIsSizedArrayTypeJitInfo;
   795 bool TypeDescrIsUnsizedArrayType(ThreadSafeContext *, unsigned argc, Value *vp);
   796 extern const JSJitInfo TypeDescrIsUnsizedArrayTypeJitInfo;
   798 /*
   799  * Usage: TypedObjectIsAttached(obj)
   800  *
   801  * Given a TypedObject `obj`, returns true if `obj` is
   802  * "attached" (i.e., its data pointer is nullptr).
   803  */
   804 bool TypedObjectIsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp);
   805 extern const JSJitInfo TypedObjectIsAttachedJitInfo;
   807 /*
   808  * Usage: ClampToUint8(v)
   809  *
   810  * Same as the C function ClampDoubleToUint8. `v` must be a number.
   811  */
   812 bool ClampToUint8(ThreadSafeContext *cx, unsigned argc, Value *vp);
   813 extern const JSJitInfo ClampToUint8JitInfo;
   815 /*
   816  * Usage: Memcpy(targetDatum, targetOffset,
   817  *               sourceDatum, sourceOffset,
   818  *               size)
   819  *
   820  * Intrinsic function. Copies size bytes from the data for
   821  * `sourceDatum` at `sourceOffset` into the data for
   822  * `targetDatum` at `targetOffset`.
   823  *
   824  * Both `sourceDatum` and `targetDatum` must be attached.
   825  */
   826 bool Memcpy(ThreadSafeContext *cx, unsigned argc, Value *vp);
   827 extern const JSJitInfo MemcpyJitInfo;
   829 /*
   830  * Usage: GetTypedObjectModule()
   831  *
   832  * Returns the global "typed object" module, which provides access
   833  * to the various builtin type descriptors. These are currently
   834  * exported as immutable properties so it is safe for self-hosted code
   835  * to access them; eventually this should be linked into the module
   836  * system.
   837  */
   838 bool GetTypedObjectModule(JSContext *cx, unsigned argc, Value *vp);
   840 /*
   841  * Usage: GetFloat32x4TypeDescr()
   842  *
   843  * Returns the float32x4 type object. SIMD pseudo-module must have
   844  * been initialized for this to be safe.
   845  */
   846 bool GetFloat32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp);
   848 /*
   849  * Usage: GetInt32x4TypeDescr()
   850  *
   851  * Returns the int32x4 type object. SIMD pseudo-module must have
   852  * been initialized for this to be safe.
   853  */
   854 bool GetInt32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp);
   856 /*
   857  * Usage: Store_int8(targetDatum, targetOffset, value)
   858  *        ...
   859  *        Store_uint8(targetDatum, targetOffset, value)
   860  *        ...
   861  *        Store_float32(targetDatum, targetOffset, value)
   862  *        Store_float64(targetDatum, targetOffset, value)
   863  *
   864  * Intrinsic function. Stores `value` into the memory referenced by
   865  * `targetDatum` at the offset `targetOffset`.
   866  *
   867  * Assumes (and asserts) that:
   868  * - `targetDatum` is attached
   869  * - `targetOffset` is a valid offset within the bounds of `targetDatum`
   870  * - `value` is a number
   871  */
   872 #define JS_STORE_SCALAR_CLASS_DEFN(_constant, T, _name)                       \
   873 class StoreScalar##T {                                                        \
   874   public:                                                                     \
   875     static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp);        \
   876     static const JSJitInfo JitInfo;                                           \
   877 };
   879 /*
   880  * Usage: Store_Any(targetDatum, targetOffset, value)
   881  *        Store_Object(targetDatum, targetOffset, value)
   882  *        Store_string(targetDatum, targetOffset, value)
   883  *
   884  * Intrinsic function. Stores `value` into the memory referenced by
   885  * `targetDatum` at the offset `targetOffset`.
   886  *
   887  * Assumes (and asserts) that:
   888  * - `targetDatum` is attached
   889  * - `targetOffset` is a valid offset within the bounds of `targetDatum`
   890  * - `value` is an object (`Store_Object`) or string (`Store_string`).
   891  */
   892 #define JS_STORE_REFERENCE_CLASS_DEFN(_constant, T, _name)                    \
   893 class StoreReference##T {                                                     \
   894   private:                                                                    \
   895     static void store(T* heap, const Value &v);                               \
   896                                                                               \
   897   public:                                                                     \
   898     static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp);        \
   899     static const JSJitInfo JitInfo;                                           \
   900 };
   902 /*
   903  * Usage: LoadScalar(targetDatum, targetOffset, value)
   904  *
   905  * Intrinsic function. Loads value (which must be an int32 or uint32)
   906  * by `scalarTypeRepr` (which must be a type repr obj) and loads the
   907  * value at the memory for `targetDatum` at offset `targetOffset`.
   908  * `targetDatum` must be attached.
   909  */
   910 #define JS_LOAD_SCALAR_CLASS_DEFN(_constant, T, _name)                        \
   911 class LoadScalar##T {                                                         \
   912   public:                                                                     \
   913     static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp);        \
   914     static const JSJitInfo JitInfo;                                           \
   915 };
   917 /*
   918  * Usage: LoadReference(targetDatum, targetOffset, value)
   919  *
   920  * Intrinsic function. Stores value (which must be an int32 or uint32)
   921  * by `scalarTypeRepr` (which must be a type repr obj) and stores the
   922  * value at the memory for `targetDatum` at offset `targetOffset`.
   923  * `targetDatum` must be attached.
   924  */
   925 #define JS_LOAD_REFERENCE_CLASS_DEFN(_constant, T, _name)                     \
   926 class LoadReference##T {                                                      \
   927   private:                                                                    \
   928     static void load(T* heap, MutableHandleValue v);                          \
   929                                                                               \
   930   public:                                                                     \
   931     static bool Func(ThreadSafeContext *cx, unsigned argc, Value *vp);        \
   932     static const JSJitInfo JitInfo;                                           \
   933 };
   935 // I was using templates for this stuff instead of macros, but ran
   936 // into problems with the Unagi compiler.
   937 JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_STORE_SCALAR_CLASS_DEFN)
   938 JS_FOR_EACH_UNIQUE_SCALAR_TYPE_REPR_CTYPE(JS_LOAD_SCALAR_CLASS_DEFN)
   939 JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_STORE_REFERENCE_CLASS_DEFN)
   940 JS_FOR_EACH_REFERENCE_TYPE_REPR(JS_LOAD_REFERENCE_CLASS_DEFN)
   942 inline bool
   943 IsTypedObjectClass(const Class *class_)
   944 {
   945     return class_ == &TransparentTypedObject::class_ ||
   946            class_ == &OpaqueTypedObject::class_;
   947 }
   949 inline bool
   950 IsSimpleTypeDescrClass(const Class* clasp)
   951 {
   952     return clasp == &ScalarTypeDescr::class_ ||
   953            clasp == &ReferenceTypeDescr::class_;
   954 }
   956 inline bool
   957 IsComplexTypeDescrClass(const Class* clasp)
   958 {
   959     return clasp == &StructTypeDescr::class_ ||
   960            clasp == &SizedArrayTypeDescr::class_ ||
   961            clasp == &X4TypeDescr::class_;
   962 }
   964 inline bool
   965 IsSizedTypeDescrClass(const Class* clasp)
   966 {
   967     return IsSimpleTypeDescrClass(clasp) ||
   968            IsComplexTypeDescrClass(clasp);
   969 }
   971 inline bool
   972 IsTypeDescrClass(const Class* clasp)
   973 {
   974     return IsSizedTypeDescrClass(clasp) ||
   975            clasp == &UnsizedArrayTypeDescr::class_;
   976 }
   978 } // namespace js
   980 JSObject *
   981 js_InitTypedObjectModuleObject(JSContext *cx, JS::HandleObject obj);
   983 template <>
   984 inline bool
   985 JSObject::is<js::SimpleTypeDescr>() const
   986 {
   987     return IsSimpleTypeDescrClass(getClass());
   988 }
   990 template <>
   991 inline bool
   992 JSObject::is<js::SizedTypeDescr>() const
   993 {
   994     return IsSizedTypeDescrClass(getClass());
   995 }
   997 template <>
   998 inline bool
   999 JSObject::is<js::ComplexTypeDescr>() const
  1001     return IsComplexTypeDescrClass(getClass());
  1004 template <>
  1005 inline bool
  1006 JSObject::is<js::TypeDescr>() const
  1008     return IsTypeDescrClass(getClass());
  1011 template <>
  1012 inline bool
  1013 JSObject::is<js::TypedObject>() const
  1015     return IsTypedObjectClass(getClass());
  1018 template<>
  1019 inline bool
  1020 JSObject::is<js::SizedArrayTypeDescr>() const
  1022     return getClass() == &js::SizedArrayTypeDescr::class_;
  1025 template<>
  1026 inline bool
  1027 JSObject::is<js::UnsizedArrayTypeDescr>() const
  1029     return getClass() == &js::UnsizedArrayTypeDescr::class_;
  1032 inline void
  1033 js::TypedProto::initTypeDescrSlot(TypeDescr &descr)
  1035     initReservedSlot(JS_TYPROTO_SLOT_DESCR, ObjectValue(descr));
  1038 #endif /* builtin_TypedObject_h */

mercurial