1 //* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
2 /* vim: set ts=40 sw=4 et tw=99: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is the Mozilla SpiderMonkey bytecode type inference
18 * The Initial Developer of the Original Code is
20 * Portions created by the Initial Developer are Copyright (C) 2010
21 * the Initial Developer. All Rights Reserved.
24 * Brian Hackett <bhackett@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 /* Definitions related to javascript type inference. */
46 #include "jsfriendapi.h"
49 #include "ds/LifoAlloc.h"
50 #include "gc/Barrier.h"
52 #include "js/HashTable.h"
55 struct TypeInferenceSizes
;
61 /* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
62 struct TypeObjectKey
{
63 static intptr_t keyBits(TypeObjectKey
*obj
) { return (intptr_t) obj
; }
64 static TypeObjectKey
*getKey(TypeObjectKey
*obj
) { return obj
; }
68 * Information about a single concrete type. We pack this into a single word,
69 * where small values are particular primitive or other singleton types, and
70 * larger values are either specific JS objects or type objects.
75 Type(uintptr_t data
) : data(data
) {}
79 uintptr_t raw() const { return data
; }
81 bool isPrimitive() const {
82 return data
< JSVAL_TYPE_OBJECT
;
85 bool isPrimitive(JSValueType type
) const {
86 JS_ASSERT(type
< JSVAL_TYPE_OBJECT
);
87 return (uintptr_t) type
== data
;
90 JSValueType
primitive() const {
91 JS_ASSERT(isPrimitive());
92 return (JSValueType
) data
;
95 bool isAnyObject() const {
96 return data
== JSVAL_TYPE_OBJECT
;
99 bool isUnknown() const {
100 return data
== JSVAL_TYPE_UNKNOWN
;
103 /* Accessors for types that are either JSObject or TypeObject. */
105 bool isObject() const {
106 JS_ASSERT(!isAnyObject() && !isUnknown());
107 return data
> JSVAL_TYPE_UNKNOWN
;
110 inline TypeObjectKey
*objectKey() const;
112 /* Accessors for JSObject types */
114 bool isSingleObject() const {
115 return isObject() && !!(data
& 1);
118 inline JSObject
*singleObject() const;
120 /* Accessors for TypeObject types */
122 bool isTypeObject() const {
123 return isObject() && !(data
& 1);
126 inline TypeObject
*typeObject() const;
128 bool operator == (Type o
) const { return data
== o
.data
; }
129 bool operator != (Type o
) const { return data
!= o
.data
; }
131 static inline Type
UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED
); }
132 static inline Type
NullType() { return Type(JSVAL_TYPE_NULL
); }
133 static inline Type
BooleanType() { return Type(JSVAL_TYPE_BOOLEAN
); }
134 static inline Type
Int32Type() { return Type(JSVAL_TYPE_INT32
); }
135 static inline Type
DoubleType() { return Type(JSVAL_TYPE_DOUBLE
); }
136 static inline Type
StringType() { return Type(JSVAL_TYPE_STRING
); }
137 static inline Type
MagicArgType() { return Type(JSVAL_TYPE_MAGIC
); }
138 static inline Type
AnyObjectType() { return Type(JSVAL_TYPE_OBJECT
); }
139 static inline Type
UnknownType() { return Type(JSVAL_TYPE_UNKNOWN
); }
141 static inline Type
PrimitiveType(JSValueType type
) {
142 JS_ASSERT(type
< JSVAL_TYPE_UNKNOWN
);
146 static inline Type
ObjectType(JSObject
*obj
);
147 static inline Type
ObjectType(TypeObject
*obj
);
148 static inline Type
ObjectType(TypeObjectKey
*obj
);
151 /* Get the type of a jsval, or zero for an unknown special value. */
152 inline Type
GetValueType(JSContext
*cx
, const Value
&val
);
155 * Type inference memory management overview.
157 * Inference constructs a global web of constraints relating the contents of
158 * type sets particular to various scripts and type objects within a
159 * compartment. This data can consume a significant amount of memory, and to
160 * avoid this building up we try to clear it with some regularity. On each GC
161 * which occurs while we are not actively working with inference or other
162 * analysis information, we clear out all generated constraints, all type sets
163 * describing stack types within scripts, and (normally) all data describing
164 * type objects for particular JS objects (see the lazy type objects overview
165 * below). JIT code depends on this data and is cleared as well.
167 * All this data is allocated into compartment->pool. Some type inference data
168 * lives across GCs: type sets for scripts and non-singleton type objects, and
169 * propeties for such type objects. This data is also allocated into
170 * compartment->pool, but everything still live is copied to a new arena on GC.
174 * A constraint which listens to additions to a type set and propagates those
175 * changes to other type sets.
182 const char *kind() const { return kind_
; }
184 const char *kind() const { return NULL
; }
187 /* Next constraint listening to the same type set. */
188 TypeConstraint
*next
;
190 TypeConstraint(const char *kind
)
198 /* Register a new type for the set this constraint is listening to. */
199 virtual void newType(JSContext
*cx
, TypeSet
*source
, Type type
) = 0;
202 * For constraints attached to an object property's type set, mark the
203 * property as having been configured or received an own property.
205 virtual void newPropertyState(JSContext
*cx
, TypeSet
*source
) {}
208 * For constraints attached to the JSID_EMPTY type set on an object, mark a
209 * change in one of the object's dynamic property flags. If force is set,
210 * recompilation is always triggered.
212 virtual void newObjectState(JSContext
*cx
, TypeObject
*object
, bool force
) {}
215 /* Flags and other state stored in TypeSet::flags */
217 TYPE_FLAG_UNDEFINED
= 0x1,
218 TYPE_FLAG_NULL
= 0x2,
219 TYPE_FLAG_BOOLEAN
= 0x4,
220 TYPE_FLAG_INT32
= 0x8,
221 TYPE_FLAG_DOUBLE
= 0x10,
222 TYPE_FLAG_STRING
= 0x20,
223 TYPE_FLAG_LAZYARGS
= 0x40,
224 TYPE_FLAG_ANYOBJECT
= 0x80,
226 /* Mask/shift for the number of objects in objectSet */
227 TYPE_FLAG_OBJECT_COUNT_MASK
= 0xff00,
228 TYPE_FLAG_OBJECT_COUNT_SHIFT
= 8,
229 TYPE_FLAG_OBJECT_COUNT_LIMIT
=
230 TYPE_FLAG_OBJECT_COUNT_MASK
>> TYPE_FLAG_OBJECT_COUNT_SHIFT
,
232 /* Whether the contents of this type set are totally unknown. */
233 TYPE_FLAG_UNKNOWN
= 0x00010000,
235 /* Mask of normal type flags on a type set. */
236 TYPE_FLAG_BASE_MASK
= 0x000100ff,
238 /* Flags for type sets which are on object properties. */
241 * Whether there are subset constraints propagating the possible types
242 * for this property inherited from the object's prototypes. Reset on GC.
244 TYPE_FLAG_PROPAGATED_PROPERTY
= 0x00020000,
246 /* Whether this property has ever been directly written. */
247 TYPE_FLAG_OWN_PROPERTY
= 0x00040000,
250 * Whether the property has ever been deleted or reconfigured to behave
251 * differently from a normal native property (e.g. made non-writable or
252 * given a scripted getter or setter).
254 TYPE_FLAG_CONFIGURED_PROPERTY
= 0x00080000,
257 * Whether the property is definitely in a particular inline slot on all
258 * objects from which it has not been deleted or reconfigured. Implies
259 * OWN_PROPERTY and unlike OWN/CONFIGURED property, this cannot change.
261 TYPE_FLAG_DEFINITE_PROPERTY
= 0x00100000,
263 /* If the property is definite, mask and shift storing the slot. */
264 TYPE_FLAG_DEFINITE_MASK
= 0x0f000000,
265 TYPE_FLAG_DEFINITE_SHIFT
= 24
267 typedef uint32_t TypeFlags
;
269 /* Flags and other state stored in TypeObject::flags */
271 /* Objects with this type are functions. */
272 OBJECT_FLAG_FUNCTION
= 0x1,
274 /* If set, newScript information should not be installed on this object. */
275 OBJECT_FLAG_NEW_SCRIPT_CLEARED
= 0x2,
278 * If set, type constraints covering the correctness of the newScript
279 * definite properties need to be regenerated before compiling any jitcode
280 * which depends on this information.
282 OBJECT_FLAG_NEW_SCRIPT_REGENERATE
= 0x4,
285 * Whether we have ensured all type sets in the compartment contain
286 * ANYOBJECT instead of this object.
288 OBJECT_FLAG_SETS_MARKED_UNKNOWN
= 0x8,
290 /* Mask/shift for the number of properties in propertySet */
291 OBJECT_FLAG_PROPERTY_COUNT_MASK
= 0xfff0,
292 OBJECT_FLAG_PROPERTY_COUNT_SHIFT
= 4,
293 OBJECT_FLAG_PROPERTY_COUNT_LIMIT
=
294 OBJECT_FLAG_PROPERTY_COUNT_MASK
>> OBJECT_FLAG_PROPERTY_COUNT_SHIFT
,
297 * Some objects are not dense arrays, or are dense arrays whose length
298 * property does not fit in an int32_t.
300 OBJECT_FLAG_NON_DENSE_ARRAY
= 0x00010000,
302 /* Whether any objects this represents are not packed arrays. */
303 OBJECT_FLAG_NON_PACKED_ARRAY
= 0x00020000,
305 /* Whether any objects this represents are not typed arrays. */
306 OBJECT_FLAG_NON_TYPED_ARRAY
= 0x00040000,
308 /* Whether any represented script is considered uninlineable. */
309 OBJECT_FLAG_UNINLINEABLE
= 0x00080000,
311 /* Whether any objects have an equality hook. */
312 OBJECT_FLAG_SPECIAL_EQUALITY
= 0x00100000,
314 /* Whether any objects have been iterated over. */
315 OBJECT_FLAG_ITERATED
= 0x00200000,
317 /* Outer function which has been marked reentrant. */
318 OBJECT_FLAG_REENTRANT_FUNCTION
= 0x00400000,
320 /* For a global object, whether flags were set on the RegExpStatics. */
321 OBJECT_FLAG_REGEXP_FLAGS_SET
= 0x00800000,
323 /* Flags which indicate dynamic properties of represented objects. */
324 OBJECT_FLAG_DYNAMIC_MASK
= 0x00ff0000,
327 * Whether all properties of this object are considered unknown.
328 * If set, all flags in DYNAMIC_MASK will also be set.
330 OBJECT_FLAG_UNKNOWN_PROPERTIES
= 0x80000000,
332 /* Mask for objects created with unknown properties. */
333 OBJECT_FLAG_UNKNOWN_MASK
=
334 OBJECT_FLAG_DYNAMIC_MASK
335 | OBJECT_FLAG_UNKNOWN_PROPERTIES
336 | OBJECT_FLAG_SETS_MARKED_UNKNOWN
338 typedef uint32_t TypeObjectFlags
;
340 /* Information about the set of types associated with an lvalue. */
343 /* Flags for this type set. */
346 /* Possible objects this type set can represent. */
347 TypeObjectKey
**objectSet
;
351 /* Chain of constraints which propagate changes out from this type set. */
352 TypeConstraint
*constraintList
;
355 : flags(0), objectSet(NULL
), constraintList(NULL
)
358 void print(JSContext
*cx
);
360 inline void sweep(JSCompartment
*compartment
);
361 inline size_t computedSizeOfExcludingThis();
363 /* Whether this set contains a specific type. */
364 inline bool hasType(Type type
);
366 TypeFlags
baseFlags() const { return flags
& TYPE_FLAG_BASE_MASK
; }
367 bool unknown() const { return !!(flags
& TYPE_FLAG_UNKNOWN
); }
368 bool unknownObject() const { return !!(flags
& (TYPE_FLAG_UNKNOWN
| TYPE_FLAG_ANYOBJECT
)); }
370 bool empty() const { return !baseFlags() && !baseObjectCount(); }
372 bool hasAnyFlag(TypeFlags flags
) const {
373 JS_ASSERT((flags
& TYPE_FLAG_BASE_MASK
) == flags
);
374 return !!(baseFlags() & flags
);
377 bool isOwnProperty(bool configurable
) const {
378 return flags
& (configurable
? TYPE_FLAG_CONFIGURED_PROPERTY
: TYPE_FLAG_OWN_PROPERTY
);
380 bool isDefiniteProperty() const { return flags
& TYPE_FLAG_DEFINITE_PROPERTY
; }
381 unsigned definiteSlot() const {
382 JS_ASSERT(isDefiniteProperty());
383 return flags
>> TYPE_FLAG_DEFINITE_SHIFT
;
387 * Add a type to this set, calling any constraint handlers if this is a new
390 inline void addType(JSContext
*cx
, Type type
);
392 /* Mark this type set as representing an own property or configured property. */
393 inline void setOwnProperty(JSContext
*cx
, bool configured
);
396 * Iterate through the objects in this set. getObjectCount overapproximates
397 * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
400 inline unsigned getObjectCount();
401 inline TypeObjectKey
*getObject(unsigned i
);
402 inline JSObject
*getSingleObject(unsigned i
);
403 inline TypeObject
*getTypeObject(unsigned i
);
405 void setOwnProperty(bool configurable
) {
406 flags
|= TYPE_FLAG_OWN_PROPERTY
;
408 flags
|= TYPE_FLAG_CONFIGURED_PROPERTY
;
410 void setDefinite(unsigned slot
) {
411 JS_ASSERT(slot
<= (TYPE_FLAG_DEFINITE_MASK
>> TYPE_FLAG_DEFINITE_SHIFT
));
412 flags
|= TYPE_FLAG_DEFINITE_PROPERTY
| (slot
<< TYPE_FLAG_DEFINITE_SHIFT
);
415 bool hasPropagatedProperty() { return !!(flags
& TYPE_FLAG_PROPAGATED_PROPERTY
); }
416 void setPropagatedProperty() { flags
|= TYPE_FLAG_PROPAGATED_PROPERTY
; }
419 FILTER_ALL_PRIMITIVES
,
424 /* Add specific kinds of constraints to this set. */
425 inline void add(JSContext
*cx
, TypeConstraint
*constraint
, bool callExisting
= true);
426 void addSubset(JSContext
*cx
, TypeSet
*target
);
427 void addGetProperty(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
428 TypeSet
*target
, jsid id
);
429 void addSetProperty(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
430 TypeSet
*target
, jsid id
);
431 void addCallProperty(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, jsid id
);
432 void addSetElement(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
433 TypeSet
*objectTypes
, TypeSet
*valueTypes
);
434 void addCall(JSContext
*cx
, TypeCallsite
*site
);
435 void addArith(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
436 TypeSet
*target
, TypeSet
*other
= NULL
);
437 void addTransformThis(JSContext
*cx
, JSScript
*script
, TypeSet
*target
);
438 void addPropagateThis(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
439 Type type
, TypeSet
*types
= NULL
);
440 void addFilterPrimitives(JSContext
*cx
, TypeSet
*target
, FilterKind filter
);
441 void addSubsetBarrier(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, TypeSet
*target
);
444 * Make an type set with the specified debugging name, not embedded in
447 static TypeSet
*make(JSContext
*cx
, const char *name
);
450 * Methods for JIT compilation. If a script is currently being compiled
451 * (see AutoEnterCompilation) these will add constraints ensuring that if
452 * the return value change in the future due to new type information, the
453 * currently compiled script will be marked for recompilation.
456 /* Completely freeze the contents of this type set. */
457 void addFreeze(JSContext
*cx
);
459 /* Get any type tag which all values in this set must have. */
460 JSValueType
getKnownTypeTag(JSContext
*cx
);
462 bool isMagicArguments(JSContext
*cx
) { return getKnownTypeTag(cx
) == JSVAL_TYPE_MAGIC
; }
464 /* Whether the type set or a particular object has any of a set of flags. */
465 bool hasObjectFlags(JSContext
*cx
, TypeObjectFlags flags
);
466 static bool HasObjectFlags(JSContext
*cx
, TypeObject
*object
, TypeObjectFlags flags
);
469 * Watch for a generic object state change on a type object. This currently
470 * includes reallocations of slot pointers for global objects, and changes
471 * to newScript data on types.
473 static void WatchObjectStateChange(JSContext
*cx
, TypeObject
*object
);
476 * For type sets on a property, return true if the property has any 'own'
477 * values assigned. If configurable is set, return 'true' if the property
478 * has additionally been reconfigured as non-configurable, non-enumerable
479 * or non-writable (this only applies to properties that have changed after
480 * having been created, not to e.g. properties non-writable on creation).
482 bool isOwnProperty(JSContext
*cx
, TypeObject
*object
, bool configurable
);
484 /* Get whether this type set is non-empty. */
485 bool knownNonEmpty(JSContext
*cx
);
487 /* Get whether this type set is known to be a subset of other. */
488 bool knownSubset(JSContext
*cx
, TypeSet
*other
);
491 * Get the typed array type of all objects in this set. Returns
492 * TypedArray::TYPE_MAX if the set contains different array types.
494 int getTypedArrayType(JSContext
*cx
);
496 /* Get the single value which can appear in this type set, otherwise NULL. */
497 JSObject
*getSingleton(JSContext
*cx
, bool freeze
= true);
499 /* Whether all objects in this set are parented to a particular global. */
500 bool hasGlobalObject(JSContext
*cx
, JSObject
*global
);
502 inline void clearObjects();
505 * Whether a location with this TypeSet needs a write barrier (i.e., whether
506 * it can hold GC things). The type set is frozen if no barrier is needed.
508 bool needsBarrier(JSContext
*cx
);
510 /* The type set is frozen if no barrier is needed. */
511 bool propertyNeedsBarrier(JSContext
*cx
, jsid id
);
514 uint32_t baseObjectCount() const {
515 return (flags
& TYPE_FLAG_OBJECT_COUNT_MASK
) >> TYPE_FLAG_OBJECT_COUNT_SHIFT
;
517 inline void setBaseObjectCount(uint32_t count
);
521 * Handler which persists information about dynamic types pushed within a
522 * script which can affect its behavior and are not covered by JOF_TYPESET ops,
523 * such as integer operations which overflow to a double. These persist across
524 * GCs, and are used to re-seed script types when they are reanalyzed.
532 TypeResult(uint32_t offset
, Type type
)
533 : offset(offset
), type(type
), next(NULL
)
538 * Type barriers overview.
540 * Type barriers are a technique for using dynamic type information to improve
541 * the inferred types within scripts. At certain opcodes --- those with the
542 * JOF_TYPESET format --- we will construct a type set storing the set of types
543 * which we have observed to be pushed at that opcode, and will only use those
544 * observed types when doing propagation downstream from the bytecode. For
545 * example, in the following script:
551 * Suppose we know the type of 'x' and that the type of its 'f' property is
552 * either an int or float. To account for all possible behaviors statically,
553 * we would mark the result of the 'x.f' access as an int or float, as well
554 * as the result of the addition and the return value of foo (and everywhere
555 * the result of 'foo' is used). When dealing with polymorphic code, this is
556 * undesirable behavior --- the type imprecision surrounding the polymorphism
557 * will tend to leak to many places in the program.
559 * Instead, we will keep track of the types that have been dynamically observed
560 * to have been produced by the 'x.f', and only use those observed types
561 * downstream from the access. If the 'x.f' has only ever produced integers,
562 * we will treat its result as an integer and mark the result of foo as an
565 * The set of observed types will be a subset of the set of possible types,
566 * and if the two sets are different, a type barriers will be added at the
567 * bytecode which checks the dynamic result every time the bytecode executes
568 * and makes sure it is in the set of observed types. If it is not, that
569 * observed set is updated, and the new type information is automatically
570 * propagated along the already-generated type constraints to the places
571 * where the result of the bytecode is used.
573 * Observing new types at a bytecode removes type barriers at the bytecode
574 * (this removal happens lazily, see ScriptAnalysis::pruneTypeBarriers), and if
575 * all type barriers at a bytecode are removed --- the set of observed types
576 * grows to match the set of possible types --- then the result of the bytecode
577 * no longer needs to be dynamically checked (unless the set of possible types
578 * grows, triggering the generation of new type barriers).
580 * Barriers are only relevant for accesses on properties whose types inference
581 * actually tracks (see propertySet comment under TypeObject). Accesses on
582 * other properties may be able to produce additional unobserved types even
583 * without a barrier present, and can only be compiled to jitcode with special
584 * knowledge of the property in question (e.g. for lengths of arrays, or
585 * elements of typed arrays).
589 * Barrier introduced at some bytecode. These are added when, during inference,
590 * we block a type from being propagated as would normally be done for a subset
591 * constraint. The propagation is technically possible, but we suspect it will
592 * not happen dynamically and this type needs to be watched for. These are only
593 * added at reads of properties and at scripted call sites.
597 /* Next barrier on the same bytecode. */
600 /* Target type set into which propagation was blocked. */
604 * Type which was not added to the target. If target ends up containing the
605 * type somehow, this barrier can be removed.
610 * If specified, this barrier can be removed if object has a non-undefined
611 * value in property id.
616 TypeBarrier(TypeSet
*target
, Type type
, JSObject
*singleton
, jsid singletonId
)
617 : next(NULL
), target(target
), type(type
),
618 singleton(singleton
), singletonId(singletonId
)
622 /* Type information about a property. */
625 /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
628 /* Possible types for this property, including types inherited from prototypes. */
631 inline Property(jsid id
);
632 inline Property(const Property
&o
);
634 static uint32_t keyBits(jsid id
) { return uint32_t(JSID_BITS(id
)); }
635 static jsid
getKey(Property
*p
) { return p
->id
; }
639 * Information attached to a TypeObject if it is always constructed using 'new'
640 * on a particular script. This is used to manage state related to the definite
641 * properties on the type object: these definite properties depend on type
642 * information which could change as the script executes (e.g. a scripted
643 * setter is added to a prototype object), and we need to ensure both that the
644 * appropriate type constraints are in place when necessary, and that we can
645 * remove the definite property information and repair the JS stack if the
646 * constraints are violated.
652 /* Allocation kind to use for newly constructed objects. */
653 gc::AllocKind allocKind
;
656 * Shape to use for newly constructed objects. Reflects all definite
657 * properties the object will have.
662 * Order in which properties become initialized. We need this in case a
663 * scripted setter is added to one of the object's prototypes while it is
664 * in the middle of being initialized, so we can walk the stack and fixup
665 * any objects which look for in-progress objects which were prematurely
666 * set with their final shape. Initialization can traverse stack frames,
667 * in which case FRAME_PUSH/FRAME_POP are used.
677 Initializer(Kind kind
, uint32_t offset
)
678 : kind(kind
), offset(offset
)
681 Initializer
*initializerList
;
683 static inline void writeBarrierPre(TypeNewScript
*newScript
);
684 static inline void writeBarrierPost(TypeNewScript
*newScript
, void *addr
);
688 * Lazy type objects overview.
690 * Type objects which represent at most one JS object are constructed lazily.
691 * These include types for native functions, standard classes, scripted
692 * functions defined at the top level of global/eval scripts, and in some
693 * other cases. Typical web workloads often create many windows (and many
694 * copies of standard natives) and many scripts, with comparatively few
695 * non-singleton types.
697 * We can recover the type information for the object from examining it,
698 * so don't normally track the possible types of its properties as it is
699 * updated. Property type sets for the object are only constructed when an
700 * analyzed script attaches constraints to it: the script is querying that
701 * property off the object or another which delegates to it, and the analysis
702 * information is sensitive to changes in the property's type. Future changes
703 * to the property (whether those uncovered by analysis or those occurring
704 * in the VM) will treat these properties like those of any other type object.
706 * When a GC occurs, we wipe out all analysis information for all the
707 * compartment's scripts, so can destroy all properties on singleton type
708 * objects at the same time. If there is no reference on the stack to the
709 * type object itself, the type object is also destroyed, and the JS object
710 * reverts to having a lazy type.
713 /* Type information about an object accessed by a script. */
714 struct TypeObject
: gc::Cell
716 /* Prototype shared by objects using this type. */
720 * Whether there is a singleton JS object with this type. That JS object
721 * must appear in type sets instead of this; we include the back reference
722 * here to allow reverting the JS object to a lazy type.
724 HeapPtrObject singleton
;
727 * Value held by singleton if this is a standin type for a singleton JS
728 * object whose type has not been constructed yet.
730 static const size_t LAZY_SINGLETON
= 1;
731 bool lazy() const { return singleton
== (JSObject
*) LAZY_SINGLETON
; }
733 /* Flags for this object. */
734 TypeObjectFlags flags
;
737 * Estimate of the contribution of this object to the type sets it appears in.
738 * This is the sum of the sizes of those sets at the point when the object
741 * When the contribution exceeds the CONTRIBUTION_LIMIT, any type sets the
742 * object is added to are instead marked as unknown. If we get to this point
743 * we are probably not adding types which will let us do meaningful optimization
744 * later, and we want to ensure in such cases that our time/space complexity
745 * is linear, not worst-case cubic as it would otherwise be.
747 uint32_t contribution
;
748 static const uint32_t CONTRIBUTION_LIMIT
= 2000;
751 * If non-NULL, objects of this type have always been constructed using
752 * 'new' on the specified script, which adds some number of properties to
753 * the object in a definite order before the object escapes.
755 HeapPtr
<TypeNewScript
> newScript
;
758 * Properties of this object. This may contain JSID_VOID, representing the
759 * types of all integer indexes of the object, and/or JSID_EMPTY, holding
760 * constraints listening to changes to the object's state.
762 * The type sets in the properties of a type object describe the possible
763 * values that can be read out of that property in actual JS objects.
764 * Properties only account for native properties (those with a slot and no
765 * specialized getter hook) and the elements of dense arrays. For accesses
766 * on such properties, the correspondence is as follows:
768 * 1. If the type has unknownProperties(), the possible properties and
769 * value types for associated JSObjects are unknown.
771 * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
772 * which is a property in obj, before obj->getProperty(id) the property
773 * in type for id must reflect the result of the getProperty.
775 * There is an exception for properties of singleton JS objects which
776 * are undefined at the point where the property was (lazily) generated.
777 * In such cases the property type set will remain empty, and the
778 * 'undefined' type will only be added after a subsequent assignment or
779 * deletion. After these properties have been assigned a defined value,
780 * the only way they can become undefined again is after such an assign
783 * We establish these by using write barriers on calls to setProperty and
784 * defineProperty which are on native properties, and by using the inference
785 * analysis to determine the side effects of code which is JIT-compiled.
787 Property
**propertySet
;
789 /* If this is an interpreted function, the function object. */
790 HeapPtrFunction interpretedFunction
;
792 #if JS_BITS_PER_WORD == 32
796 inline TypeObject(JSObject
*proto
, bool isFunction
, bool unknown
);
798 bool isFunction() { return !!(flags
& OBJECT_FLAG_FUNCTION
); }
800 bool hasAnyFlags(TypeObjectFlags flags
) {
801 JS_ASSERT((flags
& OBJECT_FLAG_DYNAMIC_MASK
) == flags
);
802 return !!(this->flags
& flags
);
804 bool hasAllFlags(TypeObjectFlags flags
) {
805 JS_ASSERT((flags
& OBJECT_FLAG_DYNAMIC_MASK
) == flags
);
806 return (this->flags
& flags
) == flags
;
809 bool unknownProperties() {
810 JS_ASSERT_IF(flags
& OBJECT_FLAG_UNKNOWN_PROPERTIES
,
811 hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK
));
812 return !!(flags
& OBJECT_FLAG_UNKNOWN_PROPERTIES
);
816 * Get or create a property of this object. Only call this for properties which
817 * a script accesses explicitly. 'assign' indicates whether this is for an
818 * assignment, and the own types of the property will be used instead of
821 inline TypeSet
*getProperty(JSContext
*cx
, jsid id
, bool assign
);
823 /* Get a property only if it already exists. */
824 inline TypeSet
*maybeGetProperty(JSContext
*cx
, jsid id
);
826 inline unsigned getPropertyCount();
827 inline Property
*getProperty(unsigned i
);
829 /* Set flags on this object which are implied by the specified key. */
830 inline void setFlagsFromKey(JSContext
*cx
, JSProtoKey kind
);
833 * Get the global object which all objects of this type are parented to,
834 * or NULL if there is none known.
836 inline JSObject
*getGlobal();
840 bool addProperty(JSContext
*cx
, jsid id
, Property
**pprop
);
841 bool addDefiniteProperties(JSContext
*cx
, JSObject
*obj
);
842 bool matchDefiniteProperties(JSObject
*obj
);
843 void addPrototype(JSContext
*cx
, TypeObject
*proto
);
844 void addPropertyType(JSContext
*cx
, jsid id
, Type type
);
845 void addPropertyType(JSContext
*cx
, jsid id
, const Value
&value
);
846 void addPropertyType(JSContext
*cx
, const char *name
, Type type
);
847 void addPropertyType(JSContext
*cx
, const char *name
, const Value
&value
);
848 void markPropertyConfigured(JSContext
*cx
, jsid id
);
849 void markStateChange(JSContext
*cx
);
850 void setFlags(JSContext
*cx
, TypeObjectFlags flags
);
851 void markUnknown(JSContext
*cx
);
852 void clearNewScript(JSContext
*cx
);
853 void getFromPrototypes(JSContext
*cx
, jsid id
, TypeSet
*types
, bool force
= false);
855 void print(JSContext
*cx
);
857 inline void clearProperties();
858 inline void sweep(FreeOp
*fop
);
860 inline size_t computedSizeOfExcludingThis();
862 void sizeOfExcludingThis(TypeInferenceSizes
*sizes
, JSMallocSizeOfFun mallocSizeOf
);
865 * Type objects don't have explicit finalizers. Memory owned by a type
866 * object pending deletion is released when weak references are sweeped
867 * from all the compartment's type objects.
869 void finalize(FreeOp
*fop
) {}
871 static inline void writeBarrierPre(TypeObject
*type
);
872 static inline void writeBarrierPost(TypeObject
*type
, void *addr
);
873 static inline void readBarrier(TypeObject
*type
);
875 static inline ThingRootKind
rootKind() { return THING_ROOT_TYPE_OBJECT
; }
878 inline uint32_t basePropertyCount() const;
879 inline void setBasePropertyCount(uint32_t count
);
881 static void staticAsserts() {
882 JS_STATIC_ASSERT(offsetof(TypeObject
, proto
) == offsetof(js::shadow::TypeObject
, proto
));
887 * Entries for the per-compartment set of type objects which are the default
888 * 'new' or the lazy types of some prototype.
890 struct TypeObjectEntry
892 typedef JSObject
*Lookup
;
894 static inline HashNumber
hash(JSObject
*base
);
895 static inline bool match(TypeObject
*key
, JSObject
*lookup
);
897 typedef HashSet
<ReadBarriered
<TypeObject
>, TypeObjectEntry
, SystemAllocPolicy
> TypeObjectSet
;
899 /* Whether to use a new type object when calling 'new' at script/pc. */
901 UseNewType(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
903 /* Whether to use a new type object for an initializer opcode at script/pc. */
905 UseNewTypeForInitializer(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
908 * Whether Array.prototype, or an object on its proto chain, has an
912 ArrayPrototypeHasIndexedProperty(JSContext
*cx
, JSScript
*script
);
915 * Type information about a callsite. this is separated from the bytecode
916 * information itself so we can handle higher order functions not called
917 * directly via a bytecode.
924 /* Whether this is a 'NEW' call. */
927 /* Types of each argument to the call. */
928 unsigned argumentCount
;
929 TypeSet
**argumentTypes
;
931 /* Types of the this variable. */
934 /* Type set receiving the return value of this call. */
935 TypeSet
*returnTypes
;
937 inline TypeCallsite(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
938 bool isNew
, unsigned argumentCount
);
942 * Information attached to outer and inner function scripts nested in one
943 * another for tracking the reentrance state for outer functions. This state is
944 * used to generate fast accesses to the args and vars of the outer function.
946 * A function is non-reentrant if, at any point in time, only the most recent
947 * activation (i.e. call object) is live. An activation is live if either the
948 * activation is on the stack, or a transitive inner function parented to the
949 * activation is on the stack.
951 * Because inner functions can be (and, quite often, are) stored in object
952 * properties and it is difficult to build a fast and robust escape analysis
953 * to cope with such flow, we detect reentrance dynamically. For the outer
954 * function, we keep track of the call object for the most recent activation,
955 * and the number of frames for the function and its inner functions which are
958 * If the outer function is called while frames associated with a previous
959 * activation are on the stack, the outer function is reentrant. If an inner
960 * function is called whose scope does not match the most recent activation,
961 * the outer function is reentrant.
963 * The situation gets trickier when there are several levels of nesting.
969 * function baz() { return a + b; }
973 * At calls to 'baz', we don't want to do the scope check for the activations
974 * of both 'foo' and 'bar', but rather 'bar' only. For this to work, a call to
975 * 'baz' which is a reentrant call on 'foo' must also be a reentrant call on
976 * 'bar'. When 'foo' is called, we clear the most recent call object for 'bar'.
978 struct TypeScriptNesting
981 * If this is an inner function, the outer function. If non-NULL, this will
982 * be the immediate nested parent of the script (even if that parent has
983 * been marked reentrant). May be NULL even if the script has a nested
984 * parent, if NAME accesses cannot be tracked into the parent (either the
985 * script extends its scope with eval() etc., or the parent can make new
986 * scope chain objects with 'let' or 'with').
990 /* If this is an outer function, list of inner functions. */
993 /* Link for children list of parent. */
996 /* If this is an outer function, the most recent activation. */
997 JSObject
*activeCall
;
1000 * If this is an outer function, pointers to the most recent activation's
1001 * arguments and variables arrays. These could be referring either to stack
1002 * values in activeCall's frame (if it has not finished yet) or to the
1003 * internal slots of activeCall (if the frame has finished). Pointers to
1004 * these fields can be embedded directly in JIT code (though remember to
1005 * use 'addDependency == true' when calling resolveNameAccess).
1007 const Value
*argArray
;
1008 const Value
*varArray
;
1010 /* Number of frames for this function on the stack. */
1011 uint32_t activeFrames
;
1013 TypeScriptNesting() { PodZero(this); }
1014 ~TypeScriptNesting();
1017 /* Construct nesting information for script wrt its parent. */
1018 bool CheckScriptNesting(JSContext
*cx
, JSScript
*script
);
1020 /* Track nesting state when calling or finishing an outer/inner function. */
1021 void NestingPrologue(JSContext
*cx
, StackFrame
*fp
);
1022 void NestingEpilogue(StackFrame
*fp
);
1024 /* Persistent type information for a script, retained across GCs. */
1027 friend struct ::JSScript
;
1029 /* Analysis information for the script, cleared on each GC. */
1030 analyze::ScriptAnalysis
*analysis
;
1033 * Information about the scope in which a script executes. This information
1034 * is not set until the script has executed at least once and SetScope
1035 * called, before that 'global' will be poisoned per GLOBAL_MISSING_SCOPE.
1037 static const size_t GLOBAL_MISSING_SCOPE
= 0x1;
1039 /* Global object for the script, if compileAndGo. */
1040 HeapPtr
<GlobalObject
> global
;
1044 /* Nesting state for outer or inner function scripts. */
1045 TypeScriptNesting
*nesting
;
1047 /* Dynamic types generated at points within this script. */
1048 TypeResult
*dynamicList
;
1050 inline TypeScript();
1052 bool hasScope() { return size_t(global
.get()) != GLOBAL_MISSING_SCOPE
; }
1054 /* Array of type type sets for variables and JOF_TYPESET ops. */
1055 TypeSet
*typeArray() { return (TypeSet
*) (uintptr_t(this) + sizeof(TypeScript
)); }
1057 static inline unsigned NumTypeSets(JSScript
*script
);
1059 static bool SetScope(JSContext
*cx
, JSScript
*script
, JSObject
*scope
);
1061 static inline TypeSet
*ReturnTypes(JSScript
*script
);
1062 static inline TypeSet
*ThisTypes(JSScript
*script
);
1063 static inline TypeSet
*ArgTypes(JSScript
*script
, unsigned i
);
1064 static inline TypeSet
*LocalTypes(JSScript
*script
, unsigned i
);
1066 /* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
1067 static inline TypeSet
*SlotTypes(JSScript
*script
, unsigned slot
);
1070 /* Check that correct types were inferred for the values pushed by this bytecode. */
1071 static void CheckBytecode(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, const js::Value
*sp
);
1074 /* Get the default 'new' object for a given standard class, per the script's global. */
1075 static inline TypeObject
*StandardType(JSContext
*cx
, JSScript
*script
, JSProtoKey kind
);
1077 /* Get a type object for an allocation site in this script. */
1078 static inline TypeObject
*InitObject(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
, JSProtoKey kind
);
1081 * Monitor a bytecode pushing a value which is not accounted for by the
1082 * inference type constraints, such as integer overflow.
1084 static inline void MonitorOverflow(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
1085 static inline void MonitorString(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
1086 static inline void MonitorUnknown(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
1088 static inline void GetPcScript(JSContext
*cx
, JSScript
**script
, jsbytecode
**pc
);
1089 static inline void MonitorOverflow(JSContext
*cx
);
1090 static inline void MonitorString(JSContext
*cx
);
1091 static inline void MonitorUnknown(JSContext
*cx
);
1094 * Monitor a bytecode pushing any value. This must be called for any opcode
1095 * which is JOF_TYPESET, and where either the script has not been analyzed
1096 * by type inference or where the pc has type barriers. For simplicity, we
1097 * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
1098 * and only look at barriers when generating JIT code for the script.
1100 static inline void Monitor(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
,
1101 const js::Value
&val
);
1102 static inline void Monitor(JSContext
*cx
, const js::Value
&rval
);
1104 /* Monitor an assignment at a SETELEM on a non-integer identifier. */
1105 static inline void MonitorAssign(JSContext
*cx
, JSObject
*obj
, jsid id
);
1107 /* Add a type for a variable in a script. */
1108 static inline void SetThis(JSContext
*cx
, JSScript
*script
, Type type
);
1109 static inline void SetThis(JSContext
*cx
, JSScript
*script
, const js::Value
&value
);
1110 static inline void SetLocal(JSContext
*cx
, JSScript
*script
, unsigned local
, Type type
);
1111 static inline void SetLocal(JSContext
*cx
, JSScript
*script
, unsigned local
, const js::Value
&value
);
1112 static inline void SetArgument(JSContext
*cx
, JSScript
*script
, unsigned arg
, Type type
);
1113 static inline void SetArgument(JSContext
*cx
, JSScript
*script
, unsigned arg
, const js::Value
&value
);
1115 static void Sweep(FreeOp
*fop
, JSScript
*script
);
1116 inline void trace(JSTracer
*trc
);
1120 struct ArrayTableKey
;
1121 typedef HashMap
<ArrayTableKey
,ReadBarriered
<TypeObject
>,ArrayTableKey
,SystemAllocPolicy
> ArrayTypeTable
;
1123 struct ObjectTableKey
;
1124 struct ObjectTableEntry
;
1125 typedef HashMap
<ObjectTableKey
,ObjectTableEntry
,ObjectTableKey
,SystemAllocPolicy
> ObjectTypeTable
;
1127 struct AllocationSiteKey
;
1128 typedef HashMap
<AllocationSiteKey
,ReadBarriered
<TypeObject
>,AllocationSiteKey
,SystemAllocPolicy
> AllocationSiteTable
;
1130 struct RecompileInfo
1133 bool constructing
: 1;
1135 uint32_t chunkIndex
:30;
1137 bool operator == (const RecompileInfo
&o
) const {
1138 return script
== o
.script
1139 && constructing
== o
.constructing
1140 && barriers
== o
.barriers
1141 && chunkIndex
== o
.chunkIndex
;
1145 /* Type information for a compartment. */
1146 struct TypeCompartment
1148 /* Constraint solving worklist structures. */
1151 * Worklist of types which need to be propagated to constraints. We use a
1152 * worklist to avoid blowing the native stack.
1156 TypeConstraint
*constraint
;
1160 PendingWork
*pendingArray
;
1161 unsigned pendingCount
;
1162 unsigned pendingCapacity
;
1164 /* Whether we are currently resolving the pending worklist. */
1167 /* Whether type inference is enabled in this compartment. */
1168 bool inferenceEnabled
;
1171 * Bit set if all current types must be marked as unknown, and all scripts
1172 * recompiled. Caused by OOM failure within inference operations.
1174 bool pendingNukeTypes
;
1176 /* Number of scripts in this compartment. */
1177 unsigned scriptCount
;
1179 /* Pending recompilations to perform before execution of JIT code can resume. */
1180 Vector
<RecompileInfo
> *pendingRecompiles
;
1183 * Number of recompilation events and inline frame expansions that have
1184 * occurred in this compartment. If these change, code should not count on
1185 * compiled code or the current stack being intact.
1187 unsigned recompilations
;
1188 unsigned frameExpansions
;
1191 * Script currently being compiled. All constraints which look for type
1192 * changes inducing recompilation are keyed to this script. Note: script
1193 * compilation is not reentrant.
1195 RecompileInfo compiledInfo
;
1197 /* Table for referencing types of objects keyed to an allocation site. */
1198 AllocationSiteTable
*allocationSiteTable
;
1200 /* Tables for determining types of singleton/JSON objects. */
1202 ArrayTypeTable
*arrayTypeTable
;
1203 ObjectTypeTable
*objectTypeTable
;
1205 void fixArrayType(JSContext
*cx
, JSObject
*obj
);
1206 void fixObjectType(JSContext
*cx
, JSObject
*obj
);
1208 /* Logging fields */
1210 /* Counts of stack type sets with some number of possible operand types. */
1211 static const unsigned TYPE_COUNT_LIMIT
= 4;
1212 unsigned typeCounts
[TYPE_COUNT_LIMIT
];
1213 unsigned typeCountOver
;
1215 void init(JSContext
*cx
);
1218 inline JSCompartment
*compartment();
1220 /* Add a type to register with a list of constraints. */
1221 inline void addPending(JSContext
*cx
, TypeConstraint
*constraint
, TypeSet
*source
, Type type
);
1222 bool growPendingArray(JSContext
*cx
);
1224 /* Resolve pending type registrations, excluding delayed ones. */
1225 inline void resolvePending(JSContext
*cx
);
1227 /* Prints results of this compartment if spew is enabled or force is set. */
1228 void print(JSContext
*cx
, bool force
);
1231 * Make a function or non-function object associated with an optional
1232 * script. The 'key' parameter here may be an array, typed array, function
1233 * or JSProto_Object to indicate a type whose class is unknown (not just
1236 TypeObject
*newTypeObject(JSContext
*cx
, JSScript
*script
,
1237 JSProtoKey kind
, JSObject
*proto
, bool unknown
= false);
1239 /* Make an object for an allocation site. */
1240 TypeObject
*newAllocationSiteTypeObject(JSContext
*cx
, const AllocationSiteKey
&key
);
1242 void nukeTypes(FreeOp
*fop
);
1243 void processPendingRecompiles(FreeOp
*fop
);
1245 /* Mark all types as needing destruction once inference has 'finished'. */
1246 void setPendingNukeTypes(JSContext
*cx
);
1247 void setPendingNukeTypesNoReport();
1249 /* Mark a script as needing recompilation once inference has finished. */
1250 void addPendingRecompile(JSContext
*cx
, const RecompileInfo
&info
);
1251 void addPendingRecompile(JSContext
*cx
, JSScript
*script
, jsbytecode
*pc
);
1253 /* Monitor future effects on a bytecode. */
1254 void monitorBytecode(JSContext
*cx
, JSScript
*script
, uint32_t offset
,
1255 bool returnOnly
= false);
1257 /* Mark any type set containing obj as having a generic object type. */
1258 void markSetsUnknown(JSContext
*cx
, TypeObject
*obj
);
1260 void sweep(FreeOp
*fop
);
1261 void finalizeObjects();
1265 ISpewOps
, /* ops: New constraints and types. */
1266 ISpewResult
, /* result: Final type sets. */
1272 const char * InferSpewColorReset();
1273 const char * InferSpewColor(TypeConstraint
*constraint
);
1274 const char * InferSpewColor(TypeSet
*types
);
1276 void InferSpew(SpewChannel which
, const char *fmt
, ...);
1277 const char * TypeString(Type type
);
1278 const char * TypeObjectString(TypeObject
*type
);
1280 /* Check that the type property for id in obj contains value. */
1281 bool TypeHasProperty(JSContext
*cx
, TypeObject
*obj
, jsid id
, const Value
&value
);
1285 inline const char * InferSpewColorReset() { return NULL
; }
1286 inline const char * InferSpewColor(TypeConstraint
*constraint
) { return NULL
; }
1287 inline const char * InferSpewColor(TypeSet
*types
) { return NULL
; }
1288 inline void InferSpew(SpewChannel which
, const char *fmt
, ...) {}
1289 inline const char * TypeString(Type type
) { return NULL
; }
1290 inline const char * TypeObjectString(TypeObject
*type
) { return NULL
; }
1294 /* Print a warning, dump state and abort the program. */
1295 void TypeFailure(JSContext
*cx
, const char *fmt
, ...);
1297 } /* namespace types */
1298 } /* namespace js */
1301 template<> class AnchorPermitted
<js::types::TypeObject
*> { };
1304 #endif // jsinfer_h___