Bumping manifests a=b2g-bump
[gecko.git] / js / src / jsinfer.h
blob9069ce4037c0cfad761ad823ba0d9dabe747ff08
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Definitions related to javascript type inference. */
9 #ifndef jsinfer_h
10 #define jsinfer_h
12 #include "mozilla/MemoryReporting.h"
13 #include "mozilla/TypedEnum.h"
15 #include "jsalloc.h"
16 #include "jsfriendapi.h"
17 #include "jstypes.h"
19 #include "ds/IdValuePair.h"
20 #include "ds/LifoAlloc.h"
21 #include "gc/Barrier.h"
22 #include "gc/Marking.h"
23 #include "jit/IonTypes.h"
24 #include "js/UbiNode.h"
25 #include "js/Utility.h"
26 #include "js/Vector.h"
28 namespace js {
30 class TypeDescr;
32 class TaggedProto
34 public:
35 static JSObject * const LazyProto;
37 TaggedProto() : proto(nullptr) {}
38 explicit TaggedProto(JSObject* proto) : proto(proto) {}
40 uintptr_t toWord() const { return uintptr_t(proto); }
42 bool isLazy() const {
43 return proto == LazyProto;
45 bool isObject() const {
46 /* Skip nullptr and LazyProto. */
47 return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
49 JSObject* toObject() const {
50 MOZ_ASSERT(isObject());
51 return proto;
53 JSObject* toObjectOrNull() const {
54 MOZ_ASSERT(!proto || isObject());
55 return proto;
57 JSObject* raw() const { return proto; }
59 bool operator ==(const TaggedProto& other) { return proto == other.proto; }
60 bool operator !=(const TaggedProto& other) { return proto != other.proto; }
62 private:
63 JSObject* proto;
66 template <>
67 struct RootKind<TaggedProto>
69 static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
72 template <> struct GCMethods<const TaggedProto>
74 static TaggedProto initial() { return TaggedProto(); }
75 static bool poisoned(const TaggedProto& v) { return IsPoisonedPtr(v.raw()); }
78 template <> struct GCMethods<TaggedProto>
80 static TaggedProto initial() { return TaggedProto(); }
81 static bool poisoned(const TaggedProto& v) { return IsPoisonedPtr(v.raw()); }
84 template<class Outer>
85 class TaggedProtoOperations
87 const TaggedProto* value() const {
88 return static_cast<const Outer*>(this)->extract();
91 public:
92 uintptr_t toWord() const { return value()->toWord(); }
93 inline bool isLazy() const { return value()->isLazy(); }
94 inline bool isObject() const { return value()->isObject(); }
95 inline JSObject* toObject() const { return value()->toObject(); }
96 inline JSObject* toObjectOrNull() const { return value()->toObjectOrNull(); }
97 JSObject* raw() const { return value()->raw(); }
100 template <>
101 class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto> >
103 friend class TaggedProtoOperations<Handle<TaggedProto> >;
104 const TaggedProto * extract() const {
105 return static_cast<const Handle<TaggedProto>*>(this)->address();
109 template <>
110 class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto> >
112 friend class TaggedProtoOperations<Rooted<TaggedProto> >;
113 const TaggedProto* extract() const {
114 return static_cast<const Rooted<TaggedProto>*>(this)->address();
118 class CallObject;
121 * Execution Mode Overview
123 * JavaScript code can execute either sequentially or in parallel, such as in
124 * PJS. Functions which behave identically in either execution mode can take a
125 * ThreadSafeContext, and functions which have similar but not identical
126 * behavior between execution modes can be templated on the mode. Such
127 * functions use a context parameter type from ExecutionModeTraits below
128 * indicating whether they are only permitted constrained operations (such as
129 * thread safety, and side effects limited to being thread-local), or whether
130 * they can have arbitrary side effects.
133 enum ExecutionMode {
134 /* Normal JavaScript execution. */
135 SequentialExecution,
138 * JavaScript code to be executed in parallel worker threads in PJS in a
139 * fork join fashion.
141 ParallelExecution,
144 * Modes after this point are internal and are not counted in
145 * NumExecutionModes below.
149 * MIR analysis performed when invoking 'new' on a script, to determine
150 * definite properties. Used by the optimizing JIT.
152 DefinitePropertiesAnalysis,
155 * MIR analysis performed when executing a script which uses its arguments,
156 * when it is not known whether a lazy arguments value can be used.
158 ArgumentsUsageAnalysis
161 inline const char*
162 ExecutionModeString(ExecutionMode mode)
164 switch (mode) {
165 case SequentialExecution:
166 return "SequentialExecution";
167 case ParallelExecution:
168 return "ParallelExecution";
169 case DefinitePropertiesAnalysis:
170 return "DefinitePropertiesAnalysis";
171 case ArgumentsUsageAnalysis:
172 return "ArgumentsUsageAnalysis";
173 default:
174 MOZ_CRASH("Invalid ExecutionMode");
179 * Not as part of the enum so we don't get warnings about unhandled enum
180 * values.
182 static const unsigned NumExecutionModes = ParallelExecution + 1;
184 template <ExecutionMode mode>
185 struct ExecutionModeTraits
189 template <> struct ExecutionModeTraits<SequentialExecution>
191 typedef JSContext * ContextType;
192 typedef ExclusiveContext * ExclusiveContextType;
194 static inline JSContext* toContextType(ExclusiveContext* cx);
197 template <> struct ExecutionModeTraits<ParallelExecution>
199 typedef ForkJoinContext * ContextType;
200 typedef ForkJoinContext * ExclusiveContextType;
202 static inline ForkJoinContext* toContextType(ForkJoinContext* cx) { return cx; }
205 namespace jit {
206 struct IonScript;
207 class JitAllocPolicy;
208 class TempAllocator;
211 namespace types {
213 struct TypeZone;
214 class TypeSet;
215 struct TypeObjectKey;
218 * Information about a single concrete type. We pack this into a single word,
219 * where small values are particular primitive or other singleton types, and
220 * larger values are either specific JS objects or type objects.
222 class Type
224 uintptr_t data;
225 explicit Type(uintptr_t data) : data(data) {}
227 public:
229 uintptr_t raw() const { return data; }
231 bool isPrimitive() const {
232 return data < JSVAL_TYPE_OBJECT;
235 bool isPrimitive(JSValueType type) const {
236 MOZ_ASSERT(type < JSVAL_TYPE_OBJECT);
237 return (uintptr_t) type == data;
240 JSValueType primitive() const {
241 MOZ_ASSERT(isPrimitive());
242 return (JSValueType) data;
245 bool isMagicArguments() const {
246 return primitive() == JSVAL_TYPE_MAGIC;
249 bool isSomeObject() const {
250 return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
253 bool isAnyObject() const {
254 return data == JSVAL_TYPE_OBJECT;
257 bool isUnknown() const {
258 return data == JSVAL_TYPE_UNKNOWN;
261 /* Accessors for types that are either JSObject or TypeObject. */
263 bool isObject() const {
264 MOZ_ASSERT(!isAnyObject() && !isUnknown());
265 return data > JSVAL_TYPE_UNKNOWN;
268 bool isObjectUnchecked() const {
269 return data > JSVAL_TYPE_UNKNOWN;
272 inline TypeObjectKey* objectKey() const;
274 /* Accessors for JSObject types */
276 bool isSingleObject() const {
277 return isObject() && !!(data & 1);
280 inline JSObject* singleObject() const;
281 inline JSObject* singleObjectNoBarrier() const;
283 /* Accessors for TypeObject types */
285 bool isTypeObject() const {
286 return isObject() && !(data & 1);
289 inline TypeObject* typeObject() const;
290 inline TypeObject* typeObjectNoBarrier() const;
292 bool operator == (Type o) const { return data == o.data; }
293 bool operator != (Type o) const { return data != o.data; }
295 static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
296 static inline Type NullType() { return Type(JSVAL_TYPE_NULL); }
297 static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); }
298 static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); }
299 static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
300 static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
301 static inline Type SymbolType() { return Type(JSVAL_TYPE_SYMBOL); }
302 static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); }
303 static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
304 static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }
306 static inline Type PrimitiveType(JSValueType type) {
307 MOZ_ASSERT(type < JSVAL_TYPE_UNKNOWN);
308 return Type(type);
311 static inline Type ObjectType(JSObject* obj);
312 static inline Type ObjectType(TypeObject* obj);
313 static inline Type ObjectType(TypeObjectKey* obj);
315 static js::ThingRootKind rootKind() { return js::THING_ROOT_TYPE; }
318 /* Get the type of a jsval, or zero for an unknown special value. */
319 inline Type GetValueType(const Value& val);
322 * Get the type of a possibly optimized out or uninitialized let value. This
323 * generally only happens on unconditional type monitors on bailing out of
324 * Ion, such as for argument and local types.
326 inline Type GetMaybeUntrackedValueType(const Value& val);
329 * Type inference memory management overview.
331 * Type information about the values observed within scripts and about the
332 * contents of the heap is accumulated as the program executes. Compilation
333 * accumulates constraints relating type information on the heap with the
334 * compilations that should be invalidated when those types change. Type
335 * information and constraints are allocated in the zone's typeLifoAlloc,
336 * and on GC all data referring to live things is copied into a new allocator.
337 * Thus, type set and constraints only hold weak references.
341 * A constraint which listens to additions to a type set and propagates those
342 * changes to other type sets.
344 class TypeConstraint
346 public:
347 /* Next constraint listening to the same type set. */
348 TypeConstraint* next;
350 TypeConstraint()
351 : next(nullptr)
354 /* Debugging name for this kind of constraint. */
355 virtual const char* kind() = 0;
357 /* Register a new type for the set this constraint is listening to. */
358 virtual void newType(JSContext* cx, TypeSet* source, Type type) = 0;
361 * For constraints attached to an object property's type set, mark the
362 * property as having changed somehow.
364 virtual void newPropertyState(JSContext* cx, TypeSet* source) {}
367 * For constraints attached to the JSID_EMPTY type set on an object,
368 * indicate a change in one of the object's dynamic property flags or other
369 * state.
371 virtual void newObjectState(JSContext* cx, TypeObject* object) {}
374 * If the data this constraint refers to is still live, copy it into the
375 * zone's new allocator. Type constraints only hold weak references.
377 virtual bool sweep(TypeZone& zone, TypeConstraint** res) = 0;
380 /* Flags and other state stored in TypeSet::flags */
381 enum MOZ_ENUM_TYPE(uint32_t) {
382 TYPE_FLAG_UNDEFINED = 0x1,
383 TYPE_FLAG_NULL = 0x2,
384 TYPE_FLAG_BOOLEAN = 0x4,
385 TYPE_FLAG_INT32 = 0x8,
386 TYPE_FLAG_DOUBLE = 0x10,
387 TYPE_FLAG_STRING = 0x20,
388 TYPE_FLAG_SYMBOL = 0x40,
389 TYPE_FLAG_LAZYARGS = 0x80,
390 TYPE_FLAG_ANYOBJECT = 0x100,
392 /* Mask containing all primitives */
393 TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
394 TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
395 TYPE_FLAG_SYMBOL,
397 /* Mask/shift for the number of objects in objectSet */
398 TYPE_FLAG_OBJECT_COUNT_MASK = 0x3e00,
399 TYPE_FLAG_OBJECT_COUNT_SHIFT = 9,
400 TYPE_FLAG_OBJECT_COUNT_LIMIT = 7,
401 TYPE_FLAG_DOMOBJECT_COUNT_LIMIT =
402 TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
404 /* Whether the contents of this type set are totally unknown. */
405 TYPE_FLAG_UNKNOWN = 0x00004000,
407 /* Mask of normal type flags on a type set. */
408 TYPE_FLAG_BASE_MASK = 0x000041ff,
410 /* Additional flags for HeapTypeSet sets. */
413 * Whether the property has ever been deleted or reconfigured to behave
414 * differently from a plain data property, other than making the property
415 * non-writable.
417 TYPE_FLAG_NON_DATA_PROPERTY = 0x00008000,
419 /* Whether the property has ever been made non-writable. */
420 TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00010000,
422 /* Whether the property might not be constant. */
423 TYPE_FLAG_NON_CONSTANT_PROPERTY = 0x00020000,
426 * Whether the property is definitely in a particular slot on all objects
427 * from which it has not been deleted or reconfigured. For singletons
428 * this may be a fixed or dynamic slot, and for other objects this will be
429 * a fixed slot.
431 * If the property is definite, mask and shift storing the slot + 1.
432 * Otherwise these bits are clear.
434 TYPE_FLAG_DEFINITE_MASK = 0xfffc0000,
435 TYPE_FLAG_DEFINITE_SHIFT = 18
437 typedef uint32_t TypeFlags;
439 /* Flags and other state stored in TypeObject::flags */
440 enum MOZ_ENUM_TYPE(uint32_t) {
441 /* Whether this type object is associated with some allocation site. */
442 OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1,
445 * If set, the object's prototype might be in the nursery and can't be
446 * used during Ion compilation (which may be occurring off thread).
448 OBJECT_FLAG_NURSERY_PROTO = 0x2,
451 * Whether we have ensured all type sets in the compartment contain
452 * ANYOBJECT instead of this object.
454 OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x4,
456 /* Mask/shift for the number of properties in propertySet */
457 OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff8,
458 OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 3,
459 OBJECT_FLAG_PROPERTY_COUNT_LIMIT =
460 OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
462 /* Whether any objects this represents may have sparse indexes. */
463 OBJECT_FLAG_SPARSE_INDEXES = 0x00010000,
465 /* Whether any objects this represents may not have packed dense elements. */
466 OBJECT_FLAG_NON_PACKED = 0x00020000,
469 * Whether any objects this represents may be arrays whose length does not
470 * fit in an int32.
472 OBJECT_FLAG_LENGTH_OVERFLOW = 0x00040000,
474 /* Whether any objects have been iterated over. */
475 OBJECT_FLAG_ITERATED = 0x00080000,
477 /* For a global object, whether flags were set on the RegExpStatics. */
478 OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00100000,
481 * For the function on a run-once script, whether the function has actually
482 * run multiple times.
484 OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000,
487 * For a global object, whether any array buffers in this compartment with
488 * typed object views have been neutered.
490 OBJECT_FLAG_TYPED_OBJECT_NEUTERED = 0x00400000,
493 * Whether objects with this type should be allocated directly in the
494 * tenured heap.
496 OBJECT_FLAG_PRE_TENURE = 0x00800000,
498 /* Whether objects with this type might have copy on write elements. */
499 OBJECT_FLAG_COPY_ON_WRITE = 0x01000000,
502 * Whether all properties of this object are considered unknown.
503 * If set, all other flags in DYNAMIC_MASK will also be set.
505 OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x02000000,
507 /* Flags which indicate dynamic properties of represented objects. */
508 OBJECT_FLAG_DYNAMIC_MASK = 0x03ff0000,
510 /* Mask for objects created with unknown properties. */
511 OBJECT_FLAG_UNKNOWN_MASK =
512 OBJECT_FLAG_DYNAMIC_MASK
513 | OBJECT_FLAG_SETS_MARKED_UNKNOWN,
515 // Mask/shift for the kind of addendum attached to this type object.
516 OBJECT_FLAG_ADDENDUM_MASK = 0x04000000,
517 OBJECT_FLAG_ADDENDUM_SHIFT = 26,
519 // Mask/shift for this type object's generation. If out of sync with the
520 // TypeZone's generation, this TypeObject hasn't been swept yet.
521 OBJECT_FLAG_GENERATION_MASK = 0x08000000,
522 OBJECT_FLAG_GENERATION_SHIFT = 27,
524 typedef uint32_t TypeObjectFlags;
526 class StackTypeSet;
527 class HeapTypeSet;
528 class TemporaryTypeSet;
531 * Information about the set of types associated with an lvalue. There are
532 * three kinds of type sets:
534 * - StackTypeSet are associated with TypeScripts, for arguments and values
535 * observed at property reads. These are implicitly frozen on compilation
536 * and do not have constraints attached to them.
538 * - HeapTypeSet are associated with the properties of TypeObjects. These
539 * may have constraints added to them to trigger invalidation of compiled
540 * code.
542 * - TemporaryTypeSet are created during compilation and do not outlive
543 * that compilation.
545 class TypeSet
547 protected:
548 /* Flags for this type set. */
549 TypeFlags flags;
551 /* Possible objects this type set can represent. */
552 TypeObjectKey** objectSet;
554 public:
556 TypeSet()
557 : flags(0), objectSet(nullptr)
560 void print();
562 /* Whether this set contains a specific type. */
563 inline bool hasType(Type type) const;
565 TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
566 bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
567 bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
568 bool empty() const { return !baseFlags() && !baseObjectCount(); }
570 bool hasAnyFlag(TypeFlags flags) const {
571 MOZ_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
572 return !!(baseFlags() & flags);
575 bool nonDataProperty() const {
576 return flags & TYPE_FLAG_NON_DATA_PROPERTY;
578 bool nonWritableProperty() const {
579 return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
581 bool nonConstantProperty() const {
582 return flags & TYPE_FLAG_NON_CONSTANT_PROPERTY;
584 bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
585 unsigned definiteSlot() const {
586 MOZ_ASSERT(definiteProperty());
587 return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
590 /* Join two type sets into a new set. The result should not be modified further. */
591 static TemporaryTypeSet* unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc);
592 /* Return the intersection of the 2 TypeSets. The result should not be modified further */
593 static TemporaryTypeSet* intersectSets(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
595 /* Add a type to this set using the specified allocator. */
596 void addType(Type type, LifoAlloc* alloc);
598 /* Get a list of all types in this set. */
599 typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
600 bool enumerateTypes(TypeList* list);
603 * Iterate through the objects in this set. getObjectCount overapproximates
604 * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
605 * may return nullptr.
607 inline unsigned getObjectCount() const;
608 inline TypeObjectKey* getObject(unsigned i) const;
609 inline JSObject* getSingleObject(unsigned i) const;
610 inline TypeObject* getTypeObject(unsigned i) const;
611 inline JSObject* getSingleObjectNoBarrier(unsigned i) const;
612 inline TypeObject* getTypeObjectNoBarrier(unsigned i) const;
614 /* The Class of an object in this set. */
615 inline const Class* getObjectClass(unsigned i) const;
617 bool canSetDefinite(unsigned slot) {
618 // Note: the cast is required to work around an MSVC issue.
619 return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
621 void setDefinite(unsigned slot) {
622 MOZ_ASSERT(canSetDefinite(slot));
623 flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
624 MOZ_ASSERT(definiteSlot() == slot);
627 /* Whether any values in this set might have the specified type. */
628 bool mightBeMIRType(jit::MIRType type);
630 /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
631 bool isDOMClass();
634 * Get whether this type set is known to be a subset of other.
635 * This variant doesn't freeze constraints. That variant is called knownSubset
637 bool isSubset(const TypeSet* other) const;
640 * Get whether the objects in this TypeSet are a subset of the objects
641 * in other.
643 bool objectsAreSubset(TypeSet* other);
645 /* Whether this TypeSet contains exactly the same types as other. */
646 bool equals(const TypeSet* other) const {
647 return this->isSubset(other) && other->isSubset(this);
650 /* Forward all types in this set to the specified constraint. */
651 bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint);
653 // Clone a type set into an arbitrary allocator.
654 TemporaryTypeSet* clone(LifoAlloc* alloc) const;
655 bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const;
657 // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
658 TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
659 // Create a new TemporaryTypeSet where the type has been set to object.
660 TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc);
661 TemporaryTypeSet* cloneWithoutObjects(LifoAlloc* alloc);
663 // Trigger a read barrier on all the contents of a type set.
664 static void readBarrier(const TypeSet* types);
666 protected:
667 uint32_t baseObjectCount() const {
668 return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
670 inline void setBaseObjectCount(uint32_t count);
672 void clearObjects();
675 // If there is an OOM while sweeping types, the type information is deoptimized
676 // so that it stays correct (i.e. overapproximates the possible types in the
677 // zone), but constraints might not have been triggered on the deoptimization
678 // or even copied over completely. In this case, destroy all JIT code and new
679 // script information in the zone, the only things whose correctness depends on
680 // the type constraints.
681 class AutoClearTypeInferenceStateOnOOM
683 Zone* zone;
684 bool oom;
686 public:
687 explicit AutoClearTypeInferenceStateOnOOM(Zone* zone)
688 : zone(zone), oom(false)
691 ~AutoClearTypeInferenceStateOnOOM();
693 void setOOM() {
694 oom = true;
698 /* Superclass common to stack and heap type sets. */
699 class ConstraintTypeSet : public TypeSet
701 public:
702 /* Chain of constraints which propagate changes out from this type set. */
703 TypeConstraint* constraintList;
705 ConstraintTypeSet() : constraintList(nullptr) {}
708 * Add a type to this set, calling any constraint handlers if this is a new
709 * possible type.
711 void addType(ExclusiveContext* cx, Type type);
713 /* Add a new constraint to this set. */
714 bool addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting = true);
716 inline void sweep(JS::Zone* zone, AutoClearTypeInferenceStateOnOOM& oom);
719 class StackTypeSet : public ConstraintTypeSet
721 public:
724 class HeapTypeSet : public ConstraintTypeSet
726 inline void newPropertyState(ExclusiveContext* cx);
728 public:
729 /* Mark this type set as representing a non-data property. */
730 inline void setNonDataProperty(ExclusiveContext* cx);
731 inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC.
733 /* Mark this type set as representing a non-writable property. */
734 inline void setNonWritableProperty(ExclusiveContext* cx);
736 // Mark this type set as being non-constant.
737 inline void setNonConstantProperty(ExclusiveContext* cx);
740 class CompilerConstraintList;
742 CompilerConstraintList*
743 NewCompilerConstraintList(jit::TempAllocator& alloc);
745 class TemporaryTypeSet : public TypeSet
747 public:
748 TemporaryTypeSet() {}
749 TemporaryTypeSet(LifoAlloc* alloc, Type type);
751 TemporaryTypeSet(uint32_t flags, TypeObjectKey** objectSet) {
752 this->flags = flags;
753 this->objectSet = objectSet;
757 * Constraints for JIT compilation.
759 * Methods for JIT compilation. These must be used when a script is
760 * currently being compiled (see AutoEnterCompilation) and will add
761 * constraints ensuring that if the return value change in the future due
762 * to new type information, the script's jitcode will be discarded.
765 /* Get any type tag which all values in this set must have. */
766 jit::MIRType getKnownMIRType();
768 bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; }
770 /* Whether this value may be an object. */
771 bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
774 * Whether this typeset represents a potentially sentineled object value:
775 * the value may be an object or null or undefined.
776 * Returns false if the value cannot ever be an object.
778 bool objectOrSentinel() {
779 TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
780 if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
781 return false;
783 return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
786 /* Whether the type set contains objects with any of a set of flags. */
787 bool hasObjectFlags(CompilerConstraintList* constraints, TypeObjectFlags flags);
789 /* Get the class shared by all objects in this set, or nullptr. */
790 const Class* getKnownClass();
792 /* Result returned from forAllClasses */
793 enum ForAllResult {
794 EMPTY=1, // Set empty
795 ALL_TRUE, // Set not empty and predicate returned true for all classes
796 ALL_FALSE, // Set not empty and predicate returned false for all classes
797 MIXED, // Set not empty and predicate returned false for some classes
798 // and true for others, or set contains an unknown or non-object
799 // type
802 /* Apply func to the members of the set and return an appropriate result.
803 * The iteration may end early if the result becomes known early.
805 ForAllResult forAllClasses(bool (*func)(const Class* clasp));
807 /* Get the prototype shared by all objects in this set, or nullptr. */
808 JSObject* getCommonPrototype();
810 /* Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType. */
811 Scalar::Type getTypedArrayType();
813 /* Get the shared typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType. */
814 Scalar::Type getSharedTypedArrayType();
816 /* Whether clasp->isCallable() is true for one or more objects in this set. */
817 bool maybeCallable();
819 /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
820 bool maybeEmulatesUndefined();
822 /* Get the single value which can appear in this type set, otherwise nullptr. */
823 JSObject* getSingleton();
825 /* Whether any objects in the type set needs a barrier on id. */
826 bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id);
829 * Whether this set contains all types in other, except (possibly) the
830 * specified type.
832 bool filtersType(const TemporaryTypeSet* other, Type type) const;
834 enum DoubleConversion {
835 /* All types in the set should use eager double conversion. */
836 AlwaysConvertToDoubles,
838 /* Some types in the set should use eager double conversion. */
839 MaybeConvertToDoubles,
841 /* No types should use eager double conversion. */
842 DontConvertToDoubles,
844 /* Some types should use eager double conversion, others cannot. */
845 AmbiguousDoubleConversion
849 * Whether known double optimizations are possible for element accesses on
850 * objects in this type set.
852 DoubleConversion convertDoubleElements(CompilerConstraintList* constraints);
855 bool
856 AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, TypeObject* type, HandleId id);
858 bool
859 AddClearDefiniteFunctionUsesInScript(JSContext* cx, TypeObject* type,
860 JSScript* script, JSScript* calleeScript);
862 /* Is this a reasonable PC to be doing inlining on? */
863 inline bool isInlinableCall(jsbytecode* pc);
865 /* Type information about a property. */
866 struct Property
868 /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
869 HeapId id;
871 /* Possible types for this property, including types inherited from prototypes. */
872 HeapTypeSet types;
874 explicit Property(jsid id)
875 : id(id)
878 Property(const Property& o)
879 : id(o.id.get()), types(o.types)
882 static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
883 static jsid getKey(Property* p) { return p->id; }
886 // New script properties analyses overview.
888 // When constructing objects using 'new' on a script, we attempt to determine
889 // the properties which that object will eventually have. This is done via two
890 // analyses. One of these, the definite properties analysis, is static, and the
891 // other, the acquired properties analysis, is dynamic. As objects are
892 // constructed using 'new' on some script to create objects of type T, our
893 // analysis strategy is as follows:
895 // - When the first objects are created, no analysis is immediately performed.
896 // Instead, all objects of type T are accumulated in an array.
898 // - After a certain number of such objects have been created, the definite
899 // properties analysis is performed. This analyzes the body of the
900 // constructor script and any other functions it calls to look for properties
901 // which will definitely be added by the constructor in a particular order,
902 // creating an object with shape S.
904 // - The properties in S are compared with the greatest common prefix P of the
905 // shapes of the objects that have been created. If P has more properties
906 // than S, the acquired properties analysis is performed.
908 // - The acquired properties analysis marks all properties in P as definite
909 // in T, and creates a new type object IT for objects which are partially
910 // initialized. Objects of type IT are initially created with shape S, and if
911 // they are later given shape P, their type can be changed to T.
913 // For objects which are rarely created, the definite properties analysis can
914 // be triggered after only one or a few objects have been allocated, when code
915 // being Ion compiled might access them. In this case type information in the
916 // constructor might not be good enough for the definite properties analysis to
917 // compute useful information, but the acquired properties analysis will still
918 // be able to identify definite properties in this case.
920 // This layered approach is designed to maximize performance on easily
921 // analyzable code, while still allowing us to determine definite properties
922 // robustly when code consistently adds the same properties to objects, but in
923 // complex ways which can't be understood statically.
924 class TypeNewScript
926 public:
927 struct Initializer {
928 enum Kind {
929 SETPROP,
930 SETPROP_FRAME,
931 DONE
932 } kind;
933 uint32_t offset;
934 Initializer(Kind kind, uint32_t offset)
935 : kind(kind), offset(offset)
939 private:
940 // Scripted function which this information was computed for.
941 // If instances of the associated type object are created without calling
942 // 'new' on this function, the new script information is cleared.
943 RelocatablePtrFunction fun;
945 // If fewer than PRELIMINARY_OBJECT_COUNT instances of the type are
946 // created, this array holds pointers to each of those objects. When the
947 // threshold has been reached, the definite and acquired properties
948 // analyses are performed and this array is cleared. The pointers in this
949 // array are weak.
950 static const uint32_t PRELIMINARY_OBJECT_COUNT = 20;
951 PlainObject** preliminaryObjects;
953 // After the new script properties analyses have been performed, a template
954 // object to use for newly constructed objects. The shape of this object
955 // reflects all definite properties the object will have, and the
956 // allocation kind to use. Note that this is actually a PlainObject, but is
957 // JSObject here to avoid cyclic include dependencies.
958 RelocatablePtrPlainObject templateObject_;
960 // Order in which definite properties become initialized. We need this in
961 // case the definite properties are invalidated (such as by adding a setter
962 // to an object on the prototype chain) while an object is in the middle of
963 // being initialized, so we can walk the stack and fixup any objects which
964 // look for in-progress objects which were prematurely set with an incorrect
965 // shape. Property assignments in inner frames are preceded by a series of
966 // SETPROP_FRAME entries specifying the stack down to the frame containing
967 // the write.
968 Initializer* initializerList;
970 // If there are additional properties found by the acquired properties
971 // analysis which were not found by the definite properties analysis, this
972 // shape contains all such additional properties (plus the definite
973 // properties). When an object of this type acquires this shape, it is
974 // fully initialized and its type can be changed to initializedType.
975 RelocatablePtrShape initializedShape_;
977 // Type object with definite properties set for all properties found by
978 // both the definite and acquired properties analyses.
979 RelocatablePtrTypeObject initializedType_;
981 public:
982 TypeNewScript() { mozilla::PodZero(this); }
983 ~TypeNewScript() {
984 js_free(preliminaryObjects);
985 js_free(initializerList);
988 static inline void writeBarrierPre(TypeNewScript* newScript);
990 bool analyzed() const {
991 if (preliminaryObjects) {
992 MOZ_ASSERT(!templateObject());
993 MOZ_ASSERT(!initializerList);
994 MOZ_ASSERT(!initializedShape());
995 MOZ_ASSERT(!initializedType());
996 return false;
998 MOZ_ASSERT(templateObject());
999 return true;
1002 PlainObject* templateObject() const {
1003 return templateObject_;
1006 Shape* initializedShape() const {
1007 return initializedShape_;
1010 TypeObject* initializedType() const {
1011 return initializedType_;
1014 void trace(JSTracer* trc);
1015 void sweep();
1017 #ifdef JSGC_COMPACTING
1018 void fixupAfterMovingGC();
1019 #endif
1021 void registerNewObject(PlainObject* res);
1022 void unregisterNewObject(PlainObject* res);
1023 bool maybeAnalyze(JSContext* cx, TypeObject* type, bool* regenerate, bool force = false);
1025 void rollbackPartiallyInitializedObjects(JSContext* cx, TypeObject* type);
1027 static void make(JSContext* cx, TypeObject* type, JSFunction* fun);
1031 * Lazy type objects overview.
1033 * Type objects which represent at most one JS object are constructed lazily.
1034 * These include types for native functions, standard classes, scripted
1035 * functions defined at the top level of global/eval scripts, and in some
1036 * other cases. Typical web workloads often create many windows (and many
1037 * copies of standard natives) and many scripts, with comparatively few
1038 * non-singleton types.
1040 * We can recover the type information for the object from examining it,
1041 * so don't normally track the possible types of its properties as it is
1042 * updated. Property type sets for the object are only constructed when an
1043 * analyzed script attaches constraints to it: the script is querying that
1044 * property off the object or another which delegates to it, and the analysis
1045 * information is sensitive to changes in the property's type. Future changes
1046 * to the property (whether those uncovered by analysis or those occurring
1047 * in the VM) will treat these properties like those of any other type object.
1050 /* Type information about an object accessed by a script. */
1051 struct TypeObject : public gc::TenuredCell
1053 private:
1054 /* Class shared by object using this type. */
1055 const Class* clasp_;
1057 /* Prototype shared by objects using this type. */
1058 HeapPtrObject proto_;
1061 * Whether there is a singleton JS object with this type. That JS object
1062 * must appear in type sets instead of this; we include the back reference
1063 * here to allow reverting the JS object to a lazy type.
1065 HeapPtrObject singleton_;
1067 public:
1069 const Class* clasp() const {
1070 return clasp_;
1073 void setClasp(const Class* clasp) {
1074 MOZ_ASSERT(singleton());
1075 clasp_ = clasp;
1078 TaggedProto proto() const {
1079 return TaggedProto(proto_);
1082 JSObject* singleton() const {
1083 return singleton_;
1086 // For use during marking, don't call otherwise.
1087 HeapPtrObject& protoRaw() { return proto_; }
1088 HeapPtrObject& singletonRaw() { return singleton_; }
1090 void setProto(JSContext* cx, TaggedProto proto);
1091 void setProtoUnchecked(TaggedProto proto) {
1092 proto_ = proto.raw();
1095 void initSingleton(JSObject* singleton) {
1096 singleton_ = singleton;
1100 * Value held by singleton if this is a standin type for a singleton JS
1101 * object whose type has not been constructed yet.
1103 static const size_t LAZY_SINGLETON = 1;
1104 bool lazy() const { return singleton() == (JSObject*) LAZY_SINGLETON; }
1106 private:
1107 /* Flags for this object. */
1108 TypeObjectFlags flags_;
1110 enum AddendumKind {
1111 Addendum_NewScript,
1112 Addendum_TypeDescr
1115 // If non-null, holds additional information about this object, whose
1116 // format is indicated by the object's addendum kind.
1117 void* addendum_;
1119 void setAddendum(AddendumKind kind, void* addendum);
1121 AddendumKind addendumKind() const {
1122 return (AddendumKind)
1123 ((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT);
1126 TypeNewScript* newScriptDontCheckGeneration() const {
1127 return addendumKind() == Addendum_NewScript
1128 ? reinterpret_cast<TypeNewScript*>(addendum_)
1129 : nullptr;
1132 public:
1134 TypeObjectFlags flags() {
1135 maybeSweep(nullptr);
1136 return flags_;
1139 void addFlags(TypeObjectFlags flags) {
1140 maybeSweep(nullptr);
1141 flags_ |= flags;
1144 void clearFlags(TypeObjectFlags flags) {
1145 maybeSweep(nullptr);
1146 flags_ &= ~flags;
1149 TypeNewScript* newScript() {
1150 maybeSweep(nullptr);
1151 return newScriptDontCheckGeneration();
1154 void setNewScript(TypeNewScript* newScript) {
1155 setAddendum(Addendum_NewScript, newScript);
1158 TypeDescr* maybeTypeDescr() {
1159 // Note: there is no need to sweep when accessing the type descriptor
1160 // of an object, as it is strongly held and immutable.
1161 if (addendumKind() == Addendum_TypeDescr)
1162 return reinterpret_cast<TypeDescr*>(addendum_);
1163 return nullptr;
1166 TypeDescr& typeDescr() {
1167 MOZ_ASSERT(addendumKind() == Addendum_TypeDescr);
1168 return *maybeTypeDescr();
1171 void setTypeDescr(TypeDescr* descr) {
1172 setAddendum(Addendum_TypeDescr, descr);
1175 private:
1177 * Properties of this object. This may contain JSID_VOID, representing the
1178 * types of all integer indexes of the object, and/or JSID_EMPTY, holding
1179 * constraints listening to changes to the object's state.
1181 * The type sets in the properties of a type object describe the possible
1182 * values that can be read out of that property in actual JS objects.
1183 * In native objects, property types account for plain data properties
1184 * (those with a slot and no getter or setter hook) and dense elements.
1185 * In typed objects, property types account for object and value properties
1186 * and elements in the object.
1188 * For accesses on these properties, the correspondence is as follows:
1190 * 1. If the type has unknownProperties(), the possible properties and
1191 * value types for associated JSObjects are unknown.
1193 * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
1194 * which is a property in obj, before obj->getProperty(id) the property
1195 * in type for id must reflect the result of the getProperty.
1197 * There are several exceptions to this:
1199 * 1. For properties of global JS objects which are undefined at the point
1200 * where the property was (lazily) generated, the property type set will
1201 * remain empty, and the 'undefined' type will only be added after a
1202 * subsequent assignment or deletion. After these properties have been
1203 * assigned a defined value, the only way they can become undefined
1204 * again is after such an assign or deletion.
1206 * 2. Array lengths are special cased by the compiler and VM and are not
1207 * reflected in property types.
1209 * 3. In typed objects, the initial values of properties (null pointers and
1210 * undefined values) are not reflected in the property types. These
1211 * values are always possible when reading the property.
1213 * We establish these by using write barriers on calls to setProperty and
1214 * defineProperty which are on native properties, and on any jitcode which
1215 * might update the property with a new type.
1217 Property** propertySet;
1218 public:
1220 /* If this is an interpreted function, the function object. */
1221 HeapPtrFunction interpretedFunction;
1223 #if JS_BITS_PER_WORD == 32
1224 uint32_t padding;
1225 #endif
1227 inline TypeObject(const Class* clasp, TaggedProto proto, TypeObjectFlags initialFlags);
1229 bool hasAnyFlags(TypeObjectFlags flags) {
1230 MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
1231 return !!(this->flags() & flags);
1233 bool hasAllFlags(TypeObjectFlags flags) {
1234 MOZ_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
1235 return (this->flags() & flags) == flags;
1238 bool unknownProperties() {
1239 MOZ_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
1240 hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
1241 return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
1244 bool shouldPreTenure() {
1245 return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties();
1248 bool hasTenuredProto() {
1249 return !(flags() & OBJECT_FLAG_NURSERY_PROTO);
1252 gc::InitialHeap initialHeap(CompilerConstraintList* constraints);
1254 bool canPreTenure() {
1255 return !unknownProperties();
1258 bool fromAllocationSite() {
1259 return flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE;
1262 void setShouldPreTenure(ExclusiveContext* cx) {
1263 MOZ_ASSERT(canPreTenure());
1264 setFlags(cx, OBJECT_FLAG_PRE_TENURE);
1268 * Get or create a property of this object. Only call this for properties which
1269 * a script accesses explicitly.
1271 inline HeapTypeSet* getProperty(ExclusiveContext* cx, jsid id);
1273 /* Get a property only if it already exists. */
1274 inline HeapTypeSet* maybeGetProperty(jsid id);
1276 inline unsigned getPropertyCount();
1277 inline Property* getProperty(unsigned i);
1279 /* Helpers */
1281 void updateNewPropertyTypes(ExclusiveContext* cx, jsid id, HeapTypeSet* types);
1282 bool addDefiniteProperties(ExclusiveContext* cx, Shape* shape);
1283 bool matchDefiniteProperties(HandleObject obj);
1284 void addPrototype(JSContext* cx, TypeObject* proto);
1285 void markPropertyNonData(ExclusiveContext* cx, jsid id);
1286 void markPropertyNonWritable(ExclusiveContext* cx, jsid id);
1287 void markStateChange(ExclusiveContext* cx);
1288 void setFlags(ExclusiveContext* cx, TypeObjectFlags flags);
1289 void markUnknown(ExclusiveContext* cx);
1290 void maybeClearNewScriptOnOOM();
1291 void clearNewScript(ExclusiveContext* cx);
1292 bool isPropertyNonData(jsid id);
1293 bool isPropertyNonWritable(jsid id);
1295 void print();
1297 inline void clearProperties();
1298 void maybeSweep(AutoClearTypeInferenceStateOnOOM* oom);
1300 private:
1301 #ifdef DEBUG
1302 bool needsSweep();
1303 #endif
1305 uint32_t generation() {
1306 return (flags_ & OBJECT_FLAG_GENERATION_MASK) >> OBJECT_FLAG_GENERATION_SHIFT;
1309 public:
1310 void setGeneration(uint32_t generation) {
1311 MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT));
1312 flags_ &= ~OBJECT_FLAG_GENERATION_MASK;
1313 flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT;
1316 #ifdef JSGC_COMPACTING
1317 void fixupAfterMovingGC();
1318 #endif
1320 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
1322 inline void finalize(FreeOp* fop);
1324 static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
1326 static inline uint32_t offsetOfClasp() {
1327 return offsetof(TypeObject, clasp_);
1330 static inline uint32_t offsetOfProto() {
1331 return offsetof(TypeObject, proto_);
1334 static inline uint32_t offsetOfAddendum() {
1335 return offsetof(TypeObject, addendum_);
1338 static inline uint32_t offsetOfFlags() {
1339 return offsetof(TypeObject, flags_);
1342 private:
1343 inline uint32_t basePropertyCount();
1344 inline void setBasePropertyCount(uint32_t count);
1346 static void staticAsserts() {
1347 JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto));
1352 * Entries for the per-compartment set of type objects which are the default
1353 * types to use for some prototype. An optional associated object is used which
1354 * allows multiple type objects to be created with the same prototype. The
1355 * associated object may be a function (for types constructed with 'new') or a
1356 * type descriptor (for typed objects). These entries are also used for the set
1357 * of lazy type objects in the compartment, which use a null associated object
1358 * (though there are only a few of these per compartment).
1360 struct NewTypeObjectEntry
1362 ReadBarrieredTypeObject object;
1364 // Note: This pointer is only used for equality and does not need a read barrier.
1365 JSObject* associated;
1367 NewTypeObjectEntry(TypeObject* object, JSObject* associated)
1368 : object(object), associated(associated)
1371 struct Lookup {
1372 const Class* clasp;
1373 TaggedProto hashProto;
1374 TaggedProto matchProto;
1375 JSObject* associated;
1377 Lookup(const Class* clasp, TaggedProto proto, JSObject* associated)
1378 : clasp(clasp), hashProto(proto), matchProto(proto), associated(associated)
1382 * For use by generational post barriers only. Look up an entry whose
1383 * proto has been moved, but was hashed with the original value.
1385 Lookup(const Class* clasp, TaggedProto hashProto, TaggedProto matchProto, JSObject* associated)
1386 : clasp(clasp), hashProto(hashProto), matchProto(matchProto), associated(associated)
1391 static inline HashNumber hash(const Lookup& lookup);
1392 static inline bool match(const NewTypeObjectEntry& key, const Lookup& lookup);
1393 static void rekey(NewTypeObjectEntry& k, const NewTypeObjectEntry& newKey) { k = newKey; }
1395 typedef HashSet<NewTypeObjectEntry, NewTypeObjectEntry, SystemAllocPolicy> NewTypeObjectTable;
1397 /* Whether to use a new type object when calling 'new' at script/pc. */
1398 bool
1399 UseNewType(JSContext* cx, JSScript* script, jsbytecode* pc);
1401 bool
1402 UseNewTypeForClone(JSFunction* fun);
1405 * Whether Array.prototype, or an object on its proto chain, has an
1406 * indexed property.
1408 bool
1409 ArrayPrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSScript* script);
1411 /* Whether obj or any of its prototypes have an indexed property. */
1412 bool
1413 TypeCanHaveExtraIndexedProperties(CompilerConstraintList* constraints, TemporaryTypeSet* types);
1415 /* Persistent type information for a script, retained across GCs. */
1416 class TypeScript
1418 friend class ::JSScript;
1420 // Variable-size array
1421 StackTypeSet typeArray_[1];
1423 public:
1424 /* Array of type sets for variables and JOF_TYPESET ops. */
1425 StackTypeSet* typeArray() const {
1426 // Ensure typeArray_ is the last data member of TypeScript.
1427 JS_STATIC_ASSERT(sizeof(TypeScript) ==
1428 sizeof(typeArray_) + offsetof(TypeScript, typeArray_));
1429 return const_cast<StackTypeSet*>(typeArray_);
1432 static inline size_t SizeIncludingTypeArray(size_t arraySize) {
1433 // Ensure typeArray_ is the last data member of TypeScript.
1434 JS_STATIC_ASSERT(sizeof(TypeScript) ==
1435 sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_));
1436 return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet);
1439 static inline unsigned NumTypeSets(JSScript* script);
1441 static inline StackTypeSet* ThisTypes(JSScript* script);
1442 static inline StackTypeSet* ArgTypes(JSScript* script, unsigned i);
1444 /* Get the type set for values observed at an opcode. */
1445 static inline StackTypeSet* BytecodeTypes(JSScript* script, jsbytecode* pc);
1447 template <typename TYPESET>
1448 static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc, uint32_t* bytecodeMap,
1449 uint32_t* hint, TYPESET* typeArray);
1451 /* Get a type object for an allocation site in this script. */
1452 static inline TypeObject* InitObject(JSContext* cx, JSScript* script, jsbytecode* pc,
1453 JSProtoKey kind);
1456 * Monitor a bytecode pushing any value. This must be called for any opcode
1457 * which is JOF_TYPESET, and where either the script has not been analyzed
1458 * by type inference or where the pc has type barriers. For simplicity, we
1459 * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
1460 * and only look at barriers when generating JIT code for the script.
1462 static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
1463 const js::Value& val);
1464 static inline void Monitor(JSContext* cx, const js::Value& rval);
1466 /* Monitor an assignment at a SETELEM on a non-integer identifier. */
1467 static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
1469 /* Add a type for a variable in a script. */
1470 static inline void SetThis(JSContext* cx, JSScript* script, Type type);
1471 static inline void SetThis(JSContext* cx, JSScript* script, const js::Value& value);
1472 static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg, Type type);
1473 static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
1474 const js::Value& value);
1477 * Freeze all the stack type sets in a script, for a compilation. Returns
1478 * copies of the type sets which will be checked against the actual ones
1479 * under FinishCompilation, to detect any type changes.
1481 static bool FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script,
1482 TemporaryTypeSet** pThisTypes,
1483 TemporaryTypeSet** pArgTypes,
1484 TemporaryTypeSet** pBytecodeTypes);
1486 static void Purge(JSContext* cx, HandleScript script);
1488 void destroy();
1490 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
1491 return mallocSizeOf(this);
1494 #ifdef DEBUG
1495 void printTypes(JSContext* cx, HandleScript script) const;
1496 #endif
1499 void
1500 FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap);
1502 ArrayObject*
1503 GetOrFixupCopyOnWriteObject(JSContext* cx, HandleScript script, jsbytecode* pc);
1505 ArrayObject*
1506 GetCopyOnWriteObject(JSScript* script, jsbytecode* pc);
1508 class RecompileInfo;
1510 // Allocate a CompilerOutput for a finished compilation and generate the type
1511 // constraints for the compilation. Returns whether the type constraints
1512 // still hold.
1513 bool
1514 FinishCompilation(JSContext* cx, HandleScript script, ExecutionMode executionMode,
1515 CompilerConstraintList* constraints, RecompileInfo* precompileInfo);
1517 // Update the actual types in any scripts queried by constraints with any
1518 // speculative types added during the definite properties analysis.
1519 void
1520 FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints);
1522 struct ArrayTableKey;
1523 typedef HashMap<ArrayTableKey,
1524 ReadBarrieredTypeObject,
1525 ArrayTableKey,
1526 SystemAllocPolicy> ArrayTypeTable;
1528 struct ObjectTableKey;
1529 struct ObjectTableEntry;
1530 typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
1532 struct AllocationSiteKey;
1533 typedef HashMap<AllocationSiteKey,
1534 ReadBarrieredTypeObject,
1535 AllocationSiteKey,
1536 SystemAllocPolicy> AllocationSiteTable;
1538 class HeapTypeSetKey;
1540 // Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
1541 struct TypeObjectKey
1543 static intptr_t keyBits(TypeObjectKey* obj) { return (intptr_t) obj; }
1544 static TypeObjectKey* getKey(TypeObjectKey* obj) { return obj; }
1546 static TypeObjectKey* get(JSObject* obj) {
1547 MOZ_ASSERT(obj);
1548 return (TypeObjectKey*) (uintptr_t(obj) | 1);
1550 static TypeObjectKey* get(TypeObject* obj) {
1551 MOZ_ASSERT(obj);
1552 return (TypeObjectKey*) obj;
1555 bool isTypeObject() {
1556 return (uintptr_t(this) & 1) == 0;
1558 bool isSingleObject() {
1559 return (uintptr_t(this) & 1) != 0;
1562 inline TypeObject* asTypeObject();
1563 inline JSObject* asSingleObject();
1565 inline TypeObject* asTypeObjectNoBarrier();
1566 inline JSObject* asSingleObjectNoBarrier();
1568 const Class* clasp();
1569 TaggedProto proto();
1570 bool hasTenuredProto();
1571 JSObject* singleton();
1572 TypeNewScript* newScript();
1574 bool unknownProperties();
1575 bool hasFlags(CompilerConstraintList* constraints, TypeObjectFlags flags);
1576 void watchStateChangeForInlinedCall(CompilerConstraintList* constraints);
1577 void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
1578 HeapTypeSetKey property(jsid id);
1579 void ensureTrackedProperty(JSContext* cx, jsid id);
1581 TypeObject* maybeType();
1584 // Representation of a heap type property which may or may not be instantiated.
1585 // Heap properties for singleton types are instantiated lazily as they are used
1586 // by the compiler, but this is only done on the main thread. If we are
1587 // compiling off thread and use a property which has not yet been instantiated,
1588 // it will be treated as empty and non-configured and will be instantiated when
1589 // rejoining to the main thread. If it is in fact not empty, the compilation
1590 // will fail; to avoid this, we try to instantiate singleton property types
1591 // during generation of baseline caches.
1592 class HeapTypeSetKey
1594 friend struct TypeObjectKey;
1596 // Object and property being accessed.
1597 TypeObjectKey* object_;
1598 jsid id_;
1600 // If instantiated, the underlying heap type set.
1601 HeapTypeSet* maybeTypes_;
1603 public:
1604 HeapTypeSetKey()
1605 : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
1608 TypeObjectKey* object() const { return object_; }
1609 jsid id() const { return id_; }
1610 HeapTypeSet* maybeTypes() const { return maybeTypes_; }
1612 bool instantiate(JSContext* cx);
1614 void freeze(CompilerConstraintList* constraints);
1615 jit::MIRType knownMIRType(CompilerConstraintList* constraints);
1616 bool nonData(CompilerConstraintList* constraints);
1617 bool nonWritable(CompilerConstraintList* constraints);
1618 bool isOwnProperty(CompilerConstraintList* constraints, bool allowEmptyTypesForGlobal = false);
1619 bool knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other);
1620 JSObject* singleton(CompilerConstraintList* constraints);
1621 bool needsBarrier(CompilerConstraintList* constraints);
1622 bool constant(CompilerConstraintList* constraints, Value* valOut);
1623 bool couldBeConstant(CompilerConstraintList* constraints);
1627 * Information about the result of the compilation of a script. This structure
1628 * stored in the TypeCompartment is indexed by the RecompileInfo. This
1629 * indirection enables the invalidation of all constraints related to the same
1630 * compilation.
1632 class CompilerOutput
1634 // If this compilation has not been invalidated, the associated script and
1635 // kind of compilation being performed.
1636 JSScript* script_;
1637 ExecutionMode mode_ : 2;
1639 // Whether this compilation is about to be invalidated.
1640 bool pendingInvalidation_ : 1;
1642 // During sweeping, the list of compiler outputs is compacted and invalidated
1643 // outputs are removed. This gives the new index for a valid compiler output.
1644 uint32_t sweepIndex_ : 29;
1646 public:
1647 static const uint32_t INVALID_SWEEP_INDEX = (1 << 29) - 1;
1649 CompilerOutput()
1650 : script_(nullptr), mode_(SequentialExecution),
1651 pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
1654 CompilerOutput(JSScript* script, ExecutionMode mode)
1655 : script_(script), mode_(mode),
1656 pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
1659 JSScript* script() const { return script_; }
1660 inline ExecutionMode mode() const { return mode_; }
1662 inline jit::IonScript* ion() const;
1664 bool isValid() const {
1665 return script_ != nullptr;
1667 void invalidate() {
1668 script_ = nullptr;
1671 void setPendingInvalidation() {
1672 pendingInvalidation_ = true;
1674 bool pendingInvalidation() {
1675 return pendingInvalidation_;
1678 void setSweepIndex(uint32_t index) {
1679 if (index >= INVALID_SWEEP_INDEX)
1680 MOZ_CRASH();
1681 sweepIndex_ = index;
1683 uint32_t sweepIndex() {
1684 MOZ_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX);
1685 return sweepIndex_;
1689 class RecompileInfo
1691 // Index in the TypeZone's compilerOutputs or sweepCompilerOutputs arrays,
1692 // depending on the generation value.
1693 uint32_t outputIndex : 31;
1695 // If out of sync with the TypeZone's generation, this index is for the
1696 // zone's sweepCompilerOutputs rather than compilerOutputs.
1697 uint32_t generation : 1;
1699 public:
1700 RecompileInfo(uint32_t outputIndex, uint32_t generation)
1701 : outputIndex(outputIndex), generation(generation)
1704 RecompileInfo()
1705 : outputIndex(JS_BITMASK(31)), generation(0)
1708 CompilerOutput* compilerOutput(TypeZone& types) const;
1709 CompilerOutput* compilerOutput(JSContext* cx) const;
1710 bool shouldSweep(TypeZone& types);
1713 typedef Vector<RecompileInfo, 0, SystemAllocPolicy> RecompileInfoVector;
1715 /* Type information for a compartment. */
1716 struct TypeCompartment
1718 /* Number of scripts in this compartment. */
1719 unsigned scriptCount;
1721 /* Table for referencing types of objects keyed to an allocation site. */
1722 AllocationSiteTable* allocationSiteTable;
1724 /* Tables for determining types of singleton/JSON objects. */
1725 ArrayTypeTable* arrayTypeTable;
1726 ObjectTypeTable* objectTypeTable;
1728 private:
1729 void setTypeToHomogenousArray(ExclusiveContext* cx, JSObject* obj, Type type);
1731 public:
1732 void fixArrayType(ExclusiveContext* cx, ArrayObject* obj);
1733 void fixObjectType(ExclusiveContext* cx, PlainObject* obj);
1734 void fixRestArgumentsType(ExclusiveContext* cx, ArrayObject* obj);
1736 JSObject* newTypedObject(JSContext* cx, IdValuePair* properties, size_t nproperties);
1738 TypeCompartment();
1739 ~TypeCompartment();
1741 inline JSCompartment* compartment();
1743 /* Prints results of this compartment if spew is enabled or force is set. */
1744 void print(JSContext* cx, bool force);
1747 * Make a function or non-function object associated with an optional
1748 * script. The 'key' parameter here may be an array, typed array, function
1749 * or JSProto_Object to indicate a type whose class is unknown (not just
1750 * js_ObjectClass).
1752 TypeObject* newTypeObject(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
1753 TypeObjectFlags initialFlags = 0);
1755 /* Get or make an object for an allocation site, and add to the allocation site table. */
1756 TypeObject* addAllocationSiteTypeObject(JSContext* cx, AllocationSiteKey key);
1758 /* Mark any type set containing obj as having a generic object type. */
1759 void markSetsUnknown(JSContext* cx, TypeObject* obj);
1761 void clearTables();
1762 void sweep(FreeOp* fop);
1763 void finalizeObjects();
1765 void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
1766 size_t* allocationSiteTables,
1767 size_t* arrayTypeTables,
1768 size_t* objectTypeTables);
1771 void FixRestArgumentsType(ExclusiveContext* cxArg, ArrayObject* obj);
1773 struct AutoEnterAnalysis;
1775 struct TypeZone
1777 JS::Zone* zone_;
1779 /* Pool for type information in this zone. */
1780 static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
1781 LifoAlloc typeLifoAlloc;
1783 // Current generation for sweeping.
1784 uint32_t generation : 1;
1787 * All Ion compilations that have occured in this zone, for indexing via
1788 * RecompileInfo. This includes both valid and invalid compilations, though
1789 * invalidated compilations are swept on GC.
1791 typedef Vector<CompilerOutput, 4, SystemAllocPolicy> CompilerOutputVector;
1792 CompilerOutputVector* compilerOutputs;
1794 // During incremental sweeping, allocator holding the old type information
1795 // for the zone.
1796 LifoAlloc sweepTypeLifoAlloc;
1798 // During incremental sweeping, the old compiler outputs for use by
1799 // recompile indexes with a stale generation.
1800 CompilerOutputVector* sweepCompilerOutputs;
1802 // During incremental sweeping, whether to try to destroy all type
1803 // information attached to scripts.
1804 bool sweepReleaseTypes;
1806 // The topmost AutoEnterAnalysis on the stack, if there is one.
1807 AutoEnterAnalysis* activeAnalysis;
1809 explicit TypeZone(JS::Zone* zone);
1810 ~TypeZone();
1812 JS::Zone* zone() const { return zone_; }
1814 void beginSweep(FreeOp* fop, bool releaseTypes, AutoClearTypeInferenceStateOnOOM& oom);
1815 void endSweep(JSRuntime* rt);
1816 void clearAllNewScriptsOnOOM();
1818 /* Mark a script as needing recompilation once inference has finished. */
1819 void addPendingRecompile(JSContext* cx, const RecompileInfo& info);
1820 void addPendingRecompile(JSContext* cx, JSScript* script);
1822 void processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles);
1825 enum SpewChannel {
1826 ISpewOps, /* ops: New constraints and types. */
1827 ISpewResult, /* result: Final type sets. */
1828 SPEW_COUNT
1831 #ifdef DEBUG
1833 const char * InferSpewColorReset();
1834 const char * InferSpewColor(TypeConstraint* constraint);
1835 const char * InferSpewColor(TypeSet* types);
1837 void InferSpew(SpewChannel which, const char* fmt, ...);
1838 const char * TypeString(Type type);
1839 const char * TypeObjectString(TypeObject* type);
1841 /* Check that the type property for id in obj contains value. */
1842 bool TypeHasProperty(JSContext* cx, TypeObject* obj, jsid id, const Value& value);
1844 #else
1846 inline const char * InferSpewColorReset() { return nullptr; }
1847 inline const char * InferSpewColor(TypeConstraint* constraint) { return nullptr; }
1848 inline const char * InferSpewColor(TypeSet* types) { return nullptr; }
1849 inline void InferSpew(SpewChannel which, const char* fmt, ...) {}
1850 inline const char * TypeString(Type type) { return nullptr; }
1851 inline const char * TypeObjectString(TypeObject* type) { return nullptr; }
1853 #endif
1855 /* Print a warning, dump state and abort the program. */
1856 MOZ_NORETURN void TypeFailure(JSContext* cx, const char* fmt, ...);
1858 } /* namespace types */
1859 } /* namespace js */
1861 // JS::ubi::Nodes can point to js::LazyScripts; they're js::gc::Cell instances
1862 // with no associated compartment.
1863 namespace JS {
1864 namespace ubi {
1865 template<> struct Concrete<js::types::TypeObject> : TracerConcrete<js::types::TypeObject> { };
1869 #endif /* jsinfer_h */