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.
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 | /* Definitions related to javascript type inference. */ |
michael@0 | 8 | |
michael@0 | 9 | #ifndef jsinfer_h |
michael@0 | 10 | #define jsinfer_h |
michael@0 | 11 | |
michael@0 | 12 | #include "mozilla/MemoryReporting.h" |
michael@0 | 13 | #include "mozilla/TypedEnum.h" |
michael@0 | 14 | |
michael@0 | 15 | #include "jsalloc.h" |
michael@0 | 16 | #include "jsfriendapi.h" |
michael@0 | 17 | #include "jstypes.h" |
michael@0 | 18 | |
michael@0 | 19 | #include "ds/IdValuePair.h" |
michael@0 | 20 | #include "ds/LifoAlloc.h" |
michael@0 | 21 | #include "gc/Barrier.h" |
michael@0 | 22 | #include "gc/Marking.h" |
michael@0 | 23 | #include "jit/IonTypes.h" |
michael@0 | 24 | #include "js/Utility.h" |
michael@0 | 25 | #include "js/Vector.h" |
michael@0 | 26 | |
michael@0 | 27 | namespace js { |
michael@0 | 28 | |
michael@0 | 29 | class TypeDescr; |
michael@0 | 30 | |
michael@0 | 31 | class TaggedProto |
michael@0 | 32 | { |
michael@0 | 33 | public: |
michael@0 | 34 | static JSObject * const LazyProto; |
michael@0 | 35 | |
michael@0 | 36 | TaggedProto() : proto(nullptr) {} |
michael@0 | 37 | TaggedProto(JSObject *proto) : proto(proto) {} |
michael@0 | 38 | |
michael@0 | 39 | uintptr_t toWord() const { return uintptr_t(proto); } |
michael@0 | 40 | |
michael@0 | 41 | bool isLazy() const { |
michael@0 | 42 | return proto == LazyProto; |
michael@0 | 43 | } |
michael@0 | 44 | bool isObject() const { |
michael@0 | 45 | /* Skip nullptr and LazyProto. */ |
michael@0 | 46 | return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto); |
michael@0 | 47 | } |
michael@0 | 48 | JSObject *toObject() const { |
michael@0 | 49 | JS_ASSERT(isObject()); |
michael@0 | 50 | return proto; |
michael@0 | 51 | } |
michael@0 | 52 | JSObject *toObjectOrNull() const { |
michael@0 | 53 | JS_ASSERT(!proto || isObject()); |
michael@0 | 54 | return proto; |
michael@0 | 55 | } |
michael@0 | 56 | JSObject *raw() const { return proto; } |
michael@0 | 57 | |
michael@0 | 58 | bool operator ==(const TaggedProto &other) { return proto == other.proto; } |
michael@0 | 59 | bool operator !=(const TaggedProto &other) { return proto != other.proto; } |
michael@0 | 60 | |
michael@0 | 61 | private: |
michael@0 | 62 | JSObject *proto; |
michael@0 | 63 | }; |
michael@0 | 64 | |
michael@0 | 65 | template <> |
michael@0 | 66 | struct RootKind<TaggedProto> |
michael@0 | 67 | { |
michael@0 | 68 | static ThingRootKind rootKind() { return THING_ROOT_OBJECT; } |
michael@0 | 69 | }; |
michael@0 | 70 | |
michael@0 | 71 | template <> struct GCMethods<const TaggedProto> |
michael@0 | 72 | { |
michael@0 | 73 | static TaggedProto initial() { return TaggedProto(); } |
michael@0 | 74 | static ThingRootKind kind() { return THING_ROOT_OBJECT; } |
michael@0 | 75 | static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } |
michael@0 | 76 | }; |
michael@0 | 77 | |
michael@0 | 78 | template <> struct GCMethods<TaggedProto> |
michael@0 | 79 | { |
michael@0 | 80 | static TaggedProto initial() { return TaggedProto(); } |
michael@0 | 81 | static ThingRootKind kind() { return THING_ROOT_OBJECT; } |
michael@0 | 82 | static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } |
michael@0 | 83 | }; |
michael@0 | 84 | |
michael@0 | 85 | template<class Outer> |
michael@0 | 86 | class TaggedProtoOperations |
michael@0 | 87 | { |
michael@0 | 88 | const TaggedProto *value() const { |
michael@0 | 89 | return static_cast<const Outer*>(this)->extract(); |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | public: |
michael@0 | 93 | uintptr_t toWord() const { return value()->toWord(); } |
michael@0 | 94 | inline bool isLazy() const { return value()->isLazy(); } |
michael@0 | 95 | inline bool isObject() const { return value()->isObject(); } |
michael@0 | 96 | inline JSObject *toObject() const { return value()->toObject(); } |
michael@0 | 97 | inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } |
michael@0 | 98 | JSObject *raw() const { return value()->raw(); } |
michael@0 | 99 | }; |
michael@0 | 100 | |
michael@0 | 101 | template <> |
michael@0 | 102 | class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto> > |
michael@0 | 103 | { |
michael@0 | 104 | friend class TaggedProtoOperations<Handle<TaggedProto> >; |
michael@0 | 105 | const TaggedProto * extract() const { |
michael@0 | 106 | return static_cast<const Handle<TaggedProto>*>(this)->address(); |
michael@0 | 107 | } |
michael@0 | 108 | }; |
michael@0 | 109 | |
michael@0 | 110 | template <> |
michael@0 | 111 | class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto> > |
michael@0 | 112 | { |
michael@0 | 113 | friend class TaggedProtoOperations<Rooted<TaggedProto> >; |
michael@0 | 114 | const TaggedProto *extract() const { |
michael@0 | 115 | return static_cast<const Rooted<TaggedProto> *>(this)->address(); |
michael@0 | 116 | } |
michael@0 | 117 | }; |
michael@0 | 118 | |
michael@0 | 119 | class CallObject; |
michael@0 | 120 | |
michael@0 | 121 | /* |
michael@0 | 122 | * Execution Mode Overview |
michael@0 | 123 | * |
michael@0 | 124 | * JavaScript code can execute either sequentially or in parallel, such as in |
michael@0 | 125 | * PJS. Functions which behave identically in either execution mode can take a |
michael@0 | 126 | * ThreadSafeContext, and functions which have similar but not identical |
michael@0 | 127 | * behavior between execution modes can be templated on the mode. Such |
michael@0 | 128 | * functions use a context parameter type from ExecutionModeTraits below |
michael@0 | 129 | * indicating whether they are only permitted constrained operations (such as |
michael@0 | 130 | * thread safety, and side effects limited to being thread-local), or whether |
michael@0 | 131 | * they can have arbitrary side effects. |
michael@0 | 132 | */ |
michael@0 | 133 | |
michael@0 | 134 | enum ExecutionMode { |
michael@0 | 135 | /* Normal JavaScript execution. */ |
michael@0 | 136 | SequentialExecution, |
michael@0 | 137 | |
michael@0 | 138 | /* |
michael@0 | 139 | * JavaScript code to be executed in parallel worker threads in PJS in a |
michael@0 | 140 | * fork join fashion. |
michael@0 | 141 | */ |
michael@0 | 142 | ParallelExecution, |
michael@0 | 143 | |
michael@0 | 144 | /* |
michael@0 | 145 | * Modes after this point are internal and are not counted in |
michael@0 | 146 | * NumExecutionModes below. |
michael@0 | 147 | */ |
michael@0 | 148 | |
michael@0 | 149 | /* |
michael@0 | 150 | * MIR analysis performed when invoking 'new' on a script, to determine |
michael@0 | 151 | * definite properties. Used by the optimizing JIT. |
michael@0 | 152 | */ |
michael@0 | 153 | DefinitePropertiesAnalysis, |
michael@0 | 154 | |
michael@0 | 155 | /* |
michael@0 | 156 | * MIR analysis performed when executing a script which uses its arguments, |
michael@0 | 157 | * when it is not known whether a lazy arguments value can be used. |
michael@0 | 158 | */ |
michael@0 | 159 | ArgumentsUsageAnalysis |
michael@0 | 160 | }; |
michael@0 | 161 | |
michael@0 | 162 | /* |
michael@0 | 163 | * Not as part of the enum so we don't get warnings about unhandled enum |
michael@0 | 164 | * values. |
michael@0 | 165 | */ |
michael@0 | 166 | static const unsigned NumExecutionModes = ParallelExecution + 1; |
michael@0 | 167 | |
michael@0 | 168 | template <ExecutionMode mode> |
michael@0 | 169 | struct ExecutionModeTraits |
michael@0 | 170 | { |
michael@0 | 171 | }; |
michael@0 | 172 | |
michael@0 | 173 | template <> struct ExecutionModeTraits<SequentialExecution> |
michael@0 | 174 | { |
michael@0 | 175 | typedef JSContext * ContextType; |
michael@0 | 176 | typedef ExclusiveContext * ExclusiveContextType; |
michael@0 | 177 | |
michael@0 | 178 | static inline JSContext *toContextType(ExclusiveContext *cx); |
michael@0 | 179 | }; |
michael@0 | 180 | |
michael@0 | 181 | template <> struct ExecutionModeTraits<ParallelExecution> |
michael@0 | 182 | { |
michael@0 | 183 | typedef ForkJoinContext * ContextType; |
michael@0 | 184 | typedef ForkJoinContext * ExclusiveContextType; |
michael@0 | 185 | |
michael@0 | 186 | static inline ForkJoinContext *toContextType(ForkJoinContext *cx) { return cx; } |
michael@0 | 187 | }; |
michael@0 | 188 | |
michael@0 | 189 | namespace jit { |
michael@0 | 190 | struct IonScript; |
michael@0 | 191 | class IonAllocPolicy; |
michael@0 | 192 | class TempAllocator; |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | namespace types { |
michael@0 | 196 | |
michael@0 | 197 | class TypeZone; |
michael@0 | 198 | class TypeSet; |
michael@0 | 199 | class TypeObjectKey; |
michael@0 | 200 | |
michael@0 | 201 | /* |
michael@0 | 202 | * Information about a single concrete type. We pack this into a single word, |
michael@0 | 203 | * where small values are particular primitive or other singleton types, and |
michael@0 | 204 | * larger values are either specific JS objects or type objects. |
michael@0 | 205 | */ |
michael@0 | 206 | class Type |
michael@0 | 207 | { |
michael@0 | 208 | uintptr_t data; |
michael@0 | 209 | Type(uintptr_t data) : data(data) {} |
michael@0 | 210 | |
michael@0 | 211 | public: |
michael@0 | 212 | |
michael@0 | 213 | uintptr_t raw() const { return data; } |
michael@0 | 214 | |
michael@0 | 215 | bool isPrimitive() const { |
michael@0 | 216 | return data < JSVAL_TYPE_OBJECT; |
michael@0 | 217 | } |
michael@0 | 218 | |
michael@0 | 219 | bool isPrimitive(JSValueType type) const { |
michael@0 | 220 | JS_ASSERT(type < JSVAL_TYPE_OBJECT); |
michael@0 | 221 | return (uintptr_t) type == data; |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | JSValueType primitive() const { |
michael@0 | 225 | JS_ASSERT(isPrimitive()); |
michael@0 | 226 | return (JSValueType) data; |
michael@0 | 227 | } |
michael@0 | 228 | |
michael@0 | 229 | bool isMagicArguments() const { |
michael@0 | 230 | return primitive() == JSVAL_TYPE_MAGIC; |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | bool isSomeObject() const { |
michael@0 | 234 | return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN; |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | bool isAnyObject() const { |
michael@0 | 238 | return data == JSVAL_TYPE_OBJECT; |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | bool isUnknown() const { |
michael@0 | 242 | return data == JSVAL_TYPE_UNKNOWN; |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | /* Accessors for types that are either JSObject or TypeObject. */ |
michael@0 | 246 | |
michael@0 | 247 | bool isObject() const { |
michael@0 | 248 | JS_ASSERT(!isAnyObject() && !isUnknown()); |
michael@0 | 249 | return data > JSVAL_TYPE_UNKNOWN; |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | bool isObjectUnchecked() const { |
michael@0 | 253 | return data > JSVAL_TYPE_UNKNOWN; |
michael@0 | 254 | } |
michael@0 | 255 | |
michael@0 | 256 | inline TypeObjectKey *objectKey() const; |
michael@0 | 257 | |
michael@0 | 258 | /* Accessors for JSObject types */ |
michael@0 | 259 | |
michael@0 | 260 | bool isSingleObject() const { |
michael@0 | 261 | return isObject() && !!(data & 1); |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | inline JSObject *singleObject() const; |
michael@0 | 265 | |
michael@0 | 266 | /* Accessors for TypeObject types */ |
michael@0 | 267 | |
michael@0 | 268 | bool isTypeObject() const { |
michael@0 | 269 | return isObject() && !(data & 1); |
michael@0 | 270 | } |
michael@0 | 271 | |
michael@0 | 272 | inline TypeObject *typeObject() const; |
michael@0 | 273 | |
michael@0 | 274 | bool operator == (Type o) const { return data == o.data; } |
michael@0 | 275 | bool operator != (Type o) const { return data != o.data; } |
michael@0 | 276 | |
michael@0 | 277 | static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); } |
michael@0 | 278 | static inline Type NullType() { return Type(JSVAL_TYPE_NULL); } |
michael@0 | 279 | static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); } |
michael@0 | 280 | static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); } |
michael@0 | 281 | static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); } |
michael@0 | 282 | static inline Type StringType() { return Type(JSVAL_TYPE_STRING); } |
michael@0 | 283 | static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); } |
michael@0 | 284 | static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); } |
michael@0 | 285 | static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); } |
michael@0 | 286 | |
michael@0 | 287 | static inline Type PrimitiveType(JSValueType type) { |
michael@0 | 288 | JS_ASSERT(type < JSVAL_TYPE_UNKNOWN); |
michael@0 | 289 | return Type(type); |
michael@0 | 290 | } |
michael@0 | 291 | |
michael@0 | 292 | static inline Type ObjectType(JSObject *obj); |
michael@0 | 293 | static inline Type ObjectType(TypeObject *obj); |
michael@0 | 294 | static inline Type ObjectType(TypeObjectKey *obj); |
michael@0 | 295 | }; |
michael@0 | 296 | |
michael@0 | 297 | /* Get the type of a jsval, or zero for an unknown special value. */ |
michael@0 | 298 | inline Type GetValueType(const Value &val); |
michael@0 | 299 | |
michael@0 | 300 | /* |
michael@0 | 301 | * Get the type of a possibly optimized out value. This generally only |
michael@0 | 302 | * happens on unconditional type monitors on bailing out of Ion, such as |
michael@0 | 303 | * for argument and local types. |
michael@0 | 304 | */ |
michael@0 | 305 | inline Type GetMaybeOptimizedOutValueType(const Value &val); |
michael@0 | 306 | |
michael@0 | 307 | /* |
michael@0 | 308 | * Type inference memory management overview. |
michael@0 | 309 | * |
michael@0 | 310 | * Type information about the values observed within scripts and about the |
michael@0 | 311 | * contents of the heap is accumulated as the program executes. Compilation |
michael@0 | 312 | * accumulates constraints relating type information on the heap with the |
michael@0 | 313 | * compilations that should be invalidated when those types change. Type |
michael@0 | 314 | * information and constraints are allocated in the zone's typeLifoAlloc, |
michael@0 | 315 | * and on GC all data referring to live things is copied into a new allocator. |
michael@0 | 316 | * Thus, type set and constraints only hold weak references. |
michael@0 | 317 | */ |
michael@0 | 318 | |
michael@0 | 319 | /* |
michael@0 | 320 | * A constraint which listens to additions to a type set and propagates those |
michael@0 | 321 | * changes to other type sets. |
michael@0 | 322 | */ |
michael@0 | 323 | class TypeConstraint |
michael@0 | 324 | { |
michael@0 | 325 | public: |
michael@0 | 326 | /* Next constraint listening to the same type set. */ |
michael@0 | 327 | TypeConstraint *next; |
michael@0 | 328 | |
michael@0 | 329 | TypeConstraint() |
michael@0 | 330 | : next(nullptr) |
michael@0 | 331 | {} |
michael@0 | 332 | |
michael@0 | 333 | /* Debugging name for this kind of constraint. */ |
michael@0 | 334 | virtual const char *kind() = 0; |
michael@0 | 335 | |
michael@0 | 336 | /* Register a new type for the set this constraint is listening to. */ |
michael@0 | 337 | virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0; |
michael@0 | 338 | |
michael@0 | 339 | /* |
michael@0 | 340 | * For constraints attached to an object property's type set, mark the |
michael@0 | 341 | * property as having its configuration changed. |
michael@0 | 342 | */ |
michael@0 | 343 | virtual void newPropertyState(JSContext *cx, TypeSet *source) {} |
michael@0 | 344 | |
michael@0 | 345 | /* |
michael@0 | 346 | * For constraints attached to the JSID_EMPTY type set on an object, |
michael@0 | 347 | * indicate a change in one of the object's dynamic property flags or other |
michael@0 | 348 | * state. |
michael@0 | 349 | */ |
michael@0 | 350 | virtual void newObjectState(JSContext *cx, TypeObject *object) {} |
michael@0 | 351 | |
michael@0 | 352 | /* |
michael@0 | 353 | * If the data this constraint refers to is still live, copy it into the |
michael@0 | 354 | * zone's new allocator. Type constraints only hold weak references. |
michael@0 | 355 | */ |
michael@0 | 356 | virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0; |
michael@0 | 357 | }; |
michael@0 | 358 | |
michael@0 | 359 | /* Flags and other state stored in TypeSet::flags */ |
michael@0 | 360 | enum MOZ_ENUM_TYPE(uint32_t) { |
michael@0 | 361 | TYPE_FLAG_UNDEFINED = 0x1, |
michael@0 | 362 | TYPE_FLAG_NULL = 0x2, |
michael@0 | 363 | TYPE_FLAG_BOOLEAN = 0x4, |
michael@0 | 364 | TYPE_FLAG_INT32 = 0x8, |
michael@0 | 365 | TYPE_FLAG_DOUBLE = 0x10, |
michael@0 | 366 | TYPE_FLAG_STRING = 0x20, |
michael@0 | 367 | TYPE_FLAG_LAZYARGS = 0x40, |
michael@0 | 368 | TYPE_FLAG_ANYOBJECT = 0x80, |
michael@0 | 369 | |
michael@0 | 370 | /* Mask containing all primitives */ |
michael@0 | 371 | TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN | |
michael@0 | 372 | TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING, |
michael@0 | 373 | |
michael@0 | 374 | /* Mask/shift for the number of objects in objectSet */ |
michael@0 | 375 | TYPE_FLAG_OBJECT_COUNT_MASK = 0x1f00, |
michael@0 | 376 | TYPE_FLAG_OBJECT_COUNT_SHIFT = 8, |
michael@0 | 377 | TYPE_FLAG_OBJECT_COUNT_LIMIT = |
michael@0 | 378 | TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT, |
michael@0 | 379 | |
michael@0 | 380 | /* Whether the contents of this type set are totally unknown. */ |
michael@0 | 381 | TYPE_FLAG_UNKNOWN = 0x00002000, |
michael@0 | 382 | |
michael@0 | 383 | /* Mask of normal type flags on a type set. */ |
michael@0 | 384 | TYPE_FLAG_BASE_MASK = 0x000020ff, |
michael@0 | 385 | |
michael@0 | 386 | /* Additional flags for HeapTypeSet sets. */ |
michael@0 | 387 | |
michael@0 | 388 | /* |
michael@0 | 389 | * Whether the property has ever been deleted or reconfigured to behave |
michael@0 | 390 | * differently from a plain data property, other than making the property |
michael@0 | 391 | * non-writable. |
michael@0 | 392 | */ |
michael@0 | 393 | TYPE_FLAG_NON_DATA_PROPERTY = 0x00004000, |
michael@0 | 394 | |
michael@0 | 395 | /* Whether the property has ever been made non-writable. */ |
michael@0 | 396 | TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00008000, |
michael@0 | 397 | |
michael@0 | 398 | /* |
michael@0 | 399 | * Whether the property is definitely in a particular slot on all objects |
michael@0 | 400 | * from which it has not been deleted or reconfigured. For singletons |
michael@0 | 401 | * this may be a fixed or dynamic slot, and for other objects this will be |
michael@0 | 402 | * a fixed slot. |
michael@0 | 403 | * |
michael@0 | 404 | * If the property is definite, mask and shift storing the slot + 1. |
michael@0 | 405 | * Otherwise these bits are clear. |
michael@0 | 406 | */ |
michael@0 | 407 | TYPE_FLAG_DEFINITE_MASK = 0xffff0000, |
michael@0 | 408 | TYPE_FLAG_DEFINITE_SHIFT = 16 |
michael@0 | 409 | }; |
michael@0 | 410 | typedef uint32_t TypeFlags; |
michael@0 | 411 | |
michael@0 | 412 | /* Flags and other state stored in TypeObject::flags */ |
michael@0 | 413 | enum MOZ_ENUM_TYPE(uint32_t) { |
michael@0 | 414 | /* Whether this type object is associated with some allocation site. */ |
michael@0 | 415 | OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1, |
michael@0 | 416 | |
michael@0 | 417 | /* If set, addendum information should not be installed on this object. */ |
michael@0 | 418 | OBJECT_FLAG_ADDENDUM_CLEARED = 0x2, |
michael@0 | 419 | |
michael@0 | 420 | /* |
michael@0 | 421 | * If set, the object's prototype might be in the nursery and can't be |
michael@0 | 422 | * used during Ion compilation (which may be occurring off thread). |
michael@0 | 423 | */ |
michael@0 | 424 | OBJECT_FLAG_NURSERY_PROTO = 0x4, |
michael@0 | 425 | |
michael@0 | 426 | /* |
michael@0 | 427 | * Whether we have ensured all type sets in the compartment contain |
michael@0 | 428 | * ANYOBJECT instead of this object. |
michael@0 | 429 | */ |
michael@0 | 430 | OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x8, |
michael@0 | 431 | |
michael@0 | 432 | /* Mask/shift for the number of properties in propertySet */ |
michael@0 | 433 | OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff0, |
michael@0 | 434 | OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 4, |
michael@0 | 435 | OBJECT_FLAG_PROPERTY_COUNT_LIMIT = |
michael@0 | 436 | OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT, |
michael@0 | 437 | |
michael@0 | 438 | /* Whether any objects this represents may have sparse indexes. */ |
michael@0 | 439 | OBJECT_FLAG_SPARSE_INDEXES = 0x00010000, |
michael@0 | 440 | |
michael@0 | 441 | /* Whether any objects this represents may not have packed dense elements. */ |
michael@0 | 442 | OBJECT_FLAG_NON_PACKED = 0x00020000, |
michael@0 | 443 | |
michael@0 | 444 | /* |
michael@0 | 445 | * Whether any objects this represents may be arrays whose length does not |
michael@0 | 446 | * fit in an int32. |
michael@0 | 447 | */ |
michael@0 | 448 | OBJECT_FLAG_LENGTH_OVERFLOW = 0x00040000, |
michael@0 | 449 | |
michael@0 | 450 | /* Whether any objects have been iterated over. */ |
michael@0 | 451 | OBJECT_FLAG_ITERATED = 0x00080000, |
michael@0 | 452 | |
michael@0 | 453 | /* For a global object, whether flags were set on the RegExpStatics. */ |
michael@0 | 454 | OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00100000, |
michael@0 | 455 | |
michael@0 | 456 | /* |
michael@0 | 457 | * For the function on a run-once script, whether the function has actually |
michael@0 | 458 | * run multiple times. |
michael@0 | 459 | */ |
michael@0 | 460 | OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000, |
michael@0 | 461 | |
michael@0 | 462 | /* |
michael@0 | 463 | * Whether objects with this type should be allocated directly in the |
michael@0 | 464 | * tenured heap. |
michael@0 | 465 | */ |
michael@0 | 466 | OBJECT_FLAG_PRE_TENURE = 0x00400000, |
michael@0 | 467 | |
michael@0 | 468 | /* |
michael@0 | 469 | * Whether all properties of this object are considered unknown. |
michael@0 | 470 | * If set, all other flags in DYNAMIC_MASK will also be set. |
michael@0 | 471 | */ |
michael@0 | 472 | OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x00800000, |
michael@0 | 473 | |
michael@0 | 474 | /* Flags which indicate dynamic properties of represented objects. */ |
michael@0 | 475 | OBJECT_FLAG_DYNAMIC_MASK = 0x00ff0000, |
michael@0 | 476 | |
michael@0 | 477 | /* Mask for objects created with unknown properties. */ |
michael@0 | 478 | OBJECT_FLAG_UNKNOWN_MASK = |
michael@0 | 479 | OBJECT_FLAG_DYNAMIC_MASK |
michael@0 | 480 | | OBJECT_FLAG_SETS_MARKED_UNKNOWN |
michael@0 | 481 | }; |
michael@0 | 482 | typedef uint32_t TypeObjectFlags; |
michael@0 | 483 | |
michael@0 | 484 | class StackTypeSet; |
michael@0 | 485 | class HeapTypeSet; |
michael@0 | 486 | class TemporaryTypeSet; |
michael@0 | 487 | |
michael@0 | 488 | /* |
michael@0 | 489 | * Information about the set of types associated with an lvalue. There are |
michael@0 | 490 | * three kinds of type sets: |
michael@0 | 491 | * |
michael@0 | 492 | * - StackTypeSet are associated with TypeScripts, for arguments and values |
michael@0 | 493 | * observed at property reads. These are implicitly frozen on compilation |
michael@0 | 494 | * and do not have constraints attached to them. |
michael@0 | 495 | * |
michael@0 | 496 | * - HeapTypeSet are associated with the properties of TypeObjects. These |
michael@0 | 497 | * may have constraints added to them to trigger invalidation of compiled |
michael@0 | 498 | * code. |
michael@0 | 499 | * |
michael@0 | 500 | * - TemporaryTypeSet are created during compilation and do not outlive |
michael@0 | 501 | * that compilation. |
michael@0 | 502 | */ |
michael@0 | 503 | class TypeSet |
michael@0 | 504 | { |
michael@0 | 505 | protected: |
michael@0 | 506 | /* Flags for this type set. */ |
michael@0 | 507 | TypeFlags flags; |
michael@0 | 508 | |
michael@0 | 509 | /* Possible objects this type set can represent. */ |
michael@0 | 510 | TypeObjectKey **objectSet; |
michael@0 | 511 | |
michael@0 | 512 | public: |
michael@0 | 513 | |
michael@0 | 514 | TypeSet() |
michael@0 | 515 | : flags(0), objectSet(nullptr) |
michael@0 | 516 | {} |
michael@0 | 517 | |
michael@0 | 518 | void print(); |
michael@0 | 519 | |
michael@0 | 520 | /* Whether this set contains a specific type. */ |
michael@0 | 521 | inline bool hasType(Type type) const; |
michael@0 | 522 | |
michael@0 | 523 | TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; } |
michael@0 | 524 | bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); } |
michael@0 | 525 | bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); } |
michael@0 | 526 | bool empty() const { return !baseFlags() && !baseObjectCount(); } |
michael@0 | 527 | |
michael@0 | 528 | bool hasAnyFlag(TypeFlags flags) const { |
michael@0 | 529 | JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags); |
michael@0 | 530 | return !!(baseFlags() & flags); |
michael@0 | 531 | } |
michael@0 | 532 | |
michael@0 | 533 | bool nonDataProperty() const { |
michael@0 | 534 | return flags & TYPE_FLAG_NON_DATA_PROPERTY; |
michael@0 | 535 | } |
michael@0 | 536 | bool nonWritableProperty() const { |
michael@0 | 537 | return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY; |
michael@0 | 538 | } |
michael@0 | 539 | bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; } |
michael@0 | 540 | unsigned definiteSlot() const { |
michael@0 | 541 | JS_ASSERT(definiteProperty()); |
michael@0 | 542 | return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1; |
michael@0 | 543 | } |
michael@0 | 544 | |
michael@0 | 545 | /* Join two type sets into a new set. The result should not be modified further. */ |
michael@0 | 546 | static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc); |
michael@0 | 547 | |
michael@0 | 548 | /* Add a type to this set using the specified allocator. */ |
michael@0 | 549 | void addType(Type type, LifoAlloc *alloc); |
michael@0 | 550 | |
michael@0 | 551 | /* Get a list of all types in this set. */ |
michael@0 | 552 | typedef Vector<Type, 1, SystemAllocPolicy> TypeList; |
michael@0 | 553 | bool enumerateTypes(TypeList *list); |
michael@0 | 554 | |
michael@0 | 555 | /* |
michael@0 | 556 | * Iterate through the objects in this set. getObjectCount overapproximates |
michael@0 | 557 | * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject |
michael@0 | 558 | * may return nullptr. |
michael@0 | 559 | */ |
michael@0 | 560 | inline unsigned getObjectCount() const; |
michael@0 | 561 | inline TypeObjectKey *getObject(unsigned i) const; |
michael@0 | 562 | inline JSObject *getSingleObject(unsigned i) const; |
michael@0 | 563 | inline TypeObject *getTypeObject(unsigned i) const; |
michael@0 | 564 | |
michael@0 | 565 | /* The Class of an object in this set. */ |
michael@0 | 566 | inline const Class *getObjectClass(unsigned i) const; |
michael@0 | 567 | |
michael@0 | 568 | bool canSetDefinite(unsigned slot) { |
michael@0 | 569 | // Note: the cast is required to work around an MSVC issue. |
michael@0 | 570 | return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT); |
michael@0 | 571 | } |
michael@0 | 572 | void setDefinite(unsigned slot) { |
michael@0 | 573 | JS_ASSERT(canSetDefinite(slot)); |
michael@0 | 574 | flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT); |
michael@0 | 575 | JS_ASSERT(definiteSlot() == slot); |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | /* Whether any values in this set might have the specified type. */ |
michael@0 | 579 | bool mightBeMIRType(jit::MIRType type); |
michael@0 | 580 | |
michael@0 | 581 | /* |
michael@0 | 582 | * Get whether this type set is known to be a subset of other. |
michael@0 | 583 | * This variant doesn't freeze constraints. That variant is called knownSubset |
michael@0 | 584 | */ |
michael@0 | 585 | bool isSubset(TypeSet *other); |
michael@0 | 586 | |
michael@0 | 587 | /* Forward all types in this set to the specified constraint. */ |
michael@0 | 588 | bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint); |
michael@0 | 589 | |
michael@0 | 590 | // Clone a type set into an arbitrary allocator. |
michael@0 | 591 | TemporaryTypeSet *clone(LifoAlloc *alloc) const; |
michael@0 | 592 | bool clone(LifoAlloc *alloc, TemporaryTypeSet *result) const; |
michael@0 | 593 | |
michael@0 | 594 | // Create a new TemporaryTypeSet where undefined and/or null has been filtered out. |
michael@0 | 595 | TemporaryTypeSet *filter(LifoAlloc *alloc, bool filterUndefined, bool filterNull) const; |
michael@0 | 596 | |
michael@0 | 597 | protected: |
michael@0 | 598 | uint32_t baseObjectCount() const { |
michael@0 | 599 | return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT; |
michael@0 | 600 | } |
michael@0 | 601 | inline void setBaseObjectCount(uint32_t count); |
michael@0 | 602 | |
michael@0 | 603 | void clearObjects(); |
michael@0 | 604 | }; |
michael@0 | 605 | |
michael@0 | 606 | /* Superclass common to stack and heap type sets. */ |
michael@0 | 607 | class ConstraintTypeSet : public TypeSet |
michael@0 | 608 | { |
michael@0 | 609 | public: |
michael@0 | 610 | /* Chain of constraints which propagate changes out from this type set. */ |
michael@0 | 611 | TypeConstraint *constraintList; |
michael@0 | 612 | |
michael@0 | 613 | ConstraintTypeSet() : constraintList(nullptr) {} |
michael@0 | 614 | |
michael@0 | 615 | /* |
michael@0 | 616 | * Add a type to this set, calling any constraint handlers if this is a new |
michael@0 | 617 | * possible type. |
michael@0 | 618 | */ |
michael@0 | 619 | void addType(ExclusiveContext *cx, Type type); |
michael@0 | 620 | |
michael@0 | 621 | /* Add a new constraint to this set. */ |
michael@0 | 622 | bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true); |
michael@0 | 623 | |
michael@0 | 624 | inline void sweep(JS::Zone *zone, bool *oom); |
michael@0 | 625 | }; |
michael@0 | 626 | |
michael@0 | 627 | class StackTypeSet : public ConstraintTypeSet |
michael@0 | 628 | { |
michael@0 | 629 | public: |
michael@0 | 630 | }; |
michael@0 | 631 | |
michael@0 | 632 | class HeapTypeSet : public ConstraintTypeSet |
michael@0 | 633 | { |
michael@0 | 634 | inline void newPropertyState(ExclusiveContext *cx); |
michael@0 | 635 | |
michael@0 | 636 | public: |
michael@0 | 637 | /* Mark this type set as representing a non-data property. */ |
michael@0 | 638 | inline void setNonDataProperty(ExclusiveContext *cx); |
michael@0 | 639 | inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC. |
michael@0 | 640 | |
michael@0 | 641 | /* Mark this type set as representing a non-writable property. */ |
michael@0 | 642 | inline void setNonWritableProperty(ExclusiveContext *cx); |
michael@0 | 643 | }; |
michael@0 | 644 | |
michael@0 | 645 | class CompilerConstraintList; |
michael@0 | 646 | |
michael@0 | 647 | CompilerConstraintList * |
michael@0 | 648 | NewCompilerConstraintList(jit::TempAllocator &alloc); |
michael@0 | 649 | |
michael@0 | 650 | class TemporaryTypeSet : public TypeSet |
michael@0 | 651 | { |
michael@0 | 652 | public: |
michael@0 | 653 | TemporaryTypeSet() {} |
michael@0 | 654 | TemporaryTypeSet(Type type); |
michael@0 | 655 | |
michael@0 | 656 | TemporaryTypeSet(uint32_t flags, TypeObjectKey **objectSet) { |
michael@0 | 657 | this->flags = flags; |
michael@0 | 658 | this->objectSet = objectSet; |
michael@0 | 659 | } |
michael@0 | 660 | |
michael@0 | 661 | /* |
michael@0 | 662 | * Constraints for JIT compilation. |
michael@0 | 663 | * |
michael@0 | 664 | * Methods for JIT compilation. These must be used when a script is |
michael@0 | 665 | * currently being compiled (see AutoEnterCompilation) and will add |
michael@0 | 666 | * constraints ensuring that if the return value change in the future due |
michael@0 | 667 | * to new type information, the script's jitcode will be discarded. |
michael@0 | 668 | */ |
michael@0 | 669 | |
michael@0 | 670 | /* Get any type tag which all values in this set must have. */ |
michael@0 | 671 | jit::MIRType getKnownMIRType(); |
michael@0 | 672 | |
michael@0 | 673 | bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; } |
michael@0 | 674 | |
michael@0 | 675 | /* Whether this value may be an object. */ |
michael@0 | 676 | bool maybeObject() { return unknownObject() || baseObjectCount() > 0; } |
michael@0 | 677 | |
michael@0 | 678 | /* |
michael@0 | 679 | * Whether this typeset represents a potentially sentineled object value: |
michael@0 | 680 | * the value may be an object or null or undefined. |
michael@0 | 681 | * Returns false if the value cannot ever be an object. |
michael@0 | 682 | */ |
michael@0 | 683 | bool objectOrSentinel() { |
michael@0 | 684 | TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT; |
michael@0 | 685 | if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK)) |
michael@0 | 686 | return false; |
michael@0 | 687 | |
michael@0 | 688 | return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0; |
michael@0 | 689 | } |
michael@0 | 690 | |
michael@0 | 691 | /* Whether the type set contains objects with any of a set of flags. */ |
michael@0 | 692 | bool hasObjectFlags(CompilerConstraintList *constraints, TypeObjectFlags flags); |
michael@0 | 693 | |
michael@0 | 694 | /* Get the class shared by all objects in this set, or nullptr. */ |
michael@0 | 695 | const Class *getKnownClass(); |
michael@0 | 696 | |
michael@0 | 697 | /* Result returned from forAllClasses */ |
michael@0 | 698 | enum ForAllResult { |
michael@0 | 699 | EMPTY=1, // Set empty |
michael@0 | 700 | ALL_TRUE, // Set not empty and predicate returned true for all classes |
michael@0 | 701 | ALL_FALSE, // Set not empty and predicate returned false for all classes |
michael@0 | 702 | MIXED, // Set not empty and predicate returned false for some classes |
michael@0 | 703 | // and true for others, or set contains an unknown or non-object |
michael@0 | 704 | // type |
michael@0 | 705 | }; |
michael@0 | 706 | |
michael@0 | 707 | /* Apply func to the members of the set and return an appropriate result. |
michael@0 | 708 | * The iteration may end early if the result becomes known early. |
michael@0 | 709 | */ |
michael@0 | 710 | ForAllResult forAllClasses(bool (*func)(const Class *clasp)); |
michael@0 | 711 | |
michael@0 | 712 | /* Get the prototype shared by all objects in this set, or nullptr. */ |
michael@0 | 713 | JSObject *getCommonPrototype(); |
michael@0 | 714 | |
michael@0 | 715 | /* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */ |
michael@0 | 716 | int getTypedArrayType(); |
michael@0 | 717 | |
michael@0 | 718 | /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */ |
michael@0 | 719 | bool isDOMClass(); |
michael@0 | 720 | |
michael@0 | 721 | /* Whether clasp->isCallable() is true for one or more objects in this set. */ |
michael@0 | 722 | bool maybeCallable(); |
michael@0 | 723 | |
michael@0 | 724 | /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */ |
michael@0 | 725 | bool maybeEmulatesUndefined(); |
michael@0 | 726 | |
michael@0 | 727 | /* Get the single value which can appear in this type set, otherwise nullptr. */ |
michael@0 | 728 | JSObject *getSingleton(); |
michael@0 | 729 | |
michael@0 | 730 | /* Whether any objects in the type set needs a barrier on id. */ |
michael@0 | 731 | bool propertyNeedsBarrier(CompilerConstraintList *constraints, jsid id); |
michael@0 | 732 | |
michael@0 | 733 | /* |
michael@0 | 734 | * Whether this set contains all types in other, except (possibly) the |
michael@0 | 735 | * specified type. |
michael@0 | 736 | */ |
michael@0 | 737 | bool filtersType(const TemporaryTypeSet *other, Type type) const; |
michael@0 | 738 | |
michael@0 | 739 | enum DoubleConversion { |
michael@0 | 740 | /* All types in the set should use eager double conversion. */ |
michael@0 | 741 | AlwaysConvertToDoubles, |
michael@0 | 742 | |
michael@0 | 743 | /* Some types in the set should use eager double conversion. */ |
michael@0 | 744 | MaybeConvertToDoubles, |
michael@0 | 745 | |
michael@0 | 746 | /* No types should use eager double conversion. */ |
michael@0 | 747 | DontConvertToDoubles, |
michael@0 | 748 | |
michael@0 | 749 | /* Some types should use eager double conversion, others cannot. */ |
michael@0 | 750 | AmbiguousDoubleConversion |
michael@0 | 751 | }; |
michael@0 | 752 | |
michael@0 | 753 | /* |
michael@0 | 754 | * Whether known double optimizations are possible for element accesses on |
michael@0 | 755 | * objects in this type set. |
michael@0 | 756 | */ |
michael@0 | 757 | DoubleConversion convertDoubleElements(CompilerConstraintList *constraints); |
michael@0 | 758 | }; |
michael@0 | 759 | |
michael@0 | 760 | bool |
michael@0 | 761 | AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id); |
michael@0 | 762 | |
michael@0 | 763 | bool |
michael@0 | 764 | AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type, |
michael@0 | 765 | JSScript *script, JSScript *calleeScript); |
michael@0 | 766 | |
michael@0 | 767 | /* Is this a reasonable PC to be doing inlining on? */ |
michael@0 | 768 | inline bool isInlinableCall(jsbytecode *pc); |
michael@0 | 769 | |
michael@0 | 770 | /* Type information about a property. */ |
michael@0 | 771 | struct Property |
michael@0 | 772 | { |
michael@0 | 773 | /* Identifier for this property, JSID_VOID for the aggregate integer index property. */ |
michael@0 | 774 | HeapId id; |
michael@0 | 775 | |
michael@0 | 776 | /* Possible types for this property, including types inherited from prototypes. */ |
michael@0 | 777 | HeapTypeSet types; |
michael@0 | 778 | |
michael@0 | 779 | Property(jsid id) |
michael@0 | 780 | : id(id) |
michael@0 | 781 | {} |
michael@0 | 782 | |
michael@0 | 783 | Property(const Property &o) |
michael@0 | 784 | : id(o.id.get()), types(o.types) |
michael@0 | 785 | {} |
michael@0 | 786 | |
michael@0 | 787 | static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); } |
michael@0 | 788 | static jsid getKey(Property *p) { return p->id; } |
michael@0 | 789 | }; |
michael@0 | 790 | |
michael@0 | 791 | struct TypeNewScript; |
michael@0 | 792 | struct TypeTypedObject; |
michael@0 | 793 | |
michael@0 | 794 | struct TypeObjectAddendum |
michael@0 | 795 | { |
michael@0 | 796 | enum Kind { |
michael@0 | 797 | NewScript, |
michael@0 | 798 | TypedObject |
michael@0 | 799 | }; |
michael@0 | 800 | |
michael@0 | 801 | TypeObjectAddendum(Kind kind); |
michael@0 | 802 | |
michael@0 | 803 | const Kind kind; |
michael@0 | 804 | |
michael@0 | 805 | bool isNewScript() { |
michael@0 | 806 | return kind == NewScript; |
michael@0 | 807 | } |
michael@0 | 808 | |
michael@0 | 809 | TypeNewScript *asNewScript() { |
michael@0 | 810 | JS_ASSERT(isNewScript()); |
michael@0 | 811 | return (TypeNewScript*) this; |
michael@0 | 812 | } |
michael@0 | 813 | |
michael@0 | 814 | bool isTypedObject() { |
michael@0 | 815 | return kind == TypedObject; |
michael@0 | 816 | } |
michael@0 | 817 | |
michael@0 | 818 | TypeTypedObject *asTypedObject() { |
michael@0 | 819 | JS_ASSERT(isTypedObject()); |
michael@0 | 820 | return (TypeTypedObject*) this; |
michael@0 | 821 | } |
michael@0 | 822 | |
michael@0 | 823 | static inline void writeBarrierPre(TypeObjectAddendum *type); |
michael@0 | 824 | |
michael@0 | 825 | static void writeBarrierPost(TypeObjectAddendum *newScript, void *addr) {} |
michael@0 | 826 | }; |
michael@0 | 827 | |
michael@0 | 828 | /* |
michael@0 | 829 | * Information attached to a TypeObject if it is always constructed using 'new' |
michael@0 | 830 | * on a particular script. This is used to manage state related to the definite |
michael@0 | 831 | * properties on the type object: these definite properties depend on type |
michael@0 | 832 | * information which could change as the script executes (e.g. a scripted |
michael@0 | 833 | * setter is added to a prototype object), and we need to ensure both that the |
michael@0 | 834 | * appropriate type constraints are in place when necessary, and that we can |
michael@0 | 835 | * remove the definite property information and repair the JS stack if the |
michael@0 | 836 | * constraints are violated. |
michael@0 | 837 | */ |
michael@0 | 838 | struct TypeNewScript : public TypeObjectAddendum |
michael@0 | 839 | { |
michael@0 | 840 | TypeNewScript(); |
michael@0 | 841 | |
michael@0 | 842 | HeapPtrFunction fun; |
michael@0 | 843 | |
michael@0 | 844 | /* |
michael@0 | 845 | * Template object to use for newly constructed objects. Reflects all |
michael@0 | 846 | * definite properties the object will have and the allocation kind to use |
michael@0 | 847 | * for the object. The allocation kind --- and template object itself --- |
michael@0 | 848 | * is subject to change if objects allocated with this type are given |
michael@0 | 849 | * dynamic slots later on due to new properties being added after the |
michael@0 | 850 | * constructor function finishes. |
michael@0 | 851 | */ |
michael@0 | 852 | HeapPtrObject templateObject; |
michael@0 | 853 | |
michael@0 | 854 | /* |
michael@0 | 855 | * Order in which properties become initialized. We need this in case a |
michael@0 | 856 | * scripted setter is added to one of the object's prototypes while it is |
michael@0 | 857 | * in the middle of being initialized, so we can walk the stack and fixup |
michael@0 | 858 | * any objects which look for in-progress objects which were prematurely |
michael@0 | 859 | * set with their final shape. Property assignments in inner frames are |
michael@0 | 860 | * preceded by a series of SETPROP_FRAME entries specifying the stack down |
michael@0 | 861 | * to the frame containing the write. |
michael@0 | 862 | */ |
michael@0 | 863 | struct Initializer { |
michael@0 | 864 | enum Kind { |
michael@0 | 865 | SETPROP, |
michael@0 | 866 | SETPROP_FRAME, |
michael@0 | 867 | DONE |
michael@0 | 868 | } kind; |
michael@0 | 869 | uint32_t offset; |
michael@0 | 870 | Initializer(Kind kind, uint32_t offset) |
michael@0 | 871 | : kind(kind), offset(offset) |
michael@0 | 872 | {} |
michael@0 | 873 | }; |
michael@0 | 874 | Initializer *initializerList; |
michael@0 | 875 | |
michael@0 | 876 | static inline void writeBarrierPre(TypeNewScript *newScript); |
michael@0 | 877 | }; |
michael@0 | 878 | |
michael@0 | 879 | struct TypeTypedObject : public TypeObjectAddendum |
michael@0 | 880 | { |
michael@0 | 881 | private: |
michael@0 | 882 | HeapPtrObject descr_; |
michael@0 | 883 | |
michael@0 | 884 | public: |
michael@0 | 885 | TypeTypedObject(Handle<TypeDescr*> descr); |
michael@0 | 886 | |
michael@0 | 887 | HeapPtrObject &descrHeapPtr() { |
michael@0 | 888 | return descr_; |
michael@0 | 889 | } |
michael@0 | 890 | |
michael@0 | 891 | TypeDescr &descr(); |
michael@0 | 892 | }; |
michael@0 | 893 | |
michael@0 | 894 | /* |
michael@0 | 895 | * Lazy type objects overview. |
michael@0 | 896 | * |
michael@0 | 897 | * Type objects which represent at most one JS object are constructed lazily. |
michael@0 | 898 | * These include types for native functions, standard classes, scripted |
michael@0 | 899 | * functions defined at the top level of global/eval scripts, and in some |
michael@0 | 900 | * other cases. Typical web workloads often create many windows (and many |
michael@0 | 901 | * copies of standard natives) and many scripts, with comparatively few |
michael@0 | 902 | * non-singleton types. |
michael@0 | 903 | * |
michael@0 | 904 | * We can recover the type information for the object from examining it, |
michael@0 | 905 | * so don't normally track the possible types of its properties as it is |
michael@0 | 906 | * updated. Property type sets for the object are only constructed when an |
michael@0 | 907 | * analyzed script attaches constraints to it: the script is querying that |
michael@0 | 908 | * property off the object or another which delegates to it, and the analysis |
michael@0 | 909 | * information is sensitive to changes in the property's type. Future changes |
michael@0 | 910 | * to the property (whether those uncovered by analysis or those occurring |
michael@0 | 911 | * in the VM) will treat these properties like those of any other type object. |
michael@0 | 912 | */ |
michael@0 | 913 | |
michael@0 | 914 | /* Type information about an object accessed by a script. */ |
michael@0 | 915 | struct TypeObject : gc::BarrieredCell<TypeObject> |
michael@0 | 916 | { |
michael@0 | 917 | private: |
michael@0 | 918 | /* Class shared by object using this type. */ |
michael@0 | 919 | const Class *clasp_; |
michael@0 | 920 | |
michael@0 | 921 | /* Prototype shared by objects using this type. */ |
michael@0 | 922 | HeapPtrObject proto_; |
michael@0 | 923 | |
michael@0 | 924 | /* |
michael@0 | 925 | * Whether there is a singleton JS object with this type. That JS object |
michael@0 | 926 | * must appear in type sets instead of this; we include the back reference |
michael@0 | 927 | * here to allow reverting the JS object to a lazy type. |
michael@0 | 928 | */ |
michael@0 | 929 | HeapPtrObject singleton_; |
michael@0 | 930 | |
michael@0 | 931 | public: |
michael@0 | 932 | |
michael@0 | 933 | const Class *clasp() const { |
michael@0 | 934 | return clasp_; |
michael@0 | 935 | } |
michael@0 | 936 | |
michael@0 | 937 | void setClasp(const Class *clasp) { |
michael@0 | 938 | JS_ASSERT(singleton()); |
michael@0 | 939 | clasp_ = clasp; |
michael@0 | 940 | } |
michael@0 | 941 | |
michael@0 | 942 | TaggedProto proto() const { |
michael@0 | 943 | return TaggedProto(proto_); |
michael@0 | 944 | } |
michael@0 | 945 | |
michael@0 | 946 | JSObject *singleton() const { |
michael@0 | 947 | return singleton_; |
michael@0 | 948 | } |
michael@0 | 949 | |
michael@0 | 950 | // For use during marking, don't call otherwise. |
michael@0 | 951 | HeapPtrObject &protoRaw() { return proto_; } |
michael@0 | 952 | HeapPtrObject &singletonRaw() { return singleton_; } |
michael@0 | 953 | |
michael@0 | 954 | void setProto(JSContext *cx, TaggedProto proto); |
michael@0 | 955 | void setProtoUnchecked(TaggedProto proto) { |
michael@0 | 956 | proto_ = proto.raw(); |
michael@0 | 957 | } |
michael@0 | 958 | |
michael@0 | 959 | void initSingleton(JSObject *singleton) { |
michael@0 | 960 | singleton_ = singleton; |
michael@0 | 961 | } |
michael@0 | 962 | |
michael@0 | 963 | /* |
michael@0 | 964 | * Value held by singleton if this is a standin type for a singleton JS |
michael@0 | 965 | * object whose type has not been constructed yet. |
michael@0 | 966 | */ |
michael@0 | 967 | static const size_t LAZY_SINGLETON = 1; |
michael@0 | 968 | bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; } |
michael@0 | 969 | |
michael@0 | 970 | private: |
michael@0 | 971 | /* Flags for this object. */ |
michael@0 | 972 | TypeObjectFlags flags_; |
michael@0 | 973 | |
michael@0 | 974 | /* |
michael@0 | 975 | * This field allows various special classes of objects to attach |
michael@0 | 976 | * additional information to a type object: |
michael@0 | 977 | * |
michael@0 | 978 | * - `TypeNewScript`: If addendum is a `TypeNewScript`, it |
michael@0 | 979 | * indicates that objects of this type have always been |
michael@0 | 980 | * constructed using 'new' on the specified script, which adds |
michael@0 | 981 | * some number of properties to the object in a definite order |
michael@0 | 982 | * before the object escapes. |
michael@0 | 983 | */ |
michael@0 | 984 | HeapPtr<TypeObjectAddendum> addendum; |
michael@0 | 985 | public: |
michael@0 | 986 | |
michael@0 | 987 | TypeObjectFlags flags() const { |
michael@0 | 988 | return flags_; |
michael@0 | 989 | } |
michael@0 | 990 | |
michael@0 | 991 | void addFlags(TypeObjectFlags flags) { |
michael@0 | 992 | flags_ |= flags; |
michael@0 | 993 | } |
michael@0 | 994 | |
michael@0 | 995 | void clearFlags(TypeObjectFlags flags) { |
michael@0 | 996 | flags_ &= ~flags; |
michael@0 | 997 | } |
michael@0 | 998 | |
michael@0 | 999 | bool hasNewScript() const { |
michael@0 | 1000 | return addendum && addendum->isNewScript(); |
michael@0 | 1001 | } |
michael@0 | 1002 | |
michael@0 | 1003 | TypeNewScript *newScript() { |
michael@0 | 1004 | return addendum->asNewScript(); |
michael@0 | 1005 | } |
michael@0 | 1006 | |
michael@0 | 1007 | bool hasTypedObject() { |
michael@0 | 1008 | return addendum && addendum->isTypedObject(); |
michael@0 | 1009 | } |
michael@0 | 1010 | |
michael@0 | 1011 | TypeTypedObject *typedObject() { |
michael@0 | 1012 | return addendum->asTypedObject(); |
michael@0 | 1013 | } |
michael@0 | 1014 | |
michael@0 | 1015 | void setAddendum(TypeObjectAddendum *addendum); |
michael@0 | 1016 | |
michael@0 | 1017 | /* |
michael@0 | 1018 | * Tag the type object for a binary data type descriptor, instance, |
michael@0 | 1019 | * or handle with the type representation of the data it points at. |
michael@0 | 1020 | * If this type object is already tagged with a binary data addendum, |
michael@0 | 1021 | * this addendum must already be associated with the same TypeRepresentation, |
michael@0 | 1022 | * and the method has no effect. |
michael@0 | 1023 | */ |
michael@0 | 1024 | bool addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr); |
michael@0 | 1025 | |
michael@0 | 1026 | private: |
michael@0 | 1027 | /* |
michael@0 | 1028 | * Properties of this object. This may contain JSID_VOID, representing the |
michael@0 | 1029 | * types of all integer indexes of the object, and/or JSID_EMPTY, holding |
michael@0 | 1030 | * constraints listening to changes to the object's state. |
michael@0 | 1031 | * |
michael@0 | 1032 | * The type sets in the properties of a type object describe the possible |
michael@0 | 1033 | * values that can be read out of that property in actual JS objects. |
michael@0 | 1034 | * Properties only account for native properties (those with a slot and no |
michael@0 | 1035 | * specialized getter hook) and the elements of dense arrays. For accesses |
michael@0 | 1036 | * on such properties, the correspondence is as follows: |
michael@0 | 1037 | * |
michael@0 | 1038 | * 1. If the type has unknownProperties(), the possible properties and |
michael@0 | 1039 | * value types for associated JSObjects are unknown. |
michael@0 | 1040 | * |
michael@0 | 1041 | * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id |
michael@0 | 1042 | * which is a property in obj, before obj->getProperty(id) the property |
michael@0 | 1043 | * in type for id must reflect the result of the getProperty. |
michael@0 | 1044 | * |
michael@0 | 1045 | * There is an exception for properties of global JS objects which |
michael@0 | 1046 | * are undefined at the point where the property was (lazily) generated. |
michael@0 | 1047 | * In such cases the property type set will remain empty, and the |
michael@0 | 1048 | * 'undefined' type will only be added after a subsequent assignment or |
michael@0 | 1049 | * deletion. After these properties have been assigned a defined value, |
michael@0 | 1050 | * the only way they can become undefined again is after such an assign |
michael@0 | 1051 | * or deletion. |
michael@0 | 1052 | * |
michael@0 | 1053 | * There is another exception for array lengths, which are special cased |
michael@0 | 1054 | * by the compiler and VM and are not reflected in property types. |
michael@0 | 1055 | * |
michael@0 | 1056 | * We establish these by using write barriers on calls to setProperty and |
michael@0 | 1057 | * defineProperty which are on native properties, and on any jitcode which |
michael@0 | 1058 | * might update the property with a new type. |
michael@0 | 1059 | */ |
michael@0 | 1060 | Property **propertySet; |
michael@0 | 1061 | public: |
michael@0 | 1062 | |
michael@0 | 1063 | /* If this is an interpreted function, the function object. */ |
michael@0 | 1064 | HeapPtrFunction interpretedFunction; |
michael@0 | 1065 | |
michael@0 | 1066 | #if JS_BITS_PER_WORD == 32 |
michael@0 | 1067 | uint32_t padding; |
michael@0 | 1068 | #endif |
michael@0 | 1069 | |
michael@0 | 1070 | inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags); |
michael@0 | 1071 | |
michael@0 | 1072 | bool hasAnyFlags(TypeObjectFlags flags) { |
michael@0 | 1073 | JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); |
michael@0 | 1074 | return !!(this->flags() & flags); |
michael@0 | 1075 | } |
michael@0 | 1076 | bool hasAllFlags(TypeObjectFlags flags) { |
michael@0 | 1077 | JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); |
michael@0 | 1078 | return (this->flags() & flags) == flags; |
michael@0 | 1079 | } |
michael@0 | 1080 | |
michael@0 | 1081 | bool unknownProperties() { |
michael@0 | 1082 | JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES, |
michael@0 | 1083 | hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK)); |
michael@0 | 1084 | return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES); |
michael@0 | 1085 | } |
michael@0 | 1086 | |
michael@0 | 1087 | bool shouldPreTenure() { |
michael@0 | 1088 | return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties(); |
michael@0 | 1089 | } |
michael@0 | 1090 | |
michael@0 | 1091 | bool hasTenuredProto() const { |
michael@0 | 1092 | return !(flags() & OBJECT_FLAG_NURSERY_PROTO); |
michael@0 | 1093 | } |
michael@0 | 1094 | |
michael@0 | 1095 | gc::InitialHeap initialHeap(CompilerConstraintList *constraints); |
michael@0 | 1096 | |
michael@0 | 1097 | bool canPreTenure() { |
michael@0 | 1098 | // Only types associated with particular allocation sites or 'new' |
michael@0 | 1099 | // scripts can be marked as needing pretenuring. Other types can be |
michael@0 | 1100 | // used for different purposes across the compartment and can't use |
michael@0 | 1101 | // this bit reliably. |
michael@0 | 1102 | if (unknownProperties()) |
michael@0 | 1103 | return false; |
michael@0 | 1104 | return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript(); |
michael@0 | 1105 | } |
michael@0 | 1106 | |
michael@0 | 1107 | void setShouldPreTenure(ExclusiveContext *cx) { |
michael@0 | 1108 | JS_ASSERT(canPreTenure()); |
michael@0 | 1109 | setFlags(cx, OBJECT_FLAG_PRE_TENURE); |
michael@0 | 1110 | } |
michael@0 | 1111 | |
michael@0 | 1112 | /* |
michael@0 | 1113 | * Get or create a property of this object. Only call this for properties which |
michael@0 | 1114 | * a script accesses explicitly. |
michael@0 | 1115 | */ |
michael@0 | 1116 | inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id); |
michael@0 | 1117 | |
michael@0 | 1118 | /* Get a property only if it already exists. */ |
michael@0 | 1119 | inline HeapTypeSet *maybeGetProperty(jsid id); |
michael@0 | 1120 | |
michael@0 | 1121 | inline unsigned getPropertyCount(); |
michael@0 | 1122 | inline Property *getProperty(unsigned i); |
michael@0 | 1123 | |
michael@0 | 1124 | /* Helpers */ |
michael@0 | 1125 | |
michael@0 | 1126 | void updateNewPropertyTypes(ExclusiveContext *cx, jsid id, HeapTypeSet *types); |
michael@0 | 1127 | bool addDefiniteProperties(ExclusiveContext *cx, JSObject *obj); |
michael@0 | 1128 | bool matchDefiniteProperties(HandleObject obj); |
michael@0 | 1129 | void addPrototype(JSContext *cx, TypeObject *proto); |
michael@0 | 1130 | void addPropertyType(ExclusiveContext *cx, jsid id, Type type); |
michael@0 | 1131 | void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value); |
michael@0 | 1132 | void markPropertyNonData(ExclusiveContext *cx, jsid id); |
michael@0 | 1133 | void markPropertyNonWritable(ExclusiveContext *cx, jsid id); |
michael@0 | 1134 | void markStateChange(ExclusiveContext *cx); |
michael@0 | 1135 | void setFlags(ExclusiveContext *cx, TypeObjectFlags flags); |
michael@0 | 1136 | void markUnknown(ExclusiveContext *cx); |
michael@0 | 1137 | void clearAddendum(ExclusiveContext *cx); |
michael@0 | 1138 | void clearNewScriptAddendum(ExclusiveContext *cx); |
michael@0 | 1139 | void clearTypedObjectAddendum(ExclusiveContext *cx); |
michael@0 | 1140 | void maybeClearNewScriptAddendumOnOOM(); |
michael@0 | 1141 | bool isPropertyNonData(jsid id); |
michael@0 | 1142 | bool isPropertyNonWritable(jsid id); |
michael@0 | 1143 | |
michael@0 | 1144 | void print(); |
michael@0 | 1145 | |
michael@0 | 1146 | inline void clearProperties(); |
michael@0 | 1147 | inline void sweep(FreeOp *fop, bool *oom); |
michael@0 | 1148 | |
michael@0 | 1149 | size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; |
michael@0 | 1150 | |
michael@0 | 1151 | /* |
michael@0 | 1152 | * Type objects don't have explicit finalizers. Memory owned by a type |
michael@0 | 1153 | * object pending deletion is released when weak references are sweeped |
michael@0 | 1154 | * from all the compartment's type objects. |
michael@0 | 1155 | */ |
michael@0 | 1156 | void finalize(FreeOp *fop) {} |
michael@0 | 1157 | |
michael@0 | 1158 | static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; } |
michael@0 | 1159 | |
michael@0 | 1160 | static inline uint32_t offsetOfClasp() { |
michael@0 | 1161 | return offsetof(TypeObject, clasp_); |
michael@0 | 1162 | } |
michael@0 | 1163 | |
michael@0 | 1164 | static inline uint32_t offsetOfProto() { |
michael@0 | 1165 | return offsetof(TypeObject, proto_); |
michael@0 | 1166 | } |
michael@0 | 1167 | |
michael@0 | 1168 | private: |
michael@0 | 1169 | inline uint32_t basePropertyCount() const; |
michael@0 | 1170 | inline void setBasePropertyCount(uint32_t count); |
michael@0 | 1171 | |
michael@0 | 1172 | static void staticAsserts() { |
michael@0 | 1173 | JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto)); |
michael@0 | 1174 | } |
michael@0 | 1175 | }; |
michael@0 | 1176 | |
michael@0 | 1177 | /* |
michael@0 | 1178 | * Entries for the per-compartment set of type objects which are 'new' types to |
michael@0 | 1179 | * use for some prototype and constructed with an optional script. This also |
michael@0 | 1180 | * includes entries for the set of lazy type objects in the compartment, which |
michael@0 | 1181 | * use a null script (though there are only a few of these per compartment). |
michael@0 | 1182 | */ |
michael@0 | 1183 | struct TypeObjectWithNewScriptEntry |
michael@0 | 1184 | { |
michael@0 | 1185 | ReadBarriered<TypeObject> object; |
michael@0 | 1186 | |
michael@0 | 1187 | // Note: This pointer is only used for equality and does not need a read barrier. |
michael@0 | 1188 | JSFunction *newFunction; |
michael@0 | 1189 | |
michael@0 | 1190 | TypeObjectWithNewScriptEntry(TypeObject *object, JSFunction *newFunction) |
michael@0 | 1191 | : object(object), newFunction(newFunction) |
michael@0 | 1192 | {} |
michael@0 | 1193 | |
michael@0 | 1194 | struct Lookup { |
michael@0 | 1195 | const Class *clasp; |
michael@0 | 1196 | TaggedProto hashProto; |
michael@0 | 1197 | TaggedProto matchProto; |
michael@0 | 1198 | JSFunction *newFunction; |
michael@0 | 1199 | |
michael@0 | 1200 | Lookup(const Class *clasp, TaggedProto proto, JSFunction *newFunction) |
michael@0 | 1201 | : clasp(clasp), hashProto(proto), matchProto(proto), newFunction(newFunction) |
michael@0 | 1202 | {} |
michael@0 | 1203 | |
michael@0 | 1204 | #ifdef JSGC_GENERATIONAL |
michael@0 | 1205 | /* |
michael@0 | 1206 | * For use by generational post barriers only. Look up an entry whose |
michael@0 | 1207 | * proto has been moved, but was hashed with the original value. |
michael@0 | 1208 | */ |
michael@0 | 1209 | Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSFunction *newFunction) |
michael@0 | 1210 | : clasp(clasp), hashProto(hashProto), matchProto(matchProto), newFunction(newFunction) |
michael@0 | 1211 | {} |
michael@0 | 1212 | #endif |
michael@0 | 1213 | |
michael@0 | 1214 | }; |
michael@0 | 1215 | |
michael@0 | 1216 | static inline HashNumber hash(const Lookup &lookup); |
michael@0 | 1217 | static inline bool match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup); |
michael@0 | 1218 | static void rekey(TypeObjectWithNewScriptEntry &k, const TypeObjectWithNewScriptEntry& newKey) { k = newKey; } |
michael@0 | 1219 | }; |
michael@0 | 1220 | typedef HashSet<TypeObjectWithNewScriptEntry, |
michael@0 | 1221 | TypeObjectWithNewScriptEntry, |
michael@0 | 1222 | SystemAllocPolicy> TypeObjectWithNewScriptSet; |
michael@0 | 1223 | |
michael@0 | 1224 | /* Whether to use a new type object when calling 'new' at script/pc. */ |
michael@0 | 1225 | bool |
michael@0 | 1226 | UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc); |
michael@0 | 1227 | |
michael@0 | 1228 | bool |
michael@0 | 1229 | UseNewTypeForClone(JSFunction *fun); |
michael@0 | 1230 | |
michael@0 | 1231 | /* |
michael@0 | 1232 | * Whether Array.prototype, or an object on its proto chain, has an |
michael@0 | 1233 | * indexed property. |
michael@0 | 1234 | */ |
michael@0 | 1235 | bool |
michael@0 | 1236 | ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSScript *script); |
michael@0 | 1237 | |
michael@0 | 1238 | /* Whether obj or any of its prototypes have an indexed property. */ |
michael@0 | 1239 | bool |
michael@0 | 1240 | TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints, TemporaryTypeSet *types); |
michael@0 | 1241 | |
michael@0 | 1242 | /* Persistent type information for a script, retained across GCs. */ |
michael@0 | 1243 | class TypeScript |
michael@0 | 1244 | { |
michael@0 | 1245 | friend class ::JSScript; |
michael@0 | 1246 | |
michael@0 | 1247 | // Variable-size array |
michael@0 | 1248 | StackTypeSet typeArray_[1]; |
michael@0 | 1249 | |
michael@0 | 1250 | public: |
michael@0 | 1251 | /* Array of type type sets for variables and JOF_TYPESET ops. */ |
michael@0 | 1252 | StackTypeSet *typeArray() const { |
michael@0 | 1253 | // Ensure typeArray_ is the last data member of TypeScript. |
michael@0 | 1254 | JS_STATIC_ASSERT(sizeof(TypeScript) == |
michael@0 | 1255 | sizeof(typeArray_) + offsetof(TypeScript, typeArray_)); |
michael@0 | 1256 | return const_cast<StackTypeSet *>(typeArray_); |
michael@0 | 1257 | } |
michael@0 | 1258 | |
michael@0 | 1259 | static inline size_t SizeIncludingTypeArray(size_t arraySize) { |
michael@0 | 1260 | // Ensure typeArray_ is the last data member of TypeScript. |
michael@0 | 1261 | JS_STATIC_ASSERT(sizeof(TypeScript) == |
michael@0 | 1262 | sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_)); |
michael@0 | 1263 | return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet); |
michael@0 | 1264 | } |
michael@0 | 1265 | |
michael@0 | 1266 | static inline unsigned NumTypeSets(JSScript *script); |
michael@0 | 1267 | |
michael@0 | 1268 | static inline StackTypeSet *ThisTypes(JSScript *script); |
michael@0 | 1269 | static inline StackTypeSet *ArgTypes(JSScript *script, unsigned i); |
michael@0 | 1270 | |
michael@0 | 1271 | /* Get the type set for values observed at an opcode. */ |
michael@0 | 1272 | static inline StackTypeSet *BytecodeTypes(JSScript *script, jsbytecode *pc); |
michael@0 | 1273 | |
michael@0 | 1274 | template <typename TYPESET> |
michael@0 | 1275 | static inline TYPESET *BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap, |
michael@0 | 1276 | uint32_t *hint, TYPESET *typeArray); |
michael@0 | 1277 | |
michael@0 | 1278 | /* Get a type object for an allocation site in this script. */ |
michael@0 | 1279 | static inline TypeObject *InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, |
michael@0 | 1280 | JSProtoKey kind); |
michael@0 | 1281 | |
michael@0 | 1282 | /* |
michael@0 | 1283 | * Monitor a bytecode pushing any value. This must be called for any opcode |
michael@0 | 1284 | * which is JOF_TYPESET, and where either the script has not been analyzed |
michael@0 | 1285 | * by type inference or where the pc has type barriers. For simplicity, we |
michael@0 | 1286 | * always monitor JOF_TYPESET opcodes in the interpreter and stub calls, |
michael@0 | 1287 | * and only look at barriers when generating JIT code for the script. |
michael@0 | 1288 | */ |
michael@0 | 1289 | static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, |
michael@0 | 1290 | const js::Value &val); |
michael@0 | 1291 | static inline void Monitor(JSContext *cx, const js::Value &rval); |
michael@0 | 1292 | |
michael@0 | 1293 | /* Monitor an assignment at a SETELEM on a non-integer identifier. */ |
michael@0 | 1294 | static inline void MonitorAssign(JSContext *cx, HandleObject obj, jsid id); |
michael@0 | 1295 | |
michael@0 | 1296 | /* Add a type for a variable in a script. */ |
michael@0 | 1297 | static inline void SetThis(JSContext *cx, JSScript *script, Type type); |
michael@0 | 1298 | static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value); |
michael@0 | 1299 | static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type); |
michael@0 | 1300 | static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, |
michael@0 | 1301 | const js::Value &value); |
michael@0 | 1302 | |
michael@0 | 1303 | /* |
michael@0 | 1304 | * Freeze all the stack type sets in a script, for a compilation. Returns |
michael@0 | 1305 | * copies of the type sets which will be checked against the actual ones |
michael@0 | 1306 | * under FinishCompilation, to detect any type changes. |
michael@0 | 1307 | */ |
michael@0 | 1308 | static bool FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script, |
michael@0 | 1309 | TemporaryTypeSet **pThisTypes, |
michael@0 | 1310 | TemporaryTypeSet **pArgTypes, |
michael@0 | 1311 | TemporaryTypeSet **pBytecodeTypes); |
michael@0 | 1312 | |
michael@0 | 1313 | static void Purge(JSContext *cx, HandleScript script); |
michael@0 | 1314 | |
michael@0 | 1315 | static void Sweep(FreeOp *fop, JSScript *script, bool *oom); |
michael@0 | 1316 | void destroy(); |
michael@0 | 1317 | |
michael@0 | 1318 | size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { |
michael@0 | 1319 | return mallocSizeOf(this); |
michael@0 | 1320 | } |
michael@0 | 1321 | |
michael@0 | 1322 | #ifdef DEBUG |
michael@0 | 1323 | void printTypes(JSContext *cx, HandleScript script) const; |
michael@0 | 1324 | #endif |
michael@0 | 1325 | }; |
michael@0 | 1326 | |
michael@0 | 1327 | void |
michael@0 | 1328 | FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap); |
michael@0 | 1329 | |
michael@0 | 1330 | class RecompileInfo; |
michael@0 | 1331 | |
michael@0 | 1332 | // Allocate a CompilerOutput for a finished compilation and generate the type |
michael@0 | 1333 | // constraints for the compilation. Returns whether the type constraints |
michael@0 | 1334 | // still hold. |
michael@0 | 1335 | bool |
michael@0 | 1336 | FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode executionMode, |
michael@0 | 1337 | CompilerConstraintList *constraints, RecompileInfo *precompileInfo); |
michael@0 | 1338 | |
michael@0 | 1339 | // Update the actual types in any scripts queried by constraints with any |
michael@0 | 1340 | // speculative types added during the definite properties analysis. |
michael@0 | 1341 | void |
michael@0 | 1342 | FinishDefinitePropertiesAnalysis(JSContext *cx, CompilerConstraintList *constraints); |
michael@0 | 1343 | |
michael@0 | 1344 | struct ArrayTableKey; |
michael@0 | 1345 | typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable; |
michael@0 | 1346 | |
michael@0 | 1347 | struct ObjectTableKey; |
michael@0 | 1348 | struct ObjectTableEntry; |
michael@0 | 1349 | typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable; |
michael@0 | 1350 | |
michael@0 | 1351 | struct AllocationSiteKey; |
michael@0 | 1352 | typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable; |
michael@0 | 1353 | |
michael@0 | 1354 | class HeapTypeSetKey; |
michael@0 | 1355 | |
michael@0 | 1356 | // Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. |
michael@0 | 1357 | struct TypeObjectKey |
michael@0 | 1358 | { |
michael@0 | 1359 | static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; } |
michael@0 | 1360 | static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; } |
michael@0 | 1361 | |
michael@0 | 1362 | static TypeObjectKey *get(JSObject *obj) { |
michael@0 | 1363 | JS_ASSERT(obj); |
michael@0 | 1364 | return (TypeObjectKey *) (uintptr_t(obj) | 1); |
michael@0 | 1365 | } |
michael@0 | 1366 | static TypeObjectKey *get(TypeObject *obj) { |
michael@0 | 1367 | JS_ASSERT(obj); |
michael@0 | 1368 | return (TypeObjectKey *) obj; |
michael@0 | 1369 | } |
michael@0 | 1370 | |
michael@0 | 1371 | bool isTypeObject() { |
michael@0 | 1372 | return (uintptr_t(this) & 1) == 0; |
michael@0 | 1373 | } |
michael@0 | 1374 | bool isSingleObject() { |
michael@0 | 1375 | return (uintptr_t(this) & 1) != 0; |
michael@0 | 1376 | } |
michael@0 | 1377 | |
michael@0 | 1378 | TypeObject *asTypeObject() { |
michael@0 | 1379 | JS_ASSERT(isTypeObject()); |
michael@0 | 1380 | return (TypeObject *) this; |
michael@0 | 1381 | } |
michael@0 | 1382 | JSObject *asSingleObject() { |
michael@0 | 1383 | JS_ASSERT(isSingleObject()); |
michael@0 | 1384 | return (JSObject *) (uintptr_t(this) & ~1); |
michael@0 | 1385 | } |
michael@0 | 1386 | |
michael@0 | 1387 | const Class *clasp(); |
michael@0 | 1388 | TaggedProto proto(); |
michael@0 | 1389 | bool hasTenuredProto(); |
michael@0 | 1390 | JSObject *singleton(); |
michael@0 | 1391 | TypeNewScript *newScript(); |
michael@0 | 1392 | |
michael@0 | 1393 | bool unknownProperties(); |
michael@0 | 1394 | bool hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags); |
michael@0 | 1395 | void watchStateChangeForInlinedCall(CompilerConstraintList *constraints); |
michael@0 | 1396 | void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints); |
michael@0 | 1397 | void watchStateChangeForTypedArrayData(CompilerConstraintList *constraints); |
michael@0 | 1398 | HeapTypeSetKey property(jsid id); |
michael@0 | 1399 | void ensureTrackedProperty(JSContext *cx, jsid id); |
michael@0 | 1400 | |
michael@0 | 1401 | TypeObject *maybeType(); |
michael@0 | 1402 | }; |
michael@0 | 1403 | |
michael@0 | 1404 | // Representation of a heap type property which may or may not be instantiated. |
michael@0 | 1405 | // Heap properties for singleton types are instantiated lazily as they are used |
michael@0 | 1406 | // by the compiler, but this is only done on the main thread. If we are |
michael@0 | 1407 | // compiling off thread and use a property which has not yet been instantiated, |
michael@0 | 1408 | // it will be treated as empty and non-configured and will be instantiated when |
michael@0 | 1409 | // rejoining to the main thread. If it is in fact not empty, the compilation |
michael@0 | 1410 | // will fail; to avoid this, we try to instantiate singleton property types |
michael@0 | 1411 | // during generation of baseline caches. |
michael@0 | 1412 | class HeapTypeSetKey |
michael@0 | 1413 | { |
michael@0 | 1414 | friend class TypeObjectKey; |
michael@0 | 1415 | |
michael@0 | 1416 | // Object and property being accessed. |
michael@0 | 1417 | TypeObjectKey *object_; |
michael@0 | 1418 | jsid id_; |
michael@0 | 1419 | |
michael@0 | 1420 | // If instantiated, the underlying heap type set. |
michael@0 | 1421 | HeapTypeSet *maybeTypes_; |
michael@0 | 1422 | |
michael@0 | 1423 | public: |
michael@0 | 1424 | HeapTypeSetKey() |
michael@0 | 1425 | : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr) |
michael@0 | 1426 | {} |
michael@0 | 1427 | |
michael@0 | 1428 | TypeObjectKey *object() const { return object_; } |
michael@0 | 1429 | jsid id() const { return id_; } |
michael@0 | 1430 | HeapTypeSet *maybeTypes() const { return maybeTypes_; } |
michael@0 | 1431 | |
michael@0 | 1432 | bool instantiate(JSContext *cx); |
michael@0 | 1433 | |
michael@0 | 1434 | void freeze(CompilerConstraintList *constraints); |
michael@0 | 1435 | jit::MIRType knownMIRType(CompilerConstraintList *constraints); |
michael@0 | 1436 | bool nonData(CompilerConstraintList *constraints); |
michael@0 | 1437 | bool nonWritable(CompilerConstraintList *constraints); |
michael@0 | 1438 | bool isOwnProperty(CompilerConstraintList *constraints); |
michael@0 | 1439 | bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other); |
michael@0 | 1440 | JSObject *singleton(CompilerConstraintList *constraints); |
michael@0 | 1441 | bool needsBarrier(CompilerConstraintList *constraints); |
michael@0 | 1442 | }; |
michael@0 | 1443 | |
michael@0 | 1444 | /* |
michael@0 | 1445 | * Information about the result of the compilation of a script. This structure |
michael@0 | 1446 | * stored in the TypeCompartment is indexed by the RecompileInfo. This |
michael@0 | 1447 | * indirection enables the invalidation of all constraints related to the same |
michael@0 | 1448 | * compilation. |
michael@0 | 1449 | */ |
michael@0 | 1450 | class CompilerOutput |
michael@0 | 1451 | { |
michael@0 | 1452 | // If this compilation has not been invalidated, the associated script and |
michael@0 | 1453 | // kind of compilation being performed. |
michael@0 | 1454 | JSScript *script_; |
michael@0 | 1455 | ExecutionMode mode_ : 2; |
michael@0 | 1456 | |
michael@0 | 1457 | // Whether this compilation is about to be invalidated. |
michael@0 | 1458 | bool pendingInvalidation_ : 1; |
michael@0 | 1459 | |
michael@0 | 1460 | // During sweeping, the list of compiler outputs is compacted and invalidated |
michael@0 | 1461 | // outputs are removed. This gives the new index for a valid compiler output. |
michael@0 | 1462 | uint32_t sweepIndex_ : 29; |
michael@0 | 1463 | |
michael@0 | 1464 | public: |
michael@0 | 1465 | static const uint32_t INVALID_SWEEP_INDEX = (1 << 29) - 1; |
michael@0 | 1466 | |
michael@0 | 1467 | CompilerOutput() |
michael@0 | 1468 | : script_(nullptr), mode_(SequentialExecution), |
michael@0 | 1469 | pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX) |
michael@0 | 1470 | {} |
michael@0 | 1471 | |
michael@0 | 1472 | CompilerOutput(JSScript *script, ExecutionMode mode) |
michael@0 | 1473 | : script_(script), mode_(mode), |
michael@0 | 1474 | pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX) |
michael@0 | 1475 | {} |
michael@0 | 1476 | |
michael@0 | 1477 | JSScript *script() const { return script_; } |
michael@0 | 1478 | inline ExecutionMode mode() const { return mode_; } |
michael@0 | 1479 | |
michael@0 | 1480 | inline jit::IonScript *ion() const; |
michael@0 | 1481 | |
michael@0 | 1482 | bool isValid() const { |
michael@0 | 1483 | return script_ != nullptr; |
michael@0 | 1484 | } |
michael@0 | 1485 | void invalidate() { |
michael@0 | 1486 | script_ = nullptr; |
michael@0 | 1487 | } |
michael@0 | 1488 | |
michael@0 | 1489 | void setPendingInvalidation() { |
michael@0 | 1490 | pendingInvalidation_ = true; |
michael@0 | 1491 | } |
michael@0 | 1492 | bool pendingInvalidation() { |
michael@0 | 1493 | return pendingInvalidation_; |
michael@0 | 1494 | } |
michael@0 | 1495 | |
michael@0 | 1496 | void setSweepIndex(uint32_t index) { |
michael@0 | 1497 | if (index >= INVALID_SWEEP_INDEX) |
michael@0 | 1498 | MOZ_CRASH(); |
michael@0 | 1499 | sweepIndex_ = index; |
michael@0 | 1500 | } |
michael@0 | 1501 | void invalidateSweepIndex() { |
michael@0 | 1502 | sweepIndex_ = INVALID_SWEEP_INDEX; |
michael@0 | 1503 | } |
michael@0 | 1504 | uint32_t sweepIndex() { |
michael@0 | 1505 | JS_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX); |
michael@0 | 1506 | return sweepIndex_; |
michael@0 | 1507 | } |
michael@0 | 1508 | }; |
michael@0 | 1509 | |
michael@0 | 1510 | class RecompileInfo |
michael@0 | 1511 | { |
michael@0 | 1512 | uint32_t outputIndex; |
michael@0 | 1513 | |
michael@0 | 1514 | public: |
michael@0 | 1515 | RecompileInfo(uint32_t outputIndex = uint32_t(-1)) |
michael@0 | 1516 | : outputIndex(outputIndex) |
michael@0 | 1517 | {} |
michael@0 | 1518 | |
michael@0 | 1519 | bool operator == (const RecompileInfo &o) const { |
michael@0 | 1520 | return outputIndex == o.outputIndex; |
michael@0 | 1521 | } |
michael@0 | 1522 | CompilerOutput *compilerOutput(TypeZone &types) const; |
michael@0 | 1523 | CompilerOutput *compilerOutput(JSContext *cx) const; |
michael@0 | 1524 | bool shouldSweep(TypeZone &types); |
michael@0 | 1525 | }; |
michael@0 | 1526 | |
michael@0 | 1527 | /* Type information for a compartment. */ |
michael@0 | 1528 | struct TypeCompartment |
michael@0 | 1529 | { |
michael@0 | 1530 | /* Constraint solving worklist structures. */ |
michael@0 | 1531 | |
michael@0 | 1532 | /* Number of scripts in this compartment. */ |
michael@0 | 1533 | unsigned scriptCount; |
michael@0 | 1534 | |
michael@0 | 1535 | /* Table for referencing types of objects keyed to an allocation site. */ |
michael@0 | 1536 | AllocationSiteTable *allocationSiteTable; |
michael@0 | 1537 | |
michael@0 | 1538 | /* Tables for determining types of singleton/JSON objects. */ |
michael@0 | 1539 | |
michael@0 | 1540 | ArrayTypeTable *arrayTypeTable; |
michael@0 | 1541 | ObjectTypeTable *objectTypeTable; |
michael@0 | 1542 | |
michael@0 | 1543 | private: |
michael@0 | 1544 | void setTypeToHomogenousArray(ExclusiveContext *cx, JSObject *obj, Type type); |
michael@0 | 1545 | |
michael@0 | 1546 | public: |
michael@0 | 1547 | void fixArrayType(ExclusiveContext *cx, JSObject *obj); |
michael@0 | 1548 | void fixObjectType(ExclusiveContext *cx, JSObject *obj); |
michael@0 | 1549 | void fixRestArgumentsType(ExclusiveContext *cx, JSObject *obj); |
michael@0 | 1550 | |
michael@0 | 1551 | JSObject *newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties); |
michael@0 | 1552 | |
michael@0 | 1553 | TypeCompartment(); |
michael@0 | 1554 | ~TypeCompartment(); |
michael@0 | 1555 | |
michael@0 | 1556 | inline JSCompartment *compartment(); |
michael@0 | 1557 | |
michael@0 | 1558 | /* Prints results of this compartment if spew is enabled or force is set. */ |
michael@0 | 1559 | void print(JSContext *cx, bool force); |
michael@0 | 1560 | |
michael@0 | 1561 | /* |
michael@0 | 1562 | * Make a function or non-function object associated with an optional |
michael@0 | 1563 | * script. The 'key' parameter here may be an array, typed array, function |
michael@0 | 1564 | * or JSProto_Object to indicate a type whose class is unknown (not just |
michael@0 | 1565 | * js_ObjectClass). |
michael@0 | 1566 | */ |
michael@0 | 1567 | TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto, |
michael@0 | 1568 | TypeObjectFlags initialFlags = 0); |
michael@0 | 1569 | |
michael@0 | 1570 | /* Get or make an object for an allocation site, and add to the allocation site table. */ |
michael@0 | 1571 | TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key); |
michael@0 | 1572 | |
michael@0 | 1573 | /* Mark any type set containing obj as having a generic object type. */ |
michael@0 | 1574 | void markSetsUnknown(JSContext *cx, TypeObject *obj); |
michael@0 | 1575 | |
michael@0 | 1576 | void clearTables(); |
michael@0 | 1577 | void sweep(FreeOp *fop); |
michael@0 | 1578 | void finalizeObjects(); |
michael@0 | 1579 | |
michael@0 | 1580 | void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, |
michael@0 | 1581 | size_t *allocationSiteTables, |
michael@0 | 1582 | size_t *arrayTypeTables, |
michael@0 | 1583 | size_t *objectTypeTables); |
michael@0 | 1584 | }; |
michael@0 | 1585 | |
michael@0 | 1586 | void FixRestArgumentsType(ExclusiveContext *cxArg, JSObject *obj); |
michael@0 | 1587 | |
michael@0 | 1588 | struct TypeZone |
michael@0 | 1589 | { |
michael@0 | 1590 | JS::Zone *zone_; |
michael@0 | 1591 | |
michael@0 | 1592 | /* Pool for type information in this zone. */ |
michael@0 | 1593 | static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024; |
michael@0 | 1594 | js::LifoAlloc typeLifoAlloc; |
michael@0 | 1595 | |
michael@0 | 1596 | /* |
michael@0 | 1597 | * All Ion compilations that have occured in this zone, for indexing via |
michael@0 | 1598 | * RecompileInfo. This includes both valid and invalid compilations, though |
michael@0 | 1599 | * invalidated compilations are swept on GC. |
michael@0 | 1600 | */ |
michael@0 | 1601 | Vector<CompilerOutput> *compilerOutputs; |
michael@0 | 1602 | |
michael@0 | 1603 | /* Pending recompilations to perform before execution of JIT code can resume. */ |
michael@0 | 1604 | Vector<RecompileInfo> *pendingRecompiles; |
michael@0 | 1605 | |
michael@0 | 1606 | TypeZone(JS::Zone *zone); |
michael@0 | 1607 | ~TypeZone(); |
michael@0 | 1608 | |
michael@0 | 1609 | JS::Zone *zone() const { return zone_; } |
michael@0 | 1610 | |
michael@0 | 1611 | void sweep(FreeOp *fop, bool releaseTypes, bool *oom); |
michael@0 | 1612 | void clearAllNewScriptAddendumsOnOOM(); |
michael@0 | 1613 | |
michael@0 | 1614 | /* Mark a script as needing recompilation once inference has finished. */ |
michael@0 | 1615 | void addPendingRecompile(JSContext *cx, const RecompileInfo &info); |
michael@0 | 1616 | void addPendingRecompile(JSContext *cx, JSScript *script); |
michael@0 | 1617 | |
michael@0 | 1618 | void processPendingRecompiles(FreeOp *fop); |
michael@0 | 1619 | }; |
michael@0 | 1620 | |
michael@0 | 1621 | enum SpewChannel { |
michael@0 | 1622 | ISpewOps, /* ops: New constraints and types. */ |
michael@0 | 1623 | ISpewResult, /* result: Final type sets. */ |
michael@0 | 1624 | SPEW_COUNT |
michael@0 | 1625 | }; |
michael@0 | 1626 | |
michael@0 | 1627 | #ifdef DEBUG |
michael@0 | 1628 | |
michael@0 | 1629 | const char * InferSpewColorReset(); |
michael@0 | 1630 | const char * InferSpewColor(TypeConstraint *constraint); |
michael@0 | 1631 | const char * InferSpewColor(TypeSet *types); |
michael@0 | 1632 | |
michael@0 | 1633 | void InferSpew(SpewChannel which, const char *fmt, ...); |
michael@0 | 1634 | const char * TypeString(Type type); |
michael@0 | 1635 | const char * TypeObjectString(TypeObject *type); |
michael@0 | 1636 | |
michael@0 | 1637 | /* Check that the type property for id in obj contains value. */ |
michael@0 | 1638 | bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value); |
michael@0 | 1639 | |
michael@0 | 1640 | #else |
michael@0 | 1641 | |
michael@0 | 1642 | inline const char * InferSpewColorReset() { return nullptr; } |
michael@0 | 1643 | inline const char * InferSpewColor(TypeConstraint *constraint) { return nullptr; } |
michael@0 | 1644 | inline const char * InferSpewColor(TypeSet *types) { return nullptr; } |
michael@0 | 1645 | inline void InferSpew(SpewChannel which, const char *fmt, ...) {} |
michael@0 | 1646 | inline const char * TypeString(Type type) { return nullptr; } |
michael@0 | 1647 | inline const char * TypeObjectString(TypeObject *type) { return nullptr; } |
michael@0 | 1648 | |
michael@0 | 1649 | #endif |
michael@0 | 1650 | |
michael@0 | 1651 | /* Print a warning, dump state and abort the program. */ |
michael@0 | 1652 | MOZ_NORETURN void TypeFailure(JSContext *cx, const char *fmt, ...); |
michael@0 | 1653 | |
michael@0 | 1654 | } /* namespace types */ |
michael@0 | 1655 | } /* namespace js */ |
michael@0 | 1656 | |
michael@0 | 1657 | #endif /* jsinfer_h */ |