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