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