Bumping manifests a=b2g-bump
[gecko.git] / js / src / jsinfer.h
blob17a5edecab4591caca6b7c5c261807b15ef44d19
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/Utility.h"
25 #include "js/Vector.h"
27 namespace js {
29 class TypeDescr;
31 class TaggedProto
33 public:
34 static JSObject * const LazyProto;
36 TaggedProto() : proto(nullptr) {}
37 explicit TaggedProto(JSObject* proto) : proto(proto) {}
39 uintptr_t toWord() const { return uintptr_t(proto); }
41 bool isLazy() const {
42 return proto == LazyProto;
44 bool isObject() const {
45 /* Skip nullptr and LazyProto. */
46 return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto);
48 JSObject* toObject() const {
49 JS_ASSERT(isObject());
50 return proto;
52 JSObject* toObjectOrNull() const {
53 JS_ASSERT(!proto || isObject());
54 return proto;
56 JSObject* raw() const { return proto; }
58 bool operator ==(const TaggedProto& other) { return proto == other.proto; }
59 bool operator !=(const TaggedProto& other) { return proto != other.proto; }
61 private:
62 JSObject* proto;
65 template <>
66 struct RootKind<TaggedProto>
68 static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
71 template <> struct GCMethods<const TaggedProto>
73 static TaggedProto initial() { return TaggedProto(); }
74 static bool poisoned(const TaggedProto& v) { return IsPoisonedPtr(v.raw()); }
77 template <> struct GCMethods<TaggedProto>
79 static TaggedProto initial() { return TaggedProto(); }
80 static bool poisoned(const TaggedProto& v) { return IsPoisonedPtr(v.raw()); }
83 template<class Outer>
84 class TaggedProtoOperations
86 const TaggedProto* value() const {
87 return static_cast<const Outer*>(this)->extract();
90 public:
91 uintptr_t toWord() const { return value()->toWord(); }
92 inline bool isLazy() const { return value()->isLazy(); }
93 inline bool isObject() const { return value()->isObject(); }
94 inline JSObject* toObject() const { return value()->toObject(); }
95 inline JSObject* toObjectOrNull() const { return value()->toObjectOrNull(); }
96 JSObject* raw() const { return value()->raw(); }
99 template <>
100 class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto> >
102 friend class TaggedProtoOperations<Handle<TaggedProto> >;
103 const TaggedProto * extract() const {
104 return static_cast<const Handle<TaggedProto>*>(this)->address();
108 template <>
109 class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto> >
111 friend class TaggedProtoOperations<Rooted<TaggedProto> >;
112 const TaggedProto* extract() const {
113 return static_cast<const Rooted<TaggedProto>*>(this)->address();
117 class CallObject;
120 * Execution Mode Overview
122 * JavaScript code can execute either sequentially or in parallel, such as in
123 * PJS. Functions which behave identically in either execution mode can take a
124 * ThreadSafeContext, and functions which have similar but not identical
125 * behavior between execution modes can be templated on the mode. Such
126 * functions use a context parameter type from ExecutionModeTraits below
127 * indicating whether they are only permitted constrained operations (such as
128 * thread safety, and side effects limited to being thread-local), or whether
129 * they can have arbitrary side effects.
132 enum ExecutionMode {
133 /* Normal JavaScript execution. */
134 SequentialExecution,
137 * JavaScript code to be executed in parallel worker threads in PJS in a
138 * fork join fashion.
140 ParallelExecution,
143 * Modes after this point are internal and are not counted in
144 * NumExecutionModes below.
148 * MIR analysis performed when invoking 'new' on a script, to determine
149 * definite properties. Used by the optimizing JIT.
151 DefinitePropertiesAnalysis,
154 * MIR analysis performed when executing a script which uses its arguments,
155 * when it is not known whether a lazy arguments value can be used.
157 ArgumentsUsageAnalysis
160 inline const char*
161 ExecutionModeString(ExecutionMode mode)
163 switch (mode) {
164 case SequentialExecution:
165 return "SequentialExecution";
166 case ParallelExecution:
167 return "ParallelExecution";
168 case DefinitePropertiesAnalysis:
169 return "DefinitePropertiesAnalysis";
170 case ArgumentsUsageAnalysis:
171 return "ArgumentsUsageAnalysis";
172 default:
173 MOZ_CRASH("Invalid ExecutionMode");
178 * Not as part of the enum so we don't get warnings about unhandled enum
179 * values.
181 static const unsigned NumExecutionModes = ParallelExecution + 1;
183 template <ExecutionMode mode>
184 struct ExecutionModeTraits
188 template <> struct ExecutionModeTraits<SequentialExecution>
190 typedef JSContext * ContextType;
191 typedef ExclusiveContext * ExclusiveContextType;
193 static inline JSContext* toContextType(ExclusiveContext* cx);
196 template <> struct ExecutionModeTraits<ParallelExecution>
198 typedef ForkJoinContext * ContextType;
199 typedef ForkJoinContext * ExclusiveContextType;
201 static inline ForkJoinContext* toContextType(ForkJoinContext* cx) { return cx; }
204 namespace jit {
205 struct IonScript;
206 class IonAllocPolicy;
207 class TempAllocator;
210 namespace types {
212 struct TypeZone;
213 class TypeSet;
214 struct TypeObjectKey;
217 * Information about a single concrete type. We pack this into a single word,
218 * where small values are particular primitive or other singleton types, and
219 * larger values are either specific JS objects or type objects.
221 class Type
223 uintptr_t data;
224 explicit Type(uintptr_t data) : data(data) {}
226 public:
228 uintptr_t raw() const { return data; }
230 bool isPrimitive() const {
231 return data < JSVAL_TYPE_OBJECT;
234 bool isPrimitive(JSValueType type) const {
235 JS_ASSERT(type < JSVAL_TYPE_OBJECT);
236 return (uintptr_t) type == data;
239 JSValueType primitive() const {
240 JS_ASSERT(isPrimitive());
241 return (JSValueType) data;
244 bool isMagicArguments() const {
245 return primitive() == JSVAL_TYPE_MAGIC;
248 bool isSomeObject() const {
249 return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
252 bool isAnyObject() const {
253 return data == JSVAL_TYPE_OBJECT;
256 bool isUnknown() const {
257 return data == JSVAL_TYPE_UNKNOWN;
260 /* Accessors for types that are either JSObject or TypeObject. */
262 bool isObject() const {
263 JS_ASSERT(!isAnyObject() && !isUnknown());
264 return data > JSVAL_TYPE_UNKNOWN;
267 bool isObjectUnchecked() const {
268 return data > JSVAL_TYPE_UNKNOWN;
271 inline TypeObjectKey* objectKey() const;
273 /* Accessors for JSObject types */
275 bool isSingleObject() const {
276 return isObject() && !!(data & 1);
279 inline JSObject* singleObject() const;
280 inline JSObject* singleObjectNoBarrier() const;
282 /* Accessors for TypeObject types */
284 bool isTypeObject() const {
285 return isObject() && !(data & 1);
288 inline TypeObject* typeObject() const;
289 inline TypeObject* typeObjectNoBarrier() const;
291 bool operator == (Type o) const { return data == o.data; }
292 bool operator != (Type o) const { return data != o.data; }
294 static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
295 static inline Type NullType() { return Type(JSVAL_TYPE_NULL); }
296 static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); }
297 static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); }
298 static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
299 static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
300 static inline Type SymbolType() { return Type(JSVAL_TYPE_SYMBOL); }
301 static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); }
302 static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
303 static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }
305 static inline Type PrimitiveType(JSValueType type) {
306 JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
307 return Type(type);
310 static inline Type ObjectType(JSObject* obj);
311 static inline Type ObjectType(TypeObject* obj);
312 static inline Type ObjectType(TypeObjectKey* obj);
314 static js::ThingRootKind rootKind() { return js::THING_ROOT_TYPE; }
317 /* Get the type of a jsval, or zero for an unknown special value. */
318 inline Type GetValueType(const Value& val);
321 * Get the type of a possibly optimized out value. This generally only
322 * happens on unconditional type monitors on bailing out of Ion, such as
323 * for argument and local types.
325 inline Type GetMaybeOptimizedOutValueType(const Value& val);
328 * Type inference memory management overview.
330 * Type information about the values observed within scripts and about the
331 * contents of the heap is accumulated as the program executes. Compilation
332 * accumulates constraints relating type information on the heap with the
333 * compilations that should be invalidated when those types change. Type
334 * information and constraints are allocated in the zone's typeLifoAlloc,
335 * and on GC all data referring to live things is copied into a new allocator.
336 * Thus, type set and constraints only hold weak references.
340 * A constraint which listens to additions to a type set and propagates those
341 * changes to other type sets.
343 class TypeConstraint
345 public:
346 /* Next constraint listening to the same type set. */
347 TypeConstraint* next;
349 TypeConstraint()
350 : next(nullptr)
353 /* Debugging name for this kind of constraint. */
354 virtual const char* kind() = 0;
356 /* Register a new type for the set this constraint is listening to. */
357 virtual void newType(JSContext* cx, TypeSet* source, Type type) = 0;
360 * For constraints attached to an object property's type set, mark the
361 * property as having changed somehow.
363 virtual void newPropertyState(JSContext* cx, TypeSet* source) {}
366 * For constraints attached to the JSID_EMPTY type set on an object,
367 * indicate a change in one of the object's dynamic property flags or other
368 * state.
370 virtual void newObjectState(JSContext* cx, TypeObject* object) {}
373 * If the data this constraint refers to is still live, copy it into the
374 * zone's new allocator. Type constraints only hold weak references.
376 virtual bool sweep(TypeZone& zone, TypeConstraint** res) = 0;
379 /* Flags and other state stored in TypeSet::flags */
380 enum MOZ_ENUM_TYPE(uint32_t) {
381 TYPE_FLAG_UNDEFINED = 0x1,
382 TYPE_FLAG_NULL = 0x2,
383 TYPE_FLAG_BOOLEAN = 0x4,
384 TYPE_FLAG_INT32 = 0x8,
385 TYPE_FLAG_DOUBLE = 0x10,
386 TYPE_FLAG_STRING = 0x20,
387 TYPE_FLAG_SYMBOL = 0x40,
388 TYPE_FLAG_LAZYARGS = 0x80,
389 TYPE_FLAG_ANYOBJECT = 0x100,
391 /* Mask containing all primitives */
392 TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
393 TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
394 TYPE_FLAG_SYMBOL,
396 /* Mask/shift for the number of objects in objectSet */
397 TYPE_FLAG_OBJECT_COUNT_MASK = 0x3e00,
398 TYPE_FLAG_OBJECT_COUNT_SHIFT = 9,
399 TYPE_FLAG_OBJECT_COUNT_LIMIT =
400 TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
402 /* Whether the contents of this type set are totally unknown. */
403 TYPE_FLAG_UNKNOWN = 0x00004000,
405 /* Mask of normal type flags on a type set. */
406 TYPE_FLAG_BASE_MASK = 0x000041ff,
408 /* Additional flags for HeapTypeSet sets. */
411 * Whether the property has ever been deleted or reconfigured to behave
412 * differently from a plain data property, other than making the property
413 * non-writable.
415 TYPE_FLAG_NON_DATA_PROPERTY = 0x00008000,
417 /* Whether the property has ever been made non-writable. */
418 TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00010000,
420 /* Whether the property might not be constant. */
421 TYPE_FLAG_NON_CONSTANT_PROPERTY = 0x00020000,
424 * Whether the property is definitely in a particular slot on all objects
425 * from which it has not been deleted or reconfigured. For singletons
426 * this may be a fixed or dynamic slot, and for other objects this will be
427 * a fixed slot.
429 * If the property is definite, mask and shift storing the slot + 1.
430 * Otherwise these bits are clear.
432 TYPE_FLAG_DEFINITE_MASK = 0xfffc0000,
433 TYPE_FLAG_DEFINITE_SHIFT = 18
435 typedef uint32_t TypeFlags;
437 /* Flags and other state stored in TypeObject::flags */
438 enum MOZ_ENUM_TYPE(uint32_t) {
439 /* Whether this type object is associated with some allocation site. */
440 OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1,
443 * If set, the object's prototype might be in the nursery and can't be
444 * used during Ion compilation (which may be occurring off thread).
446 OBJECT_FLAG_NURSERY_PROTO = 0x2,
449 * Whether we have ensured all type sets in the compartment contain
450 * ANYOBJECT instead of this object.
452 OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x4,
454 /* Mask/shift for the number of properties in propertySet */
455 OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff8,
456 OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 3,
457 OBJECT_FLAG_PROPERTY_COUNT_LIMIT =
458 OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
460 /* Whether any objects this represents may have sparse indexes. */
461 OBJECT_FLAG_SPARSE_INDEXES = 0x00010000,
463 /* Whether any objects this represents may not have packed dense elements. */
464 OBJECT_FLAG_NON_PACKED = 0x00020000,
467 * Whether any objects this represents may be arrays whose length does not
468 * fit in an int32.
470 OBJECT_FLAG_LENGTH_OVERFLOW = 0x00040000,
472 /* Whether any objects have been iterated over. */
473 OBJECT_FLAG_ITERATED = 0x00080000,
475 /* For a global object, whether flags were set on the RegExpStatics. */
476 OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00100000,
479 * For the function on a run-once script, whether the function has actually
480 * run multiple times.
482 OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000,
485 * Whether objects with this type should be allocated directly in the
486 * tenured heap.
488 OBJECT_FLAG_PRE_TENURE = 0x00400000,
490 /* Whether objects with this type might have copy on write elements. */
491 OBJECT_FLAG_COPY_ON_WRITE = 0x00800000,
494 * Whether all properties of this object are considered unknown.
495 * If set, all other flags in DYNAMIC_MASK will also be set.
497 OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x01000000,
499 /* Flags which indicate dynamic properties of represented objects. */
500 OBJECT_FLAG_DYNAMIC_MASK = 0x01ff0000,
502 /* Mask for objects created with unknown properties. */
503 OBJECT_FLAG_UNKNOWN_MASK =
504 OBJECT_FLAG_DYNAMIC_MASK
505 | OBJECT_FLAG_SETS_MARKED_UNKNOWN
507 typedef uint32_t TypeObjectFlags;
509 class StackTypeSet;
510 class HeapTypeSet;
511 class TemporaryTypeSet;
514 * Information about the set of types associated with an lvalue. There are
515 * three kinds of type sets:
517 * - StackTypeSet are associated with TypeScripts, for arguments and values
518 * observed at property reads. These are implicitly frozen on compilation
519 * and do not have constraints attached to them.
521 * - HeapTypeSet are associated with the properties of TypeObjects. These
522 * may have constraints added to them to trigger invalidation of compiled
523 * code.
525 * - TemporaryTypeSet are created during compilation and do not outlive
526 * that compilation.
528 class TypeSet
530 protected:
531 /* Flags for this type set. */
532 TypeFlags flags;
534 /* Possible objects this type set can represent. */
535 TypeObjectKey** objectSet;
537 public:
539 TypeSet()
540 : flags(0), objectSet(nullptr)
543 void print();
545 /* Whether this set contains a specific type. */
546 inline bool hasType(Type type) const;
548 TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
549 bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
550 bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
551 bool empty() const { return !baseFlags() && !baseObjectCount(); }
553 bool hasAnyFlag(TypeFlags flags) const {
554 JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
555 return !!(baseFlags() & flags);
558 bool nonDataProperty() const {
559 return flags & TYPE_FLAG_NON_DATA_PROPERTY;
561 bool nonWritableProperty() const {
562 return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
564 bool nonConstantProperty() const {
565 return flags & TYPE_FLAG_NON_CONSTANT_PROPERTY;
567 bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
568 unsigned definiteSlot() const {
569 JS_ASSERT(definiteProperty());
570 return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
573 /* Join two type sets into a new set. The result should not be modified further. */
574 static TemporaryTypeSet* unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc);
576 /* Add a type to this set using the specified allocator. */
577 void addType(Type type, LifoAlloc* alloc);
579 /* Get a list of all types in this set. */
580 typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
581 bool enumerateTypes(TypeList* list);
584 * Iterate through the objects in this set. getObjectCount overapproximates
585 * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
586 * may return nullptr.
588 inline unsigned getObjectCount() const;
589 inline TypeObjectKey* getObject(unsigned i) const;
590 inline JSObject* getSingleObject(unsigned i) const;
591 inline TypeObject* getTypeObject(unsigned i) const;
592 inline JSObject* getSingleObjectNoBarrier(unsigned i) const;
593 inline TypeObject* getTypeObjectNoBarrier(unsigned i) const;
595 /* The Class of an object in this set. */
596 inline const Class* getObjectClass(unsigned i) const;
598 bool canSetDefinite(unsigned slot) {
599 // Note: the cast is required to work around an MSVC issue.
600 return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
602 void setDefinite(unsigned slot) {
603 JS_ASSERT(canSetDefinite(slot));
604 flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
605 JS_ASSERT(definiteSlot() == slot);
608 /* Whether any values in this set might have the specified type. */
609 bool mightBeMIRType(jit::MIRType type);
612 * Get whether this type set is known to be a subset of other.
613 * This variant doesn't freeze constraints. That variant is called knownSubset
615 bool isSubset(TypeSet* other);
618 * Get whether the objects in this TypeSet are a subset of the objects
619 * in other.
621 bool objectsAreSubset(TypeSet* other);
623 /* Forward all types in this set to the specified constraint. */
624 bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint);
626 // Clone a type set into an arbitrary allocator.
627 TemporaryTypeSet* clone(LifoAlloc* alloc) const;
628 bool clone(LifoAlloc* alloc, TemporaryTypeSet* result) const;
630 // Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
631 TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
633 // Create a new TemporaryTypeSet where the type has been set to object.
634 TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc);
636 // Trigger a read barrier on all the contents of a type set.
637 static void readBarrier(const TypeSet* types);
639 protected:
640 uint32_t baseObjectCount() const {
641 return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
643 inline void setBaseObjectCount(uint32_t count);
645 void clearObjects();
648 /* Superclass common to stack and heap type sets. */
649 class ConstraintTypeSet : public TypeSet
651 public:
652 /* Chain of constraints which propagate changes out from this type set. */
653 TypeConstraint* constraintList;
655 ConstraintTypeSet() : constraintList(nullptr) {}
658 * Add a type to this set, calling any constraint handlers if this is a new
659 * possible type.
661 void addType(ExclusiveContext* cx, Type type);
663 /* Add a new constraint to this set. */
664 bool addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting = true);
666 inline void sweep(JS::Zone* zone, bool* oom);
669 class StackTypeSet : public ConstraintTypeSet
671 public:
674 class HeapTypeSet : public ConstraintTypeSet
676 inline void newPropertyState(ExclusiveContext* cx);
678 public:
679 /* Mark this type set as representing a non-data property. */
680 inline void setNonDataProperty(ExclusiveContext* cx);
681 inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC.
683 /* Mark this type set as representing a non-writable property. */
684 inline void setNonWritableProperty(ExclusiveContext* cx);
686 // Mark this type set as being non-constant.
687 inline void setNonConstantProperty(ExclusiveContext* cx);
690 class CompilerConstraintList;
692 CompilerConstraintList*
693 NewCompilerConstraintList(jit::TempAllocator& alloc);
695 class TemporaryTypeSet : public TypeSet
697 public:
698 TemporaryTypeSet() {}
699 explicit TemporaryTypeSet(Type type);
701 TemporaryTypeSet(uint32_t flags, TypeObjectKey** objectSet) {
702 this->flags = flags;
703 this->objectSet = objectSet;
707 * Constraints for JIT compilation.
709 * Methods for JIT compilation. These must be used when a script is
710 * currently being compiled (see AutoEnterCompilation) and will add
711 * constraints ensuring that if the return value change in the future due
712 * to new type information, the script's jitcode will be discarded.
715 /* Get any type tag which all values in this set must have. */
716 jit::MIRType getKnownMIRType();
718 bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; }
720 /* Whether this value may be an object. */
721 bool maybeObject() { return unknownObject() || baseObjectCount() > 0; }
724 * Whether this typeset represents a potentially sentineled object value:
725 * the value may be an object or null or undefined.
726 * Returns false if the value cannot ever be an object.
728 bool objectOrSentinel() {
729 TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
730 if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK))
731 return false;
733 return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
736 /* Whether the type set contains objects with any of a set of flags. */
737 bool hasObjectFlags(CompilerConstraintList* constraints, TypeObjectFlags flags);
739 /* Get the class shared by all objects in this set, or nullptr. */
740 const Class* getKnownClass();
742 /* Result returned from forAllClasses */
743 enum ForAllResult {
744 EMPTY=1, // Set empty
745 ALL_TRUE, // Set not empty and predicate returned true for all classes
746 ALL_FALSE, // Set not empty and predicate returned false for all classes
747 MIXED, // Set not empty and predicate returned false for some classes
748 // and true for others, or set contains an unknown or non-object
749 // type
752 /* Apply func to the members of the set and return an appropriate result.
753 * The iteration may end early if the result becomes known early.
755 ForAllResult forAllClasses(bool (*func)(const Class* clasp));
757 /* Get the prototype shared by all objects in this set, or nullptr. */
758 JSObject* getCommonPrototype();
760 /* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */
761 Scalar::Type getTypedArrayType();
763 /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
764 bool isDOMClass();
766 /* Whether clasp->isCallable() is true for one or more objects in this set. */
767 bool maybeCallable();
769 /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
770 bool maybeEmulatesUndefined();
772 /* Get the single value which can appear in this type set, otherwise nullptr. */
773 JSObject* getSingleton();
775 /* Whether any objects in the type set needs a barrier on id. */
776 bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id);
778 /* Whether any objects in the type set might treat id as a constant property. */
779 bool propertyMightBeConstant(CompilerConstraintList* constraints, jsid id);
780 bool propertyIsConstant(CompilerConstraintList* constraints, jsid id, Value* valOut);
783 * Whether this set contains all types in other, except (possibly) the
784 * specified type.
786 bool filtersType(const TemporaryTypeSet* other, Type type) const;
788 enum DoubleConversion {
789 /* All types in the set should use eager double conversion. */
790 AlwaysConvertToDoubles,
792 /* Some types in the set should use eager double conversion. */
793 MaybeConvertToDoubles,
795 /* No types should use eager double conversion. */
796 DontConvertToDoubles,
798 /* Some types should use eager double conversion, others cannot. */
799 AmbiguousDoubleConversion
803 * Whether known double optimizations are possible for element accesses on
804 * objects in this type set.
806 DoubleConversion convertDoubleElements(CompilerConstraintList* constraints);
809 bool
810 AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, TypeObject* type, HandleId id);
812 bool
813 AddClearDefiniteFunctionUsesInScript(JSContext* cx, TypeObject* type,
814 JSScript* script, JSScript* calleeScript);
816 /* Is this a reasonable PC to be doing inlining on? */
817 inline bool isInlinableCall(jsbytecode* pc);
819 /* Type information about a property. */
820 struct Property
822 /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
823 HeapId id;
825 /* Possible types for this property, including types inherited from prototypes. */
826 HeapTypeSet types;
828 explicit Property(jsid id)
829 : id(id)
832 Property(const Property& o)
833 : id(o.id.get()), types(o.types)
836 static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
837 static jsid getKey(Property* p) { return p->id; }
841 * Information attached to a TypeObject if it is always constructed using 'new'
842 * on a particular script. This is used to manage state related to the definite
843 * properties on the type object: these definite properties depend on type
844 * information which could change as the script executes (e.g. a scripted
845 * setter is added to a prototype object), and we need to ensure both that the
846 * appropriate type constraints are in place when necessary, and that we can
847 * remove the definite property information and repair the JS stack if the
848 * constraints are violated.
850 struct TypeNewScript
852 HeapPtrFunction fun;
855 * Template object to use for newly constructed objects. Reflects all
856 * definite properties the object will have and the allocation kind to use
857 * for the object. The allocation kind --- and template object itself ---
858 * is subject to change if objects allocated with this type are given
859 * dynamic slots later on due to new properties being added after the
860 * constructor function finishes.
862 HeapPtrObject templateObject;
865 * Order in which properties become initialized. We need this in case a
866 * scripted setter is added to one of the object's prototypes while it is
867 * in the middle of being initialized, so we can walk the stack and fixup
868 * any objects which look for in-progress objects which were prematurely
869 * set with their final shape. Property assignments in inner frames are
870 * preceded by a series of SETPROP_FRAME entries specifying the stack down
871 * to the frame containing the write.
873 struct Initializer {
874 enum Kind {
875 SETPROP,
876 SETPROP_FRAME,
877 DONE
878 } kind;
879 uint32_t offset;
880 Initializer(Kind kind, uint32_t offset)
881 : kind(kind), offset(offset)
884 Initializer* initializerList;
886 static inline void writeBarrierPre(TypeNewScript* newScript);
887 static void writeBarrierPost(TypeNewScript* newScript, void* addr) {}
891 * Lazy type objects overview.
893 * Type objects which represent at most one JS object are constructed lazily.
894 * These include types for native functions, standard classes, scripted
895 * functions defined at the top level of global/eval scripts, and in some
896 * other cases. Typical web workloads often create many windows (and many
897 * copies of standard natives) and many scripts, with comparatively few
898 * non-singleton types.
900 * We can recover the type information for the object from examining it,
901 * so don't normally track the possible types of its properties as it is
902 * updated. Property type sets for the object are only constructed when an
903 * analyzed script attaches constraints to it: the script is querying that
904 * property off the object or another which delegates to it, and the analysis
905 * information is sensitive to changes in the property's type. Future changes
906 * to the property (whether those uncovered by analysis or those occurring
907 * in the VM) will treat these properties like those of any other type object.
910 /* Type information about an object accessed by a script. */
911 struct TypeObject : gc::BarrieredCell<TypeObject>
913 private:
914 /* Class shared by object using this type. */
915 const Class* clasp_;
917 /* Prototype shared by objects using this type. */
918 HeapPtrObject proto_;
921 * Whether there is a singleton JS object with this type. That JS object
922 * must appear in type sets instead of this; we include the back reference
923 * here to allow reverting the JS object to a lazy type.
925 HeapPtrObject singleton_;
927 public:
929 const Class* clasp() const {
930 return clasp_;
933 void setClasp(const Class* clasp) {
934 JS_ASSERT(singleton());
935 clasp_ = clasp;
938 TaggedProto proto() const {
939 return TaggedProto(proto_);
942 JSObject* singleton() const {
943 return singleton_;
946 // For use during marking, don't call otherwise.
947 HeapPtrObject& protoRaw() { return proto_; }
948 HeapPtrObject& singletonRaw() { return singleton_; }
950 void setProto(JSContext* cx, TaggedProto proto);
951 void setProtoUnchecked(TaggedProto proto) {
952 proto_ = proto.raw();
955 void initSingleton(JSObject* singleton) {
956 singleton_ = singleton;
960 * Value held by singleton if this is a standin type for a singleton JS
961 * object whose type has not been constructed yet.
963 static const size_t LAZY_SINGLETON = 1;
964 bool lazy() const { return singleton() == (JSObject*) LAZY_SINGLETON; }
966 private:
967 /* Flags for this object. */
968 TypeObjectFlags flags_;
971 * If specified, holds information about properties which are definitely
972 * added to objects of this type after being constructed by a particular
973 * script.
975 HeapPtrTypeNewScript newScript_;
977 public:
979 TypeObjectFlags flags() const {
980 return flags_;
983 void addFlags(TypeObjectFlags flags) {
984 flags_ |= flags;
987 void clearFlags(TypeObjectFlags flags) {
988 flags_ &= ~flags;
991 TypeNewScript* newScript() {
992 return newScript_;
995 void setNewScript(TypeNewScript* newScript);
997 private:
999 * Properties of this object. This may contain JSID_VOID, representing the
1000 * types of all integer indexes of the object, and/or JSID_EMPTY, holding
1001 * constraints listening to changes to the object's state.
1003 * The type sets in the properties of a type object describe the possible
1004 * values that can be read out of that property in actual JS objects.
1005 * Properties only account for native properties (those with a slot and no
1006 * specialized getter hook) and the elements of dense arrays. For accesses
1007 * on such properties, the correspondence is as follows:
1009 * 1. If the type has unknownProperties(), the possible properties and
1010 * value types for associated JSObjects are unknown.
1012 * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
1013 * which is a property in obj, before obj->getProperty(id) the property
1014 * in type for id must reflect the result of the getProperty.
1016 * There is an exception for properties of global JS objects which
1017 * are undefined at the point where the property was (lazily) generated.
1018 * In such cases the property type set will remain empty, and the
1019 * 'undefined' type will only be added after a subsequent assignment or
1020 * deletion. After these properties have been assigned a defined value,
1021 * the only way they can become undefined again is after such an assign
1022 * or deletion.
1024 * There is another exception for array lengths, which are special cased
1025 * by the compiler and VM and are not reflected in property types.
1027 * We establish these by using write barriers on calls to setProperty and
1028 * defineProperty which are on native properties, and on any jitcode which
1029 * might update the property with a new type.
1031 Property** propertySet;
1032 public:
1034 /* If this is an interpreted function, the function object. */
1035 HeapPtrFunction interpretedFunction;
1037 #if JS_BITS_PER_WORD == 32
1038 uint32_t padding;
1039 #endif
1041 inline TypeObject(const Class* clasp, TaggedProto proto, TypeObjectFlags initialFlags);
1043 bool hasAnyFlags(TypeObjectFlags flags) {
1044 JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
1045 return !!(this->flags() & flags);
1047 bool hasAllFlags(TypeObjectFlags flags) {
1048 JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
1049 return (this->flags() & flags) == flags;
1052 bool unknownProperties() {
1053 JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES,
1054 hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
1055 return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES);
1058 bool shouldPreTenure() {
1059 return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties();
1062 bool hasTenuredProto() const {
1063 return !(flags() & OBJECT_FLAG_NURSERY_PROTO);
1066 gc::InitialHeap initialHeap(CompilerConstraintList* constraints);
1068 bool canPreTenure() {
1069 // Only types associated with particular allocation sites or 'new'
1070 // scripts can be marked as needing pretenuring. Other types can be
1071 // used for different purposes across the compartment and can't use
1072 // this bit reliably.
1073 if (unknownProperties())
1074 return false;
1075 return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || newScript();
1078 void setShouldPreTenure(ExclusiveContext* cx) {
1079 JS_ASSERT(canPreTenure());
1080 setFlags(cx, OBJECT_FLAG_PRE_TENURE);
1084 * Get or create a property of this object. Only call this for properties which
1085 * a script accesses explicitly.
1087 inline HeapTypeSet* getProperty(ExclusiveContext* cx, jsid id);
1089 /* Get a property only if it already exists. */
1090 inline HeapTypeSet* maybeGetProperty(jsid id);
1092 inline unsigned getPropertyCount();
1093 inline Property* getProperty(unsigned i);
1095 /* Helpers */
1097 void updateNewPropertyTypes(ExclusiveContext* cx, jsid id, HeapTypeSet* types);
1098 bool addDefiniteProperties(ExclusiveContext* cx, JSObject* obj);
1099 bool matchDefiniteProperties(HandleObject obj);
1100 void addPrototype(JSContext* cx, TypeObject* proto);
1101 void addPropertyType(ExclusiveContext* cx, jsid id, Type type);
1102 void addPropertyType(ExclusiveContext* cx, jsid id, const Value& value);
1103 void markPropertyNonData(ExclusiveContext* cx, jsid id);
1104 void markPropertyNonWritable(ExclusiveContext* cx, jsid id);
1105 void markStateChange(ExclusiveContext* cx);
1106 void setFlags(ExclusiveContext* cx, TypeObjectFlags flags);
1107 void markUnknown(ExclusiveContext* cx);
1108 void maybeClearNewScriptOnOOM();
1109 void clearNewScript(ExclusiveContext* cx);
1110 bool isPropertyNonData(jsid id);
1111 bool isPropertyNonWritable(jsid id);
1113 void print();
1115 inline void clearProperties();
1116 inline void sweep(FreeOp* fop, bool* oom);
1118 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
1121 * Type objects don't have explicit finalizers. Memory owned by a type
1122 * object pending deletion is released when weak references are sweeped
1123 * from all the compartment's type objects.
1125 void finalize(FreeOp* fop) {}
1127 static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
1129 static inline uint32_t offsetOfClasp() {
1130 return offsetof(TypeObject, clasp_);
1133 static inline uint32_t offsetOfProto() {
1134 return offsetof(TypeObject, proto_);
1137 private:
1138 inline uint32_t basePropertyCount() const;
1139 inline void setBasePropertyCount(uint32_t count);
1141 static void staticAsserts() {
1142 JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto));
1147 * Entries for the per-compartment set of type objects which are 'new' types to
1148 * use for some prototype and constructed with an optional script. This also
1149 * includes entries for the set of lazy type objects in the compartment, which
1150 * use a null script (though there are only a few of these per compartment).
1152 struct TypeObjectWithNewScriptEntry
1154 ReadBarrieredTypeObject object;
1156 // Note: This pointer is only used for equality and does not need a read barrier.
1157 JSFunction* newFunction;
1159 TypeObjectWithNewScriptEntry(TypeObject* object, JSFunction* newFunction)
1160 : object(object), newFunction(newFunction)
1163 struct Lookup {
1164 const Class* clasp;
1165 TaggedProto hashProto;
1166 TaggedProto matchProto;
1167 JSFunction* newFunction;
1169 Lookup(const Class* clasp, TaggedProto proto, JSFunction* newFunction)
1170 : clasp(clasp), hashProto(proto), matchProto(proto), newFunction(newFunction)
1173 #ifdef JSGC_GENERATIONAL
1175 * For use by generational post barriers only. Look up an entry whose
1176 * proto has been moved, but was hashed with the original value.
1178 Lookup(const Class* clasp, TaggedProto hashProto, TaggedProto matchProto, JSFunction* newFunction)
1179 : clasp(clasp), hashProto(hashProto), matchProto(matchProto), newFunction(newFunction)
1181 #endif
1185 static inline HashNumber hash(const Lookup& lookup);
1186 static inline bool match(const TypeObjectWithNewScriptEntry& key, const Lookup& lookup);
1187 static void rekey(TypeObjectWithNewScriptEntry& k, const TypeObjectWithNewScriptEntry& newKey) { k = newKey; }
1189 typedef HashSet<TypeObjectWithNewScriptEntry,
1190 TypeObjectWithNewScriptEntry,
1191 SystemAllocPolicy> TypeObjectWithNewScriptSet;
1193 /* Whether to use a new type object when calling 'new' at script/pc. */
1194 bool
1195 UseNewType(JSContext* cx, JSScript* script, jsbytecode* pc);
1197 bool
1198 UseNewTypeForClone(JSFunction* fun);
1201 * Whether Array.prototype, or an object on its proto chain, has an
1202 * indexed property.
1204 bool
1205 ArrayPrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSScript* script);
1207 /* Whether obj or any of its prototypes have an indexed property. */
1208 bool
1209 TypeCanHaveExtraIndexedProperties(CompilerConstraintList* constraints, TemporaryTypeSet* types);
1211 /* Persistent type information for a script, retained across GCs. */
1212 class TypeScript
1214 friend class ::JSScript;
1216 // Variable-size array
1217 StackTypeSet typeArray_[1];
1219 public:
1220 /* Array of type type sets for variables and JOF_TYPESET ops. */
1221 StackTypeSet* typeArray() const {
1222 // Ensure typeArray_ is the last data member of TypeScript.
1223 JS_STATIC_ASSERT(sizeof(TypeScript) ==
1224 sizeof(typeArray_) + offsetof(TypeScript, typeArray_));
1225 return const_cast<StackTypeSet*>(typeArray_);
1228 static inline size_t SizeIncludingTypeArray(size_t arraySize) {
1229 // Ensure typeArray_ is the last data member of TypeScript.
1230 JS_STATIC_ASSERT(sizeof(TypeScript) ==
1231 sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_));
1232 return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet);
1235 static inline unsigned NumTypeSets(JSScript* script);
1237 static inline StackTypeSet* ThisTypes(JSScript* script);
1238 static inline StackTypeSet* ArgTypes(JSScript* script, unsigned i);
1240 /* Get the type set for values observed at an opcode. */
1241 static inline StackTypeSet* BytecodeTypes(JSScript* script, jsbytecode* pc);
1243 template <typename TYPESET>
1244 static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc, uint32_t* bytecodeMap,
1245 uint32_t* hint, TYPESET* typeArray);
1247 /* Get a type object for an allocation site in this script. */
1248 static inline TypeObject* InitObject(JSContext* cx, JSScript* script, jsbytecode* pc,
1249 JSProtoKey kind);
1252 * Monitor a bytecode pushing any value. This must be called for any opcode
1253 * which is JOF_TYPESET, and where either the script has not been analyzed
1254 * by type inference or where the pc has type barriers. For simplicity, we
1255 * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
1256 * and only look at barriers when generating JIT code for the script.
1258 static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc,
1259 const js::Value& val);
1260 static inline void Monitor(JSContext* cx, const js::Value& rval);
1262 /* Monitor an assignment at a SETELEM on a non-integer identifier. */
1263 static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
1265 /* Add a type for a variable in a script. */
1266 static inline void SetThis(JSContext* cx, JSScript* script, Type type);
1267 static inline void SetThis(JSContext* cx, JSScript* script, const js::Value& value);
1268 static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg, Type type);
1269 static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg,
1270 const js::Value& value);
1273 * Freeze all the stack type sets in a script, for a compilation. Returns
1274 * copies of the type sets which will be checked against the actual ones
1275 * under FinishCompilation, to detect any type changes.
1277 static bool FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script,
1278 TemporaryTypeSet** pThisTypes,
1279 TemporaryTypeSet** pArgTypes,
1280 TemporaryTypeSet** pBytecodeTypes);
1282 static void Purge(JSContext* cx, HandleScript script);
1284 static void Sweep(FreeOp* fop, JSScript* script, bool* oom);
1285 void destroy();
1287 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
1288 return mallocSizeOf(this);
1291 #ifdef DEBUG
1292 void printTypes(JSContext* cx, HandleScript script) const;
1293 #endif
1296 void
1297 FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap);
1299 JSObject*
1300 GetOrFixupCopyOnWriteObject(JSContext* cx, HandleScript script, jsbytecode* pc);
1302 JSObject*
1303 GetCopyOnWriteObject(JSScript* script, jsbytecode* pc);
1305 class RecompileInfo;
1307 // Allocate a CompilerOutput for a finished compilation and generate the type
1308 // constraints for the compilation. Returns whether the type constraints
1309 // still hold.
1310 bool
1311 FinishCompilation(JSContext* cx, HandleScript script, ExecutionMode executionMode,
1312 CompilerConstraintList* constraints, RecompileInfo* precompileInfo);
1314 // Update the actual types in any scripts queried by constraints with any
1315 // speculative types added during the definite properties analysis.
1316 void
1317 FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints);
1319 struct ArrayTableKey;
1320 typedef HashMap<ArrayTableKey,
1321 ReadBarrieredTypeObject,
1322 ArrayTableKey,
1323 SystemAllocPolicy> ArrayTypeTable;
1325 struct ObjectTableKey;
1326 struct ObjectTableEntry;
1327 typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
1329 struct AllocationSiteKey;
1330 typedef HashMap<AllocationSiteKey,
1331 ReadBarrieredTypeObject,
1332 AllocationSiteKey,
1333 SystemAllocPolicy> AllocationSiteTable;
1335 class HeapTypeSetKey;
1337 // Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.
1338 struct TypeObjectKey
1340 static intptr_t keyBits(TypeObjectKey* obj) { return (intptr_t) obj; }
1341 static TypeObjectKey* getKey(TypeObjectKey* obj) { return obj; }
1343 static TypeObjectKey* get(JSObject* obj) {
1344 JS_ASSERT(obj);
1345 return (TypeObjectKey*) (uintptr_t(obj) | 1);
1347 static TypeObjectKey* get(TypeObject* obj) {
1348 JS_ASSERT(obj);
1349 return (TypeObjectKey*) obj;
1352 bool isTypeObject() {
1353 return (uintptr_t(this) & 1) == 0;
1355 bool isSingleObject() {
1356 return (uintptr_t(this) & 1) != 0;
1359 inline TypeObject* asTypeObject();
1360 inline JSObject* asSingleObject();
1362 inline TypeObject* asTypeObjectNoBarrier();
1363 inline JSObject* asSingleObjectNoBarrier();
1365 const Class* clasp();
1366 TaggedProto proto();
1367 bool hasTenuredProto();
1368 JSObject* singleton();
1369 TypeNewScript* newScript();
1371 bool unknownProperties();
1372 bool hasFlags(CompilerConstraintList* constraints, TypeObjectFlags flags);
1373 void watchStateChangeForInlinedCall(CompilerConstraintList* constraints);
1374 void watchStateChangeForNewScriptTemplate(CompilerConstraintList* constraints);
1375 void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
1376 HeapTypeSetKey property(jsid id);
1377 void ensureTrackedProperty(JSContext* cx, jsid id);
1379 TypeObject* maybeType();
1382 // Representation of a heap type property which may or may not be instantiated.
1383 // Heap properties for singleton types are instantiated lazily as they are used
1384 // by the compiler, but this is only done on the main thread. If we are
1385 // compiling off thread and use a property which has not yet been instantiated,
1386 // it will be treated as empty and non-configured and will be instantiated when
1387 // rejoining to the main thread. If it is in fact not empty, the compilation
1388 // will fail; to avoid this, we try to instantiate singleton property types
1389 // during generation of baseline caches.
1390 class HeapTypeSetKey
1392 friend struct TypeObjectKey;
1394 // Object and property being accessed.
1395 TypeObjectKey* object_;
1396 jsid id_;
1398 // If instantiated, the underlying heap type set.
1399 HeapTypeSet* maybeTypes_;
1401 public:
1402 HeapTypeSetKey()
1403 : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
1406 TypeObjectKey* object() const { return object_; }
1407 jsid id() const { return id_; }
1408 HeapTypeSet* maybeTypes() const { return maybeTypes_; }
1410 bool instantiate(JSContext* cx);
1412 void freeze(CompilerConstraintList* constraints);
1413 jit::MIRType knownMIRType(CompilerConstraintList* constraints);
1414 bool nonData(CompilerConstraintList* constraints);
1415 bool nonWritable(CompilerConstraintList* constraints);
1416 bool isOwnProperty(CompilerConstraintList* constraints);
1417 bool knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other);
1418 JSObject* singleton(CompilerConstraintList* constraints);
1419 bool needsBarrier(CompilerConstraintList* constraints);
1420 bool constant(CompilerConstraintList* constraints, Value* valOut);
1424 * Information about the result of the compilation of a script. This structure
1425 * stored in the TypeCompartment is indexed by the RecompileInfo. This
1426 * indirection enables the invalidation of all constraints related to the same
1427 * compilation.
1429 class CompilerOutput
1431 // If this compilation has not been invalidated, the associated script and
1432 // kind of compilation being performed.
1433 JSScript* script_;
1434 ExecutionMode mode_ : 2;
1436 // Whether this compilation is about to be invalidated.
1437 bool pendingInvalidation_ : 1;
1439 // During sweeping, the list of compiler outputs is compacted and invalidated
1440 // outputs are removed. This gives the new index for a valid compiler output.
1441 uint32_t sweepIndex_ : 29;
1443 public:
1444 static const uint32_t INVALID_SWEEP_INDEX = (1 << 29) - 1;
1446 CompilerOutput()
1447 : script_(nullptr), mode_(SequentialExecution),
1448 pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
1451 CompilerOutput(JSScript* script, ExecutionMode mode)
1452 : script_(script), mode_(mode),
1453 pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX)
1456 JSScript* script() const { return script_; }
1457 inline ExecutionMode mode() const { return mode_; }
1459 inline jit::IonScript* ion() const;
1461 bool isValid() const {
1462 return script_ != nullptr;
1464 void invalidate() {
1465 script_ = nullptr;
1468 void setPendingInvalidation() {
1469 pendingInvalidation_ = true;
1471 bool pendingInvalidation() {
1472 return pendingInvalidation_;
1475 void setSweepIndex(uint32_t index) {
1476 if (index >= INVALID_SWEEP_INDEX)
1477 MOZ_CRASH();
1478 sweepIndex_ = index;
1480 void invalidateSweepIndex() {
1481 sweepIndex_ = INVALID_SWEEP_INDEX;
1483 uint32_t sweepIndex() {
1484 JS_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX);
1485 return sweepIndex_;
1489 class RecompileInfo
1491 uint32_t outputIndex;
1493 public:
1494 explicit RecompileInfo(uint32_t outputIndex = uint32_t(-1))
1495 : outputIndex(outputIndex)
1498 bool operator == (const RecompileInfo& o) const {
1499 return outputIndex == o.outputIndex;
1501 CompilerOutput* compilerOutput(TypeZone& types) const;
1502 CompilerOutput* compilerOutput(JSContext* cx) const;
1503 bool shouldSweep(TypeZone& types);
1506 /* Type information for a compartment. */
1507 struct TypeCompartment
1509 /* Constraint solving worklist structures. */
1511 /* Number of scripts in this compartment. */
1512 unsigned scriptCount;
1514 /* Table for referencing types of objects keyed to an allocation site. */
1515 AllocationSiteTable* allocationSiteTable;
1517 /* Tables for determining types of singleton/JSON objects. */
1519 ArrayTypeTable* arrayTypeTable;
1520 ObjectTypeTable* objectTypeTable;
1522 private:
1523 void setTypeToHomogenousArray(ExclusiveContext* cx, JSObject* obj, Type type);
1525 public:
1526 void fixArrayType(ExclusiveContext* cx, JSObject* obj);
1527 void fixObjectType(ExclusiveContext* cx, JSObject* obj);
1528 void fixRestArgumentsType(ExclusiveContext* cx, JSObject* obj);
1530 JSObject* newTypedObject(JSContext* cx, IdValuePair* properties, size_t nproperties);
1532 TypeCompartment();
1533 ~TypeCompartment();
1535 inline JSCompartment* compartment();
1537 /* Prints results of this compartment if spew is enabled or force is set. */
1538 void print(JSContext* cx, bool force);
1541 * Make a function or non-function object associated with an optional
1542 * script. The 'key' parameter here may be an array, typed array, function
1543 * or JSProto_Object to indicate a type whose class is unknown (not just
1544 * js_ObjectClass).
1546 TypeObject* newTypeObject(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
1547 TypeObjectFlags initialFlags = 0);
1549 /* Get or make an object for an allocation site, and add to the allocation site table. */
1550 TypeObject* addAllocationSiteTypeObject(JSContext* cx, AllocationSiteKey key);
1552 /* Mark any type set containing obj as having a generic object type. */
1553 void markSetsUnknown(JSContext* cx, TypeObject* obj);
1555 void clearTables();
1556 void sweep(FreeOp* fop);
1557 void finalizeObjects();
1559 void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
1560 size_t* allocationSiteTables,
1561 size_t* arrayTypeTables,
1562 size_t* objectTypeTables);
1565 void FixRestArgumentsType(ExclusiveContext* cxArg, JSObject* obj);
1567 struct TypeZone
1569 JS::Zone* zone_;
1571 /* Pool for type information in this zone. */
1572 static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
1573 js::LifoAlloc typeLifoAlloc;
1576 * All Ion compilations that have occured in this zone, for indexing via
1577 * RecompileInfo. This includes both valid and invalid compilations, though
1578 * invalidated compilations are swept on GC.
1580 Vector<CompilerOutput>* compilerOutputs;
1582 /* Pending recompilations to perform before execution of JIT code can resume. */
1583 Vector<RecompileInfo>* pendingRecompiles;
1585 explicit TypeZone(JS::Zone* zone);
1586 ~TypeZone();
1588 JS::Zone* zone() const { return zone_; }
1590 void sweep(FreeOp* fop, bool releaseTypes, bool* oom);
1591 void clearAllNewScriptsOnOOM();
1593 /* Mark a script as needing recompilation once inference has finished. */
1594 void addPendingRecompile(JSContext* cx, const RecompileInfo& info);
1595 void addPendingRecompile(JSContext* cx, JSScript* script);
1597 void processPendingRecompiles(FreeOp* fop);
1600 enum SpewChannel {
1601 ISpewOps, /* ops: New constraints and types. */
1602 ISpewResult, /* result: Final type sets. */
1603 SPEW_COUNT
1606 #ifdef DEBUG
1608 const char * InferSpewColorReset();
1609 const char * InferSpewColor(TypeConstraint* constraint);
1610 const char * InferSpewColor(TypeSet* types);
1612 void InferSpew(SpewChannel which, const char* fmt, ...);
1613 const char * TypeString(Type type);
1614 const char * TypeObjectString(TypeObject* type);
1616 /* Check that the type property for id in obj contains value. */
1617 bool TypeHasProperty(JSContext* cx, TypeObject* obj, jsid id, const Value& value);
1619 #else
1621 inline const char * InferSpewColorReset() { return nullptr; }
1622 inline const char * InferSpewColor(TypeConstraint* constraint) { return nullptr; }
1623 inline const char * InferSpewColor(TypeSet* types) { return nullptr; }
1624 inline void InferSpew(SpewChannel which, const char* fmt, ...) {}
1625 inline const char * TypeString(Type type) { return nullptr; }
1626 inline const char * TypeObjectString(TypeObject* type) { return nullptr; }
1628 #endif
1630 /* Print a warning, dump state and abort the program. */
1631 MOZ_NORETURN void TypeFailure(JSContext* cx, const char* fmt, ...);
1633 } /* namespace types */
1634 } /* namespace js */
1636 #endif /* jsinfer_h */