js/src/jsinfer.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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 */

mercurial