Wed, 31 Dec 2014 06:09:35 +0100
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
1000 {
1001 return IsComplexTypeDescrClass(getClass());
1002 }
1004 template <>
1005 inline bool
1006 JSObject::is<js::TypeDescr>() const
1007 {
1008 return IsTypeDescrClass(getClass());
1009 }
1011 template <>
1012 inline bool
1013 JSObject::is<js::TypedObject>() const
1014 {
1015 return IsTypedObjectClass(getClass());
1016 }
1018 template<>
1019 inline bool
1020 JSObject::is<js::SizedArrayTypeDescr>() const
1021 {
1022 return getClass() == &js::SizedArrayTypeDescr::class_;
1023 }
1025 template<>
1026 inline bool
1027 JSObject::is<js::UnsizedArrayTypeDescr>() const
1028 {
1029 return getClass() == &js::UnsizedArrayTypeDescr::class_;
1030 }
1032 inline void
1033 js::TypedProto::initTypeDescrSlot(TypeDescr &descr)
1034 {
1035 initReservedSlot(JS_TYPROTO_SLOT_DESCR, ObjectValue(descr));
1036 }
1038 #endif /* builtin_TypedObject_h */