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