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