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
5 : *
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/
10 : *
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
14 : * License.
15 : *
16 : * The Original Code is the Mozilla SpiderMonkey bytecode type inference
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Foundation
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Brian Hackett <bhackett@mozilla.com>
25 : *
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.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /* Definitions related to javascript type inference. */
41 :
42 : #ifndef jsinfer_h___
43 : #define jsinfer_h___
44 :
45 : #include "jsalloc.h"
46 : #include "jscell.h"
47 : #include "jsfriendapi.h"
48 : #include "jsprvtd.h"
49 :
50 : #include "ds/LifoAlloc.h"
51 : #include "gc/Barrier.h"
52 : #include "js/HashTable.h"
53 :
54 : namespace JS {
55 : struct TypeInferenceSizes;
56 : }
57 :
58 : namespace js {
59 : namespace types {
60 :
61 : /* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */
62 : struct TypeObjectKey {
63 2204634 : static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; }
64 45956590 : static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
65 : };
66 :
67 : /*
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.
71 : */
72 : class Type
73 : {
74 : uintptr_t data;
75 174900315 : Type(uintptr_t data) : data(data) {}
76 :
77 : public:
78 :
79 1585 : uintptr_t raw() const { return data; }
80 :
81 300555251 : bool isPrimitive() const {
82 300555251 : return data < JSVAL_TYPE_OBJECT;
83 : }
84 :
85 165247 : bool isPrimitive(JSValueType type) const {
86 165247 : JS_ASSERT(type < JSVAL_TYPE_OBJECT);
87 165247 : return (uintptr_t) type == data;
88 : }
89 :
90 124903456 : JSValueType primitive() const {
91 124903456 : JS_ASSERT(isPrimitive());
92 124903456 : return (JSValueType) data;
93 : }
94 :
95 111519024 : bool isAnyObject() const {
96 111519024 : return data == JSVAL_TYPE_OBJECT;
97 : }
98 :
99 229599788 : bool isUnknown() const {
100 229599788 : return data == JSVAL_TYPE_UNKNOWN;
101 : }
102 :
103 : /* Accessors for types that are either JSObject or TypeObject. */
104 :
105 59262682 : bool isObject() const {
106 59262682 : JS_ASSERT(!isAnyObject() && !isUnknown());
107 59262682 : return data > JSVAL_TYPE_UNKNOWN;
108 : }
109 :
110 42216099 : TypeObjectKey *objectKey() const {
111 42216099 : JS_ASSERT(isObject());
112 42216099 : return (TypeObjectKey *) data;
113 : }
114 :
115 : /* Accessors for JSObject types */
116 :
117 10822821 : bool isSingleObject() const {
118 10822821 : return isObject() && !!(data & 1);
119 : }
120 :
121 3702395 : JSObject *singleObject() const {
122 3702395 : JS_ASSERT(isSingleObject());
123 3702395 : return (JSObject *) (data ^ 1);
124 : }
125 :
126 : /* Accessors for TypeObject types */
127 :
128 4734039 : bool isTypeObject() const {
129 4734039 : return isObject() && !(data & 1);
130 : }
131 :
132 3718383 : TypeObject *typeObject() const {
133 3718383 : JS_ASSERT(isTypeObject());
134 3718383 : return (TypeObject *) data;
135 : }
136 :
137 3405949 : bool operator == (Type o) const { return data == o.data; }
138 6980 : bool operator != (Type o) const { return data != o.data; }
139 :
140 756741 : static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
141 330900 : static inline Type NullType() { return Type(JSVAL_TYPE_NULL); }
142 391067 : static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); }
143 464670 : static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); }
144 12710176 : static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
145 707015 : static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
146 433 : static inline Type LazyArgsType() { return Type(JSVAL_TYPE_MAGIC); }
147 396279 : static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
148 1159019 : static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }
149 :
150 115434759 : static inline Type PrimitiveType(JSValueType type) {
151 115434759 : JS_ASSERT(type < JSVAL_TYPE_UNKNOWN);
152 115434759 : return Type(type);
153 : }
154 :
155 : static inline Type ObjectType(JSObject *obj);
156 : static inline Type ObjectType(TypeObject *obj);
157 : static inline Type ObjectType(TypeObjectKey *obj);
158 : };
159 :
160 : /* Get the type of a jsval, or zero for an unknown special value. */
161 : inline Type GetValueType(JSContext *cx, const Value &val);
162 :
163 : /*
164 : * Type inference memory management overview.
165 : *
166 : * Inference constructs a global web of constraints relating the contents of
167 : * type sets particular to various scripts and type objects within a
168 : * compartment. This data can consume a significant amount of memory, and to
169 : * avoid this building up we try to clear it with some regularity. On each GC
170 : * which occurs while we are not actively working with inference or other
171 : * analysis information, we clear out all generated constraints, all type sets
172 : * describing stack types within scripts, and (normally) all data describing
173 : * type objects for particular JS objects (see the lazy type objects overview
174 : * below). JIT code depends on this data and is cleared as well.
175 : *
176 : * All this data is allocated into compartment->pool. Some type inference data
177 : * lives across GCs: type sets for scripts and non-singleton type objects, and
178 : * propeties for such type objects. This data is also allocated into
179 : * compartment->pool, but everything still live is copied to a new arena on GC.
180 : */
181 :
182 : /*
183 : * A constraint which listens to additions to a type set and propagates those
184 : * changes to other type sets.
185 : */
186 : class TypeConstraint
187 : {
188 : public:
189 : #ifdef DEBUG
190 : const char *kind_;
191 4659922 : const char *kind() const { return kind_; }
192 : #else
193 : const char *kind() const { return NULL; }
194 : #endif
195 :
196 : /* Next constraint listening to the same type set. */
197 : TypeConstraint *next;
198 :
199 4659922 : TypeConstraint(const char *kind)
200 4659922 : : next(NULL)
201 : {
202 : #ifdef DEBUG
203 4659922 : this->kind_ = kind;
204 : #endif
205 4659922 : }
206 :
207 : /* Register a new type for the set this constraint is listening to. */
208 : virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0;
209 :
210 : /*
211 : * For constraints attached to an object property's type set, mark the
212 : * property as having been configured or received an own property.
213 : */
214 6602 : virtual void newPropertyState(JSContext *cx, TypeSet *source) {}
215 :
216 : /*
217 : * For constraints attached to the JSID_EMPTY type set on an object, mark a
218 : * change in one of the object's dynamic property flags. If force is set,
219 : * recompilation is always triggered.
220 : */
221 0 : virtual void newObjectState(JSContext *cx, TypeObject *object, bool force) {}
222 : };
223 :
224 : /* Flags and other state stored in TypeSet::flags */
225 : enum {
226 : TYPE_FLAG_UNDEFINED = 0x1,
227 : TYPE_FLAG_NULL = 0x2,
228 : TYPE_FLAG_BOOLEAN = 0x4,
229 : TYPE_FLAG_INT32 = 0x8,
230 : TYPE_FLAG_DOUBLE = 0x10,
231 : TYPE_FLAG_STRING = 0x20,
232 : TYPE_FLAG_LAZYARGS = 0x40,
233 : TYPE_FLAG_ANYOBJECT = 0x80,
234 :
235 : /* Mask/shift for the number of objects in objectSet */
236 : TYPE_FLAG_OBJECT_COUNT_MASK = 0xff00,
237 : TYPE_FLAG_OBJECT_COUNT_SHIFT = 8,
238 : TYPE_FLAG_OBJECT_COUNT_LIMIT =
239 : TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
240 :
241 : /* Whether the contents of this type set are totally unknown. */
242 : TYPE_FLAG_UNKNOWN = 0x00010000,
243 :
244 : /* Mask of normal type flags on a type set. */
245 : TYPE_FLAG_BASE_MASK = 0x000100ff,
246 :
247 : /* Flags for type sets which are on object properties. */
248 :
249 : /*
250 : * Whether there are subset constraints propagating the possible types
251 : * for this property inherited from the object's prototypes. Reset on GC.
252 : */
253 : TYPE_FLAG_PROPAGATED_PROPERTY = 0x00020000,
254 :
255 : /* Whether this property has ever been directly written. */
256 : TYPE_FLAG_OWN_PROPERTY = 0x00040000,
257 :
258 : /*
259 : * Whether the property has ever been deleted or reconfigured to behave
260 : * differently from a normal native property (e.g. made non-writable or
261 : * given a scripted getter or setter).
262 : */
263 : TYPE_FLAG_CONFIGURED_PROPERTY = 0x00080000,
264 :
265 : /*
266 : * Whether the property is definitely in a particular inline slot on all
267 : * objects from which it has not been deleted or reconfigured. Implies
268 : * OWN_PROPERTY and unlike OWN/CONFIGURED property, this cannot change.
269 : */
270 : TYPE_FLAG_DEFINITE_PROPERTY = 0x00100000,
271 :
272 : /* If the property is definite, mask and shift storing the slot. */
273 : TYPE_FLAG_DEFINITE_MASK = 0x0f000000,
274 : TYPE_FLAG_DEFINITE_SHIFT = 24
275 : };
276 : typedef uint32_t TypeFlags;
277 :
278 : /* Flags and other state stored in TypeObject::flags */
279 : enum {
280 : /* Objects with this type are functions. */
281 : OBJECT_FLAG_FUNCTION = 0x1,
282 :
283 : /* If set, newScript information should not be installed on this object. */
284 : OBJECT_FLAG_NEW_SCRIPT_CLEARED = 0x2,
285 :
286 : /*
287 : * If set, type constraints covering the correctness of the newScript
288 : * definite properties need to be regenerated before compiling any jitcode
289 : * which depends on this information.
290 : */
291 : OBJECT_FLAG_NEW_SCRIPT_REGENERATE = 0x4,
292 :
293 : /*
294 : * Whether we have ensured all type sets in the compartment contain
295 : * ANYOBJECT instead of this object.
296 : */
297 : OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x8,
298 :
299 : /* Mask/shift for the number of properties in propertySet */
300 : OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff0,
301 : OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 4,
302 : OBJECT_FLAG_PROPERTY_COUNT_LIMIT =
303 : OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
304 :
305 : /*
306 : * Some objects are not dense arrays, or are dense arrays whose length
307 : * property does not fit in an int32_t.
308 : */
309 : OBJECT_FLAG_NON_DENSE_ARRAY = 0x00010000,
310 :
311 : /* Whether any objects this represents are not packed arrays. */
312 : OBJECT_FLAG_NON_PACKED_ARRAY = 0x00020000,
313 :
314 : /* Whether any objects this represents are not typed arrays. */
315 : OBJECT_FLAG_NON_TYPED_ARRAY = 0x00040000,
316 :
317 : /* Whether any represented script is considered uninlineable. */
318 : OBJECT_FLAG_UNINLINEABLE = 0x00080000,
319 :
320 : /* Whether any objects have an equality hook. */
321 : OBJECT_FLAG_SPECIAL_EQUALITY = 0x00100000,
322 :
323 : /* Whether any objects have been iterated over. */
324 : OBJECT_FLAG_ITERATED = 0x00200000,
325 :
326 : /* Outer function which has been marked reentrant. */
327 : OBJECT_FLAG_REENTRANT_FUNCTION = 0x00400000,
328 :
329 : /* For a global object, whether flags were set on the RegExpStatics. */
330 : OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00800000,
331 :
332 : /* Flags which indicate dynamic properties of represented objects. */
333 : OBJECT_FLAG_DYNAMIC_MASK = 0x00ff0000,
334 :
335 : /*
336 : * Whether all properties of this object are considered unknown.
337 : * If set, all flags in DYNAMIC_MASK will also be set.
338 : */
339 : OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x80000000,
340 :
341 : /* Mask for objects created with unknown properties. */
342 : OBJECT_FLAG_UNKNOWN_MASK =
343 : OBJECT_FLAG_DYNAMIC_MASK
344 : | OBJECT_FLAG_UNKNOWN_PROPERTIES
345 : | OBJECT_FLAG_SETS_MARKED_UNKNOWN
346 : };
347 : typedef uint32_t TypeObjectFlags;
348 :
349 : /* Information about the set of types associated with an lvalue. */
350 : class TypeSet
351 : {
352 : /* Flags for this type set. */
353 : TypeFlags flags;
354 :
355 : /* Possible objects this type set can represent. */
356 : TypeObjectKey **objectSet;
357 :
358 : public:
359 :
360 : /* Chain of constraints which propagate changes out from this type set. */
361 : TypeConstraint *constraintList;
362 :
363 168475 : TypeSet()
364 168475 : : flags(0), objectSet(NULL), constraintList(NULL)
365 168475 : {}
366 :
367 : void print(JSContext *cx);
368 :
369 : inline void sweep(JSCompartment *compartment);
370 : inline size_t computedSizeOfExcludingThis();
371 :
372 : /* Whether this set contains a specific type. */
373 : inline bool hasType(Type type);
374 :
375 2009669 : TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
376 178444435 : bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
377 6716373 : bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
378 :
379 : bool empty() const { return !baseFlags() && !baseObjectCount(); }
380 :
381 35547 : bool hasAnyFlag(TypeFlags flags) const {
382 35547 : JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
383 35547 : return !!(baseFlags() & flags);
384 : }
385 :
386 238287 : bool isOwnProperty(bool configurable) const {
387 238287 : return flags & (configurable ? TYPE_FLAG_CONFIGURED_PROPERTY : TYPE_FLAG_OWN_PROPERTY);
388 : }
389 44406 : bool isDefiniteProperty() const { return flags & TYPE_FLAG_DEFINITE_PROPERTY; }
390 10943 : unsigned definiteSlot() const {
391 10943 : JS_ASSERT(isDefiniteProperty());
392 10943 : return flags >> TYPE_FLAG_DEFINITE_SHIFT;
393 : }
394 :
395 : /*
396 : * Add a type to this set, calling any constraint handlers if this is a new
397 : * possible type.
398 : */
399 : inline void addType(JSContext *cx, Type type);
400 :
401 : /* Mark this type set as representing an own property or configured property. */
402 : inline void setOwnProperty(JSContext *cx, bool configured);
403 :
404 : /*
405 : * Iterate through the objects in this set. getObjectCount overapproximates
406 : * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
407 : * may return NULL.
408 : */
409 : inline unsigned getObjectCount();
410 : inline TypeObjectKey *getObject(unsigned i);
411 : inline JSObject *getSingleObject(unsigned i);
412 : inline TypeObject *getTypeObject(unsigned i);
413 :
414 : void setOwnProperty(bool configurable) {
415 : flags |= TYPE_FLAG_OWN_PROPERTY;
416 : if (configurable)
417 : flags |= TYPE_FLAG_CONFIGURED_PROPERTY;
418 : }
419 5660 : void setDefinite(unsigned slot) {
420 5660 : JS_ASSERT(slot <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT));
421 5660 : flags |= TYPE_FLAG_DEFINITE_PROPERTY | (slot << TYPE_FLAG_DEFINITE_SHIFT);
422 5660 : }
423 :
424 1317898 : bool hasPropagatedProperty() { return !!(flags & TYPE_FLAG_PROPAGATED_PROPERTY); }
425 91076 : void setPropagatedProperty() { flags |= TYPE_FLAG_PROPAGATED_PROPERTY; }
426 :
427 : enum FilterKind {
428 : FILTER_ALL_PRIMITIVES,
429 : FILTER_NULL_VOID,
430 : FILTER_VOID
431 : };
432 :
433 : /* Add specific kinds of constraints to this set. */
434 : inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
435 : void addSubset(JSContext *cx, TypeSet *target);
436 : void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
437 : TypeSet *target, jsid id);
438 : void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
439 : TypeSet *target, jsid id);
440 : void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
441 : void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
442 : TypeSet *objectTypes, TypeSet *valueTypes);
443 : void addCall(JSContext *cx, TypeCallsite *site);
444 : void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
445 : TypeSet *target, TypeSet *other = NULL);
446 : void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
447 : void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
448 : Type type, TypeSet *types = NULL);
449 : void addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter);
450 : void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
451 :
452 : /*
453 : * Make an type set with the specified debugging name, not embedded in
454 : * another structure.
455 : */
456 : static TypeSet *make(JSContext *cx, const char *name);
457 :
458 : /*
459 : * Methods for JIT compilation. If a script is currently being compiled
460 : * (see AutoEnterCompilation) these will add constraints ensuring that if
461 : * the return value change in the future due to new type information, the
462 : * currently compiled script will be marked for recompilation.
463 : */
464 :
465 : /* Completely freeze the contents of this type set. */
466 : void addFreeze(JSContext *cx);
467 :
468 : /* Get any type tag which all values in this set must have. */
469 : JSValueType getKnownTypeTag(JSContext *cx);
470 :
471 39891 : bool isLazyArguments(JSContext *cx) { return getKnownTypeTag(cx) == JSVAL_TYPE_MAGIC; }
472 :
473 : /* Whether the type set or a particular object has any of a set of flags. */
474 : bool hasObjectFlags(JSContext *cx, TypeObjectFlags flags);
475 : static bool HasObjectFlags(JSContext *cx, TypeObject *object, TypeObjectFlags flags);
476 :
477 : /*
478 : * Watch for a generic object state change on a type object. This currently
479 : * includes reallocations of slot pointers for global objects, and changes
480 : * to newScript data on types.
481 : */
482 : static void WatchObjectStateChange(JSContext *cx, TypeObject *object);
483 :
484 : /*
485 : * For type sets on a property, return true if the property has any 'own'
486 : * values assigned. If configurable is set, return 'true' if the property
487 : * has additionally been reconfigured as non-configurable, non-enumerable
488 : * or non-writable (this only applies to properties that have changed after
489 : * having been created, not to e.g. properties non-writable on creation).
490 : */
491 : bool isOwnProperty(JSContext *cx, TypeObject *object, bool configurable);
492 :
493 : /* Get whether this type set is non-empty. */
494 : bool knownNonEmpty(JSContext *cx);
495 :
496 : /* Get whether this type set is known to be a subset of other. */
497 : bool knownSubset(JSContext *cx, TypeSet *other);
498 :
499 : /*
500 : * Get the typed array type of all objects in this set. Returns
501 : * TypedArray::TYPE_MAX if the set contains different array types.
502 : */
503 : int getTypedArrayType(JSContext *cx);
504 :
505 : /* Get the single value which can appear in this type set, otherwise NULL. */
506 : JSObject *getSingleton(JSContext *cx, bool freeze = true);
507 :
508 : /* Whether all objects in this set are parented to a particular global. */
509 : bool hasGlobalObject(JSContext *cx, JSObject *global);
510 :
511 : inline void clearObjects();
512 :
513 : /*
514 : * Whether a location with this TypeSet needs a write barrier (i.e., whether
515 : * it can hold GC things). The type set is frozen if no barrier is needed.
516 : */
517 : bool needsBarrier(JSContext *cx);
518 :
519 : /* The type set is frozen if no barrier is needed. */
520 : bool propertyNeedsBarrier(JSContext *cx, jsid id);
521 :
522 : private:
523 55556427 : uint32_t baseObjectCount() const {
524 55556427 : return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
525 : }
526 : inline void setBaseObjectCount(uint32_t count);
527 : };
528 :
529 : /*
530 : * Handler which persists information about dynamic types pushed within a
531 : * script which can affect its behavior and are not covered by JOF_TYPESET ops,
532 : * such as integer operations which overflow to a double. These persist across
533 : * GCs, and are used to re-seed script types when they are reanalyzed.
534 : */
535 : struct TypeResult
536 2817 : {
537 : uint32_t offset;
538 : Type type;
539 : TypeResult *next;
540 :
541 2817 : TypeResult(uint32_t offset, Type type)
542 2817 : : offset(offset), type(type), next(NULL)
543 2817 : {}
544 : };
545 :
546 : /*
547 : * Type barriers overview.
548 : *
549 : * Type barriers are a technique for using dynamic type information to improve
550 : * the inferred types within scripts. At certain opcodes --- those with the
551 : * JOF_TYPESET format --- we will construct a type set storing the set of types
552 : * which we have observed to be pushed at that opcode, and will only use those
553 : * observed types when doing propagation downstream from the bytecode. For
554 : * example, in the following script:
555 : *
556 : * function foo(x) {
557 : * return x.f + 10;
558 : * }
559 : *
560 : * Suppose we know the type of 'x' and that the type of its 'f' property is
561 : * either an int or float. To account for all possible behaviors statically,
562 : * we would mark the result of the 'x.f' access as an int or float, as well
563 : * as the result of the addition and the return value of foo (and everywhere
564 : * the result of 'foo' is used). When dealing with polymorphic code, this is
565 : * undesirable behavior --- the type imprecision surrounding the polymorphism
566 : * will tend to leak to many places in the program.
567 : *
568 : * Instead, we will keep track of the types that have been dynamically observed
569 : * to have been produced by the 'x.f', and only use those observed types
570 : * downstream from the access. If the 'x.f' has only ever produced integers,
571 : * we will treat its result as an integer and mark the result of foo as an
572 : * integer.
573 : *
574 : * The set of observed types will be a subset of the set of possible types,
575 : * and if the two sets are different, a type barriers will be added at the
576 : * bytecode which checks the dynamic result every time the bytecode executes
577 : * and makes sure it is in the set of observed types. If it is not, that
578 : * observed set is updated, and the new type information is automatically
579 : * propagated along the already-generated type constraints to the places
580 : * where the result of the bytecode is used.
581 : *
582 : * Observing new types at a bytecode removes type barriers at the bytecode
583 : * (this removal happens lazily, see ScriptAnalysis::pruneTypeBarriers), and if
584 : * all type barriers at a bytecode are removed --- the set of observed types
585 : * grows to match the set of possible types --- then the result of the bytecode
586 : * no longer needs to be dynamically checked (unless the set of possible types
587 : * grows, triggering the generation of new type barriers).
588 : *
589 : * Barriers are only relevant for accesses on properties whose types inference
590 : * actually tracks (see propertySet comment under TypeObject). Accesses on
591 : * other properties may be able to produce additional unobserved types even
592 : * without a barrier present, and can only be compiled to jitcode with special
593 : * knowledge of the property in question (e.g. for lengths of arrays, or
594 : * elements of typed arrays).
595 : */
596 :
597 : /*
598 : * Barrier introduced at some bytecode. These are added when, during inference,
599 : * we block a type from being propagated as would normally be done for a subset
600 : * constraint. The propagation is technically possible, but we suspect it will
601 : * not happen dynamically and this type needs to be watched for. These are only
602 : * added at reads of properties and at scripted call sites.
603 : */
604 : struct TypeBarrier
605 : {
606 : /* Next barrier on the same bytecode. */
607 : TypeBarrier *next;
608 :
609 : /* Target type set into which propagation was blocked. */
610 : TypeSet *target;
611 :
612 : /*
613 : * Type which was not added to the target. If target ends up containing the
614 : * type somehow, this barrier can be removed.
615 : */
616 : Type type;
617 :
618 : /*
619 : * If specified, this barrier can be removed if object has a non-undefined
620 : * value in property id.
621 : */
622 : JSObject *singleton;
623 : jsid singletonId;
624 :
625 543279 : TypeBarrier(TypeSet *target, Type type, JSObject *singleton, jsid singletonId)
626 : : next(NULL), target(target), type(type),
627 543279 : singleton(singleton), singletonId(singletonId)
628 543279 : {}
629 : };
630 :
631 : /* Type information about a property. */
632 : struct Property
633 10767 : {
634 : /* Identifier for this property, JSID_VOID for the aggregate integer index property. */
635 : HeapId id;
636 :
637 : /* Possible types for this property, including types inherited from prototypes. */
638 : TypeSet types;
639 :
640 : inline Property(jsid id);
641 : inline Property(const Property &o);
642 :
643 678104 : static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); }
644 24501410 : static jsid getKey(Property *p) { return p->id; }
645 : };
646 :
647 : /*
648 : * Information attached to a TypeObject if it is always constructed using 'new'
649 : * on a particular script. This is used to manage state related to the definite
650 : * properties on the type object: these definite properties depend on type
651 : * information which could change as the script executes (e.g. a scripted
652 : * setter is added to a prototype object), and we need to ensure both that the
653 : * appropriate type constraints are in place when necessary, and that we can
654 : * remove the definite property information and repair the JS stack if the
655 : * constraints are violated.
656 : */
657 : struct TypeNewScript
658 : {
659 : HeapPtrFunction fun;
660 :
661 : /* Allocation kind to use for newly constructed objects. */
662 : gc::AllocKind allocKind;
663 :
664 : /*
665 : * Shape to use for newly constructed objects. Reflects all definite
666 : * properties the object will have.
667 : */
668 : HeapPtrShape shape;
669 :
670 : /*
671 : * Order in which properties become initialized. We need this in case a
672 : * scripted setter is added to one of the object's prototypes while it is
673 : * in the middle of being initialized, so we can walk the stack and fixup
674 : * any objects which look for in-progress objects which were prematurely
675 : * set with their final shape. Initialization can traverse stack frames,
676 : * in which case FRAME_PUSH/FRAME_POP are used.
677 : */
678 2974 : struct Initializer {
679 : enum Kind {
680 : SETPROP,
681 : FRAME_PUSH,
682 : FRAME_POP,
683 : DONE
684 : } kind;
685 : uint32_t offset;
686 1673 : Initializer(Kind kind, uint32_t offset)
687 1673 : : kind(kind), offset(offset)
688 1673 : {}
689 : };
690 : Initializer *initializerList;
691 :
692 : static inline void writeBarrierPre(TypeNewScript *newScript);
693 : static inline void writeBarrierPost(TypeNewScript *newScript, void *addr);
694 : };
695 :
696 : /*
697 : * Lazy type objects overview.
698 : *
699 : * Type objects which represent at most one JS object are constructed lazily.
700 : * These include types for native functions, standard classes, scripted
701 : * functions defined at the top level of global/eval scripts, and in some
702 : * other cases. Typical web workloads often create many windows (and many
703 : * copies of standard natives) and many scripts, with comparatively few
704 : * non-singleton types.
705 : *
706 : * We can recover the type information for the object from examining it,
707 : * so don't normally track the possible types of its properties as it is
708 : * updated. Property type sets for the object are only constructed when an
709 : * analyzed script attaches constraints to it: the script is querying that
710 : * property off the object or another which delegates to it, and the analysis
711 : * information is sensitive to changes in the property's type. Future changes
712 : * to the property (whether those uncovered by analysis or those occurring
713 : * in the VM) will treat these properties like those of any other type object.
714 : *
715 : * When a GC occurs, we wipe out all analysis information for all the
716 : * compartment's scripts, so can destroy all properties on singleton type
717 : * objects at the same time. If there is no reference on the stack to the
718 : * type object itself, the type object is also destroyed, and the JS object
719 : * reverts to having a lazy type.
720 : */
721 :
722 : /* Type information about an object accessed by a script. */
723 : struct TypeObject : gc::Cell
724 : {
725 : /* Prototype shared by objects using this type. */
726 : HeapPtrObject proto;
727 :
728 : /*
729 : * Whether there is a singleton JS object with this type. That JS object
730 : * must appear in type sets instead of this; we include the back reference
731 : * here to allow reverting the JS object to a lazy type.
732 : */
733 : HeapPtrObject singleton;
734 :
735 : /*
736 : * Value held by singleton if this is a standin type for a singleton JS
737 : * object whose type has not been constructed yet.
738 : */
739 : static const size_t LAZY_SINGLETON = 1;
740 151077379 : bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; }
741 :
742 : /* Flags for this object. */
743 : TypeObjectFlags flags;
744 :
745 : /*
746 : * Estimate of the contribution of this object to the type sets it appears in.
747 : * This is the sum of the sizes of those sets at the point when the object
748 : * was added.
749 : *
750 : * When the contribution exceeds the CONTRIBUTION_LIMIT, any type sets the
751 : * object is added to are instead marked as unknown. If we get to this point
752 : * we are probably not adding types which will let us do meaningful optimization
753 : * later, and we want to ensure in such cases that our time/space complexity
754 : * is linear, not worst-case cubic as it would otherwise be.
755 : */
756 : uint32_t contribution;
757 : static const uint32_t CONTRIBUTION_LIMIT = 2000;
758 :
759 : /*
760 : * If non-NULL, objects of this type have always been constructed using
761 : * 'new' on the specified script, which adds some number of properties to
762 : * the object in a definite order before the object escapes.
763 : */
764 : HeapPtr<TypeNewScript> newScript;
765 :
766 : /*
767 : * Properties of this object. This may contain JSID_VOID, representing the
768 : * types of all integer indexes of the object, and/or JSID_EMPTY, holding
769 : * constraints listening to changes to the object's state.
770 : *
771 : * The type sets in the properties of a type object describe the possible
772 : * values that can be read out of that property in actual JS objects.
773 : * Properties only account for native properties (those with a slot and no
774 : * specialized getter hook) and the elements of dense arrays. For accesses
775 : * on such properties, the correspondence is as follows:
776 : *
777 : * 1. If the type has unknownProperties(), the possible properties and
778 : * value types for associated JSObjects are unknown.
779 : *
780 : * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id
781 : * which is a property in obj, before obj->getProperty(id) the property
782 : * in type for id must reflect the result of the getProperty.
783 : *
784 : * There is an exception for properties of singleton JS objects which
785 : * are undefined at the point where the property was (lazily) generated.
786 : * In such cases the property type set will remain empty, and the
787 : * 'undefined' type will only be added after a subsequent assignment or
788 : * deletion. After these properties have been assigned a defined value,
789 : * the only way they can become undefined again is after such an assign
790 : * or deletion.
791 : *
792 : * We establish these by using write barriers on calls to setProperty and
793 : * defineProperty which are on native properties, and by using the inference
794 : * analysis to determine the side effects of code which is JIT-compiled.
795 : */
796 : Property **propertySet;
797 :
798 : /* If this is an interpreted function, the function object. */
799 : HeapPtrFunction interpretedFunction;
800 :
801 : #if JS_BITS_PER_WORD == 32
802 : void *padding;
803 : #endif
804 :
805 : inline TypeObject(JSObject *proto, bool isFunction, bool unknown);
806 :
807 14025 : bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); }
808 :
809 449621 : bool hasAnyFlags(TypeObjectFlags flags) {
810 449621 : JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
811 449621 : return !!(this->flags & flags);
812 : }
813 9596940 : bool hasAllFlags(TypeObjectFlags flags) {
814 9596940 : JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
815 9596940 : return (this->flags & flags) == flags;
816 : }
817 :
818 54311257 : bool unknownProperties() {
819 8198574 : JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES,
820 62509831 : hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));
821 54311257 : return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES);
822 : }
823 :
824 : /*
825 : * Get or create a property of this object. Only call this for properties which
826 : * a script accesses explicitly. 'assign' indicates whether this is for an
827 : * assignment, and the own types of the property will be used instead of
828 : * aggregate types.
829 : */
830 : inline TypeSet *getProperty(JSContext *cx, jsid id, bool assign);
831 :
832 : /* Get a property only if it already exists. */
833 : inline TypeSet *maybeGetProperty(JSContext *cx, jsid id);
834 :
835 : inline unsigned getPropertyCount();
836 : inline Property *getProperty(unsigned i);
837 :
838 : /* Set flags on this object which are implied by the specified key. */
839 : inline void setFlagsFromKey(JSContext *cx, JSProtoKey kind);
840 :
841 : /*
842 : * Get the global object which all objects of this type are parented to,
843 : * or NULL if there is none known.
844 : */
845 : inline JSObject *getGlobal();
846 :
847 : /* Helpers */
848 :
849 : bool addProperty(JSContext *cx, jsid id, Property **pprop);
850 : bool addDefiniteProperties(JSContext *cx, JSObject *obj);
851 : bool matchDefiniteProperties(JSObject *obj);
852 : void addPrototype(JSContext *cx, TypeObject *proto);
853 : void addPropertyType(JSContext *cx, jsid id, Type type);
854 : void addPropertyType(JSContext *cx, jsid id, const Value &value);
855 : void addPropertyType(JSContext *cx, const char *name, Type type);
856 : void addPropertyType(JSContext *cx, const char *name, const Value &value);
857 : void markPropertyConfigured(JSContext *cx, jsid id);
858 : void markStateChange(JSContext *cx);
859 : void setFlags(JSContext *cx, TypeObjectFlags flags);
860 : void markUnknown(JSContext *cx);
861 : void clearNewScript(JSContext *cx);
862 : void getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force = false);
863 :
864 : void print(JSContext *cx);
865 :
866 : inline void clearProperties();
867 : inline void sweep(FreeOp *fop);
868 :
869 : inline size_t computedSizeOfExcludingThis();
870 :
871 : void sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf);
872 :
873 : /*
874 : * Type objects don't have explicit finalizers. Memory owned by a type
875 : * object pending deletion is released when weak references are sweeped
876 : * from all the compartment's type objects.
877 : */
878 346138 : void finalize(FreeOp *fop) {}
879 :
880 : static inline void writeBarrierPre(TypeObject *type);
881 : static inline void writeBarrierPost(TypeObject *type, void *addr);
882 : static inline void readBarrier(TypeObject *type);
883 :
884 : static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
885 :
886 : private:
887 : inline uint32_t basePropertyCount() const;
888 : inline void setBasePropertyCount(uint32_t count);
889 :
890 : static void staticAsserts() {
891 : JS_STATIC_ASSERT(offsetof(TypeObject, proto) == offsetof(js::shadow::TypeObject, proto));
892 : }
893 : };
894 :
895 : /*
896 : * Entries for the per-compartment set of type objects which are the default
897 : * 'new' or the lazy types of some prototype.
898 : */
899 : struct TypeObjectEntry
900 : {
901 : typedef JSObject *Lookup;
902 :
903 : static inline HashNumber hash(JSObject *base);
904 : static inline bool match(TypeObject *key, JSObject *lookup);
905 : };
906 : typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
907 :
908 : /* Whether to use a new type object when calling 'new' at script/pc. */
909 : bool
910 : UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
911 :
912 : /* Whether to use a new type object for an initializer opcode at script/pc. */
913 : bool
914 : UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc);
915 :
916 : /*
917 : * Whether Array.prototype, or an object on its proto chain, has an
918 : * indexed property.
919 : */
920 : bool
921 : ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script);
922 :
923 : /*
924 : * Type information about a callsite. this is separated from the bytecode
925 : * information itself so we can handle higher order functions not called
926 : * directly via a bytecode.
927 : */
928 : struct TypeCallsite
929 : {
930 : JSScript *script;
931 : jsbytecode *pc;
932 :
933 : /* Whether this is a 'NEW' call. */
934 : bool isNew;
935 :
936 : /* Types of each argument to the call. */
937 : TypeSet **argumentTypes;
938 : unsigned argumentCount;
939 :
940 : /* Types of the this variable. */
941 : TypeSet *thisTypes;
942 :
943 : /* Type set receiving the return value of this call. */
944 : TypeSet *returnTypes;
945 :
946 : inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
947 : bool isNew, unsigned argumentCount);
948 : };
949 :
950 : /*
951 : * Information attached to outer and inner function scripts nested in one
952 : * another for tracking the reentrance state for outer functions. This state is
953 : * used to generate fast accesses to the args and vars of the outer function.
954 : *
955 : * A function is non-reentrant if, at any point in time, only the most recent
956 : * activation (i.e. call object) is live. An activation is live if either the
957 : * activation is on the stack, or a transitive inner function parented to the
958 : * activation is on the stack.
959 : *
960 : * Because inner functions can be (and, quite often, are) stored in object
961 : * properties and it is difficult to build a fast and robust escape analysis
962 : * to cope with such flow, we detect reentrance dynamically. For the outer
963 : * function, we keep track of the call object for the most recent activation,
964 : * and the number of frames for the function and its inner functions which are
965 : * on the stack.
966 : *
967 : * If the outer function is called while frames associated with a previous
968 : * activation are on the stack, the outer function is reentrant. If an inner
969 : * function is called whose scope does not match the most recent activation,
970 : * the outer function is reentrant.
971 : *
972 : * The situation gets trickier when there are several levels of nesting.
973 : *
974 : * function foo() {
975 : * var a;
976 : * function bar() {
977 : * var b;
978 : * function baz() { return a + b; }
979 : * }
980 : * }
981 : *
982 : * At calls to 'baz', we don't want to do the scope check for the activations
983 : * of both 'foo' and 'bar', but rather 'bar' only. For this to work, a call to
984 : * 'baz' which is a reentrant call on 'foo' must also be a reentrant call on
985 : * 'bar'. When 'foo' is called, we clear the most recent call object for 'bar'.
986 : */
987 : struct TypeScriptNesting
988 : {
989 : /*
990 : * If this is an inner function, the outer function. If non-NULL, this will
991 : * be the immediate nested parent of the script (even if that parent has
992 : * been marked reentrant). May be NULL even if the script has a nested
993 : * parent, if NAME accesses cannot be tracked into the parent (either the
994 : * script extends its scope with eval() etc., or the parent can make new
995 : * scope chain objects with 'let' or 'with').
996 : */
997 : JSScript *parent;
998 :
999 : /* If this is an outer function, list of inner functions. */
1000 : JSScript *children;
1001 :
1002 : /* Link for children list of parent. */
1003 : JSScript *next;
1004 :
1005 : /* If this is an outer function, the most recent activation. */
1006 : JSObject *activeCall;
1007 :
1008 : /*
1009 : * If this is an outer function, pointers to the most recent activation's
1010 : * arguments and variables arrays. These could be referring either to stack
1011 : * values in activeCall's frame (if it has not finished yet) or to the
1012 : * internal slots of activeCall (if the frame has finished). Pointers to
1013 : * these fields can be embedded directly in JIT code (though remember to
1014 : * use 'addDependency == true' when calling resolveNameAccess).
1015 : */
1016 : const Value *argArray;
1017 : const Value *varArray;
1018 :
1019 : /* Number of frames for this function on the stack. */
1020 : uint32_t activeFrames;
1021 :
1022 4815 : TypeScriptNesting() { PodZero(this); }
1023 : ~TypeScriptNesting();
1024 : };
1025 :
1026 : /* Construct nesting information for script wrt its parent. */
1027 : bool CheckScriptNesting(JSContext *cx, JSScript *script);
1028 :
1029 : /* Track nesting state when calling or finishing an outer/inner function. */
1030 : void NestingPrologue(JSContext *cx, StackFrame *fp);
1031 : void NestingEpilogue(StackFrame *fp);
1032 :
1033 : /* Persistent type information for a script, retained across GCs. */
1034 : class TypeScript
1035 : {
1036 : friend struct ::JSScript;
1037 :
1038 : /* Analysis information for the script, cleared on each GC. */
1039 : analyze::ScriptAnalysis *analysis;
1040 :
1041 : /*
1042 : * Information about the scope in which a script executes. This information
1043 : * is not set until the script has executed at least once and SetScope
1044 : * called, before that 'global' will be poisoned per GLOBAL_MISSING_SCOPE.
1045 : */
1046 : static const size_t GLOBAL_MISSING_SCOPE = 0x1;
1047 :
1048 : /* Global object for the script, if compileAndGo. */
1049 : HeapPtr<GlobalObject> global;
1050 :
1051 : public:
1052 :
1053 : /* Nesting state for outer or inner function scripts. */
1054 : TypeScriptNesting *nesting;
1055 :
1056 : /* Dynamic types generated at points within this script. */
1057 : TypeResult *dynamicList;
1058 :
1059 : inline TypeScript();
1060 :
1061 160395227 : bool hasScope() { return size_t(global.get()) != GLOBAL_MISSING_SCOPE; }
1062 :
1063 : /* Array of type type sets for variables and JOF_TYPESET ops. */
1064 75373137 : TypeSet *typeArray() { return (TypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
1065 :
1066 : static inline unsigned NumTypeSets(JSScript *script);
1067 :
1068 : static bool SetScope(JSContext *cx, JSScript *script, JSObject *scope);
1069 :
1070 : static inline TypeSet *ReturnTypes(JSScript *script);
1071 : static inline TypeSet *ThisTypes(JSScript *script);
1072 : static inline TypeSet *ArgTypes(JSScript *script, unsigned i);
1073 : static inline TypeSet *LocalTypes(JSScript *script, unsigned i);
1074 :
1075 : /* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
1076 : static inline TypeSet *SlotTypes(JSScript *script, unsigned slot);
1077 :
1078 : #ifdef DEBUG
1079 : /* Check that correct types were inferred for the values pushed by this bytecode. */
1080 : static void CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp);
1081 : #endif
1082 :
1083 : /* Get the default 'new' object for a given standard class, per the script's global. */
1084 : static inline TypeObject *StandardType(JSContext *cx, JSScript *script, JSProtoKey kind);
1085 :
1086 : /* Get a type object for an allocation site in this script. */
1087 : static inline TypeObject *InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind);
1088 :
1089 : /*
1090 : * Monitor a bytecode pushing a value which is not accounted for by the
1091 : * inference type constraints, such as integer overflow.
1092 : */
1093 : static inline void MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc);
1094 : static inline void MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc);
1095 : static inline void MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc);
1096 :
1097 : static inline void GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc);
1098 : static inline void MonitorOverflow(JSContext *cx);
1099 : static inline void MonitorString(JSContext *cx);
1100 : static inline void MonitorUnknown(JSContext *cx);
1101 :
1102 : /*
1103 : * Monitor a bytecode pushing any value. This must be called for any opcode
1104 : * which is JOF_TYPESET, and where either the script has not been analyzed
1105 : * by type inference or where the pc has type barriers. For simplicity, we
1106 : * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
1107 : * and only look at barriers when generating JIT code for the script.
1108 : */
1109 : static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
1110 : const js::Value &val);
1111 : static inline void Monitor(JSContext *cx, const js::Value &rval);
1112 :
1113 : /* Monitor an assignment at a SETELEM on a non-integer identifier. */
1114 : static inline void MonitorAssign(JSContext *cx, JSObject *obj, jsid id);
1115 :
1116 : /* Add a type for a variable in a script. */
1117 : static inline void SetThis(JSContext *cx, JSScript *script, Type type);
1118 : static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
1119 : static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type);
1120 : static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value);
1121 : static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
1122 : static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
1123 :
1124 : static void Sweep(FreeOp *fop, JSScript *script);
1125 : inline void trace(JSTracer *trc);
1126 : void destroy();
1127 : };
1128 :
1129 : struct ArrayTableKey;
1130 : typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
1131 :
1132 : struct ObjectTableKey;
1133 : struct ObjectTableEntry;
1134 : typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
1135 :
1136 : struct AllocationSiteKey;
1137 : typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable;
1138 :
1139 : struct RecompileInfo
1140 34838 : {
1141 : JSScript *script;
1142 : bool constructing:1;
1143 : uint32_t chunkIndex:31;
1144 :
1145 262493 : bool operator == (const RecompileInfo &o) const {
1146 262493 : return script == o.script && constructing == o.constructing && chunkIndex == o.chunkIndex;
1147 : }
1148 : };
1149 :
1150 : /* Type information for a compartment. */
1151 : struct TypeCompartment
1152 : {
1153 : /* Whether type inference is enabled in this compartment. */
1154 : bool inferenceEnabled;
1155 :
1156 : /* Number of scripts in this compartment. */
1157 : unsigned scriptCount;
1158 :
1159 : /*
1160 : * Bit set if all current types must be marked as unknown, and all scripts
1161 : * recompiled. Caused by OOM failure within inference operations.
1162 : */
1163 : bool pendingNukeTypes;
1164 :
1165 : /* Pending recompilations to perform before execution of JIT code can resume. */
1166 : Vector<RecompileInfo> *pendingRecompiles;
1167 :
1168 : /*
1169 : * Number of recompilation events and inline frame expansions that have
1170 : * occurred in this compartment. If these change, code should not count on
1171 : * compiled code or the current stack being intact.
1172 : */
1173 : unsigned recompilations;
1174 : unsigned frameExpansions;
1175 :
1176 : /*
1177 : * Script currently being compiled. All constraints which look for type
1178 : * changes inducing recompilation are keyed to this script. Note: script
1179 : * compilation is not reentrant.
1180 : */
1181 : RecompileInfo compiledInfo;
1182 :
1183 : /* Table for referencing types of objects keyed to an allocation site. */
1184 : AllocationSiteTable *allocationSiteTable;
1185 :
1186 : /* Tables for determining types of singleton/JSON objects. */
1187 :
1188 : ArrayTypeTable *arrayTypeTable;
1189 : ObjectTypeTable *objectTypeTable;
1190 :
1191 : void fixArrayType(JSContext *cx, JSObject *obj);
1192 : void fixObjectType(JSContext *cx, JSObject *obj);
1193 :
1194 : /* Constraint solving worklist structures. */
1195 :
1196 : /*
1197 : * Worklist of types which need to be propagated to constraints. We use a
1198 : * worklist to avoid blowing the native stack.
1199 : */
1200 : struct PendingWork
1201 : {
1202 : TypeConstraint *constraint;
1203 : TypeSet *source;
1204 : Type type;
1205 : };
1206 : PendingWork *pendingArray;
1207 : unsigned pendingCount;
1208 : unsigned pendingCapacity;
1209 :
1210 : /* Whether we are currently resolving the pending worklist. */
1211 : bool resolving;
1212 :
1213 : /* Logging fields */
1214 :
1215 : /* Counts of stack type sets with some number of possible operand types. */
1216 : static const unsigned TYPE_COUNT_LIMIT = 4;
1217 : unsigned typeCounts[TYPE_COUNT_LIMIT];
1218 : unsigned typeCountOver;
1219 :
1220 : void init(JSContext *cx);
1221 : ~TypeCompartment();
1222 :
1223 : inline JSCompartment *compartment();
1224 :
1225 : /* Add a type to register with a list of constraints. */
1226 : inline void addPending(JSContext *cx, TypeConstraint *constraint, TypeSet *source, Type type);
1227 : bool growPendingArray(JSContext *cx);
1228 :
1229 : /* Resolve pending type registrations, excluding delayed ones. */
1230 : inline void resolvePending(JSContext *cx);
1231 :
1232 : /* Prints results of this compartment if spew is enabled or force is set. */
1233 : void print(JSContext *cx, bool force);
1234 :
1235 : /*
1236 : * Make a function or non-function object associated with an optional
1237 : * script. The 'key' parameter here may be an array, typed array, function
1238 : * or JSProto_Object to indicate a type whose class is unknown (not just
1239 : * js_ObjectClass).
1240 : */
1241 : TypeObject *newTypeObject(JSContext *cx, JSScript *script,
1242 : JSProtoKey kind, JSObject *proto, bool unknown = false);
1243 :
1244 : /* Make an object for an allocation site. */
1245 : TypeObject *newAllocationSiteTypeObject(JSContext *cx, const AllocationSiteKey &key);
1246 :
1247 : void nukeTypes(FreeOp *fop);
1248 : void processPendingRecompiles(FreeOp *fop);
1249 :
1250 : /* Mark all types as needing destruction once inference has 'finished'. */
1251 : void setPendingNukeTypes(JSContext *cx);
1252 : void setPendingNukeTypesNoReport();
1253 :
1254 : /* Mark a script as needing recompilation once inference has finished. */
1255 : void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
1256 : void addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc);
1257 :
1258 : /* Monitor future effects on a bytecode. */
1259 : void monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
1260 : bool returnOnly = false);
1261 :
1262 : /* Mark any type set containing obj as having a generic object type. */
1263 : void markSetsUnknown(JSContext *cx, TypeObject *obj);
1264 :
1265 : void sweep(FreeOp *fop);
1266 : void finalizeObjects();
1267 : };
1268 :
1269 : enum SpewChannel {
1270 : ISpewOps, /* ops: New constraints and types. */
1271 : ISpewResult, /* result: Final type sets. */
1272 : SPEW_COUNT
1273 : };
1274 :
1275 : #ifdef DEBUG
1276 :
1277 : const char * InferSpewColorReset();
1278 : const char * InferSpewColor(TypeConstraint *constraint);
1279 : const char * InferSpewColor(TypeSet *types);
1280 :
1281 : void InferSpew(SpewChannel which, const char *fmt, ...);
1282 : const char * TypeString(Type type);
1283 : const char * TypeObjectString(TypeObject *type);
1284 :
1285 : /* Check that the type property for id in obj contains value. */
1286 : bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value);
1287 :
1288 : #else
1289 :
1290 : inline const char * InferSpewColorReset() { return NULL; }
1291 : inline const char * InferSpewColor(TypeConstraint *constraint) { return NULL; }
1292 : inline const char * InferSpewColor(TypeSet *types) { return NULL; }
1293 : inline void InferSpew(SpewChannel which, const char *fmt, ...) {}
1294 : inline const char * TypeString(Type type) { return NULL; }
1295 : inline const char * TypeObjectString(TypeObject *type) { return NULL; }
1296 :
1297 : #endif
1298 :
1299 : /* Print a warning, dump state and abort the program. */
1300 : void TypeFailure(JSContext *cx, const char *fmt, ...);
1301 :
1302 : } /* namespace types */
1303 : } /* namespace js */
1304 :
1305 : namespace JS {
1306 : template<> class AnchorPermitted<js::types::TypeObject *> { };
1307 : }
1308 :
1309 : #endif // jsinfer_h___
|