1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsinfer.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1657 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Definitions related to javascript type inference. */ 1.11 + 1.12 +#ifndef jsinfer_h 1.13 +#define jsinfer_h 1.14 + 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "mozilla/TypedEnum.h" 1.17 + 1.18 +#include "jsalloc.h" 1.19 +#include "jsfriendapi.h" 1.20 +#include "jstypes.h" 1.21 + 1.22 +#include "ds/IdValuePair.h" 1.23 +#include "ds/LifoAlloc.h" 1.24 +#include "gc/Barrier.h" 1.25 +#include "gc/Marking.h" 1.26 +#include "jit/IonTypes.h" 1.27 +#include "js/Utility.h" 1.28 +#include "js/Vector.h" 1.29 + 1.30 +namespace js { 1.31 + 1.32 +class TypeDescr; 1.33 + 1.34 +class TaggedProto 1.35 +{ 1.36 + public: 1.37 + static JSObject * const LazyProto; 1.38 + 1.39 + TaggedProto() : proto(nullptr) {} 1.40 + TaggedProto(JSObject *proto) : proto(proto) {} 1.41 + 1.42 + uintptr_t toWord() const { return uintptr_t(proto); } 1.43 + 1.44 + bool isLazy() const { 1.45 + return proto == LazyProto; 1.46 + } 1.47 + bool isObject() const { 1.48 + /* Skip nullptr and LazyProto. */ 1.49 + return uintptr_t(proto) > uintptr_t(TaggedProto::LazyProto); 1.50 + } 1.51 + JSObject *toObject() const { 1.52 + JS_ASSERT(isObject()); 1.53 + return proto; 1.54 + } 1.55 + JSObject *toObjectOrNull() const { 1.56 + JS_ASSERT(!proto || isObject()); 1.57 + return proto; 1.58 + } 1.59 + JSObject *raw() const { return proto; } 1.60 + 1.61 + bool operator ==(const TaggedProto &other) { return proto == other.proto; } 1.62 + bool operator !=(const TaggedProto &other) { return proto != other.proto; } 1.63 + 1.64 + private: 1.65 + JSObject *proto; 1.66 +}; 1.67 + 1.68 +template <> 1.69 +struct RootKind<TaggedProto> 1.70 +{ 1.71 + static ThingRootKind rootKind() { return THING_ROOT_OBJECT; } 1.72 +}; 1.73 + 1.74 +template <> struct GCMethods<const TaggedProto> 1.75 +{ 1.76 + static TaggedProto initial() { return TaggedProto(); } 1.77 + static ThingRootKind kind() { return THING_ROOT_OBJECT; } 1.78 + static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } 1.79 +}; 1.80 + 1.81 +template <> struct GCMethods<TaggedProto> 1.82 +{ 1.83 + static TaggedProto initial() { return TaggedProto(); } 1.84 + static ThingRootKind kind() { return THING_ROOT_OBJECT; } 1.85 + static bool poisoned(const TaggedProto &v) { return IsPoisonedPtr(v.raw()); } 1.86 +}; 1.87 + 1.88 +template<class Outer> 1.89 +class TaggedProtoOperations 1.90 +{ 1.91 + const TaggedProto *value() const { 1.92 + return static_cast<const Outer*>(this)->extract(); 1.93 + } 1.94 + 1.95 + public: 1.96 + uintptr_t toWord() const { return value()->toWord(); } 1.97 + inline bool isLazy() const { return value()->isLazy(); } 1.98 + inline bool isObject() const { return value()->isObject(); } 1.99 + inline JSObject *toObject() const { return value()->toObject(); } 1.100 + inline JSObject *toObjectOrNull() const { return value()->toObjectOrNull(); } 1.101 + JSObject *raw() const { return value()->raw(); } 1.102 +}; 1.103 + 1.104 +template <> 1.105 +class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto> > 1.106 +{ 1.107 + friend class TaggedProtoOperations<Handle<TaggedProto> >; 1.108 + const TaggedProto * extract() const { 1.109 + return static_cast<const Handle<TaggedProto>*>(this)->address(); 1.110 + } 1.111 +}; 1.112 + 1.113 +template <> 1.114 +class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto> > 1.115 +{ 1.116 + friend class TaggedProtoOperations<Rooted<TaggedProto> >; 1.117 + const TaggedProto *extract() const { 1.118 + return static_cast<const Rooted<TaggedProto> *>(this)->address(); 1.119 + } 1.120 +}; 1.121 + 1.122 +class CallObject; 1.123 + 1.124 +/* 1.125 + * Execution Mode Overview 1.126 + * 1.127 + * JavaScript code can execute either sequentially or in parallel, such as in 1.128 + * PJS. Functions which behave identically in either execution mode can take a 1.129 + * ThreadSafeContext, and functions which have similar but not identical 1.130 + * behavior between execution modes can be templated on the mode. Such 1.131 + * functions use a context parameter type from ExecutionModeTraits below 1.132 + * indicating whether they are only permitted constrained operations (such as 1.133 + * thread safety, and side effects limited to being thread-local), or whether 1.134 + * they can have arbitrary side effects. 1.135 + */ 1.136 + 1.137 +enum ExecutionMode { 1.138 + /* Normal JavaScript execution. */ 1.139 + SequentialExecution, 1.140 + 1.141 + /* 1.142 + * JavaScript code to be executed in parallel worker threads in PJS in a 1.143 + * fork join fashion. 1.144 + */ 1.145 + ParallelExecution, 1.146 + 1.147 + /* 1.148 + * Modes after this point are internal and are not counted in 1.149 + * NumExecutionModes below. 1.150 + */ 1.151 + 1.152 + /* 1.153 + * MIR analysis performed when invoking 'new' on a script, to determine 1.154 + * definite properties. Used by the optimizing JIT. 1.155 + */ 1.156 + DefinitePropertiesAnalysis, 1.157 + 1.158 + /* 1.159 + * MIR analysis performed when executing a script which uses its arguments, 1.160 + * when it is not known whether a lazy arguments value can be used. 1.161 + */ 1.162 + ArgumentsUsageAnalysis 1.163 +}; 1.164 + 1.165 +/* 1.166 + * Not as part of the enum so we don't get warnings about unhandled enum 1.167 + * values. 1.168 + */ 1.169 +static const unsigned NumExecutionModes = ParallelExecution + 1; 1.170 + 1.171 +template <ExecutionMode mode> 1.172 +struct ExecutionModeTraits 1.173 +{ 1.174 +}; 1.175 + 1.176 +template <> struct ExecutionModeTraits<SequentialExecution> 1.177 +{ 1.178 + typedef JSContext * ContextType; 1.179 + typedef ExclusiveContext * ExclusiveContextType; 1.180 + 1.181 + static inline JSContext *toContextType(ExclusiveContext *cx); 1.182 +}; 1.183 + 1.184 +template <> struct ExecutionModeTraits<ParallelExecution> 1.185 +{ 1.186 + typedef ForkJoinContext * ContextType; 1.187 + typedef ForkJoinContext * ExclusiveContextType; 1.188 + 1.189 + static inline ForkJoinContext *toContextType(ForkJoinContext *cx) { return cx; } 1.190 +}; 1.191 + 1.192 +namespace jit { 1.193 + struct IonScript; 1.194 + class IonAllocPolicy; 1.195 + class TempAllocator; 1.196 +} 1.197 + 1.198 +namespace types { 1.199 + 1.200 +class TypeZone; 1.201 +class TypeSet; 1.202 +class TypeObjectKey; 1.203 + 1.204 +/* 1.205 + * Information about a single concrete type. We pack this into a single word, 1.206 + * where small values are particular primitive or other singleton types, and 1.207 + * larger values are either specific JS objects or type objects. 1.208 + */ 1.209 +class Type 1.210 +{ 1.211 + uintptr_t data; 1.212 + Type(uintptr_t data) : data(data) {} 1.213 + 1.214 + public: 1.215 + 1.216 + uintptr_t raw() const { return data; } 1.217 + 1.218 + bool isPrimitive() const { 1.219 + return data < JSVAL_TYPE_OBJECT; 1.220 + } 1.221 + 1.222 + bool isPrimitive(JSValueType type) const { 1.223 + JS_ASSERT(type < JSVAL_TYPE_OBJECT); 1.224 + return (uintptr_t) type == data; 1.225 + } 1.226 + 1.227 + JSValueType primitive() const { 1.228 + JS_ASSERT(isPrimitive()); 1.229 + return (JSValueType) data; 1.230 + } 1.231 + 1.232 + bool isMagicArguments() const { 1.233 + return primitive() == JSVAL_TYPE_MAGIC; 1.234 + } 1.235 + 1.236 + bool isSomeObject() const { 1.237 + return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN; 1.238 + } 1.239 + 1.240 + bool isAnyObject() const { 1.241 + return data == JSVAL_TYPE_OBJECT; 1.242 + } 1.243 + 1.244 + bool isUnknown() const { 1.245 + return data == JSVAL_TYPE_UNKNOWN; 1.246 + } 1.247 + 1.248 + /* Accessors for types that are either JSObject or TypeObject. */ 1.249 + 1.250 + bool isObject() const { 1.251 + JS_ASSERT(!isAnyObject() && !isUnknown()); 1.252 + return data > JSVAL_TYPE_UNKNOWN; 1.253 + } 1.254 + 1.255 + bool isObjectUnchecked() const { 1.256 + return data > JSVAL_TYPE_UNKNOWN; 1.257 + } 1.258 + 1.259 + inline TypeObjectKey *objectKey() const; 1.260 + 1.261 + /* Accessors for JSObject types */ 1.262 + 1.263 + bool isSingleObject() const { 1.264 + return isObject() && !!(data & 1); 1.265 + } 1.266 + 1.267 + inline JSObject *singleObject() const; 1.268 + 1.269 + /* Accessors for TypeObject types */ 1.270 + 1.271 + bool isTypeObject() const { 1.272 + return isObject() && !(data & 1); 1.273 + } 1.274 + 1.275 + inline TypeObject *typeObject() const; 1.276 + 1.277 + bool operator == (Type o) const { return data == o.data; } 1.278 + bool operator != (Type o) const { return data != o.data; } 1.279 + 1.280 + static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); } 1.281 + static inline Type NullType() { return Type(JSVAL_TYPE_NULL); } 1.282 + static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); } 1.283 + static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); } 1.284 + static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); } 1.285 + static inline Type StringType() { return Type(JSVAL_TYPE_STRING); } 1.286 + static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); } 1.287 + static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); } 1.288 + static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); } 1.289 + 1.290 + static inline Type PrimitiveType(JSValueType type) { 1.291 + JS_ASSERT(type < JSVAL_TYPE_UNKNOWN); 1.292 + return Type(type); 1.293 + } 1.294 + 1.295 + static inline Type ObjectType(JSObject *obj); 1.296 + static inline Type ObjectType(TypeObject *obj); 1.297 + static inline Type ObjectType(TypeObjectKey *obj); 1.298 +}; 1.299 + 1.300 +/* Get the type of a jsval, or zero for an unknown special value. */ 1.301 +inline Type GetValueType(const Value &val); 1.302 + 1.303 +/* 1.304 + * Get the type of a possibly optimized out value. This generally only 1.305 + * happens on unconditional type monitors on bailing out of Ion, such as 1.306 + * for argument and local types. 1.307 + */ 1.308 +inline Type GetMaybeOptimizedOutValueType(const Value &val); 1.309 + 1.310 +/* 1.311 + * Type inference memory management overview. 1.312 + * 1.313 + * Type information about the values observed within scripts and about the 1.314 + * contents of the heap is accumulated as the program executes. Compilation 1.315 + * accumulates constraints relating type information on the heap with the 1.316 + * compilations that should be invalidated when those types change. Type 1.317 + * information and constraints are allocated in the zone's typeLifoAlloc, 1.318 + * and on GC all data referring to live things is copied into a new allocator. 1.319 + * Thus, type set and constraints only hold weak references. 1.320 + */ 1.321 + 1.322 +/* 1.323 + * A constraint which listens to additions to a type set and propagates those 1.324 + * changes to other type sets. 1.325 + */ 1.326 +class TypeConstraint 1.327 +{ 1.328 +public: 1.329 + /* Next constraint listening to the same type set. */ 1.330 + TypeConstraint *next; 1.331 + 1.332 + TypeConstraint() 1.333 + : next(nullptr) 1.334 + {} 1.335 + 1.336 + /* Debugging name for this kind of constraint. */ 1.337 + virtual const char *kind() = 0; 1.338 + 1.339 + /* Register a new type for the set this constraint is listening to. */ 1.340 + virtual void newType(JSContext *cx, TypeSet *source, Type type) = 0; 1.341 + 1.342 + /* 1.343 + * For constraints attached to an object property's type set, mark the 1.344 + * property as having its configuration changed. 1.345 + */ 1.346 + virtual void newPropertyState(JSContext *cx, TypeSet *source) {} 1.347 + 1.348 + /* 1.349 + * For constraints attached to the JSID_EMPTY type set on an object, 1.350 + * indicate a change in one of the object's dynamic property flags or other 1.351 + * state. 1.352 + */ 1.353 + virtual void newObjectState(JSContext *cx, TypeObject *object) {} 1.354 + 1.355 + /* 1.356 + * If the data this constraint refers to is still live, copy it into the 1.357 + * zone's new allocator. Type constraints only hold weak references. 1.358 + */ 1.359 + virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0; 1.360 +}; 1.361 + 1.362 +/* Flags and other state stored in TypeSet::flags */ 1.363 +enum MOZ_ENUM_TYPE(uint32_t) { 1.364 + TYPE_FLAG_UNDEFINED = 0x1, 1.365 + TYPE_FLAG_NULL = 0x2, 1.366 + TYPE_FLAG_BOOLEAN = 0x4, 1.367 + TYPE_FLAG_INT32 = 0x8, 1.368 + TYPE_FLAG_DOUBLE = 0x10, 1.369 + TYPE_FLAG_STRING = 0x20, 1.370 + TYPE_FLAG_LAZYARGS = 0x40, 1.371 + TYPE_FLAG_ANYOBJECT = 0x80, 1.372 + 1.373 + /* Mask containing all primitives */ 1.374 + TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN | 1.375 + TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING, 1.376 + 1.377 + /* Mask/shift for the number of objects in objectSet */ 1.378 + TYPE_FLAG_OBJECT_COUNT_MASK = 0x1f00, 1.379 + TYPE_FLAG_OBJECT_COUNT_SHIFT = 8, 1.380 + TYPE_FLAG_OBJECT_COUNT_LIMIT = 1.381 + TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT, 1.382 + 1.383 + /* Whether the contents of this type set are totally unknown. */ 1.384 + TYPE_FLAG_UNKNOWN = 0x00002000, 1.385 + 1.386 + /* Mask of normal type flags on a type set. */ 1.387 + TYPE_FLAG_BASE_MASK = 0x000020ff, 1.388 + 1.389 + /* Additional flags for HeapTypeSet sets. */ 1.390 + 1.391 + /* 1.392 + * Whether the property has ever been deleted or reconfigured to behave 1.393 + * differently from a plain data property, other than making the property 1.394 + * non-writable. 1.395 + */ 1.396 + TYPE_FLAG_NON_DATA_PROPERTY = 0x00004000, 1.397 + 1.398 + /* Whether the property has ever been made non-writable. */ 1.399 + TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00008000, 1.400 + 1.401 + /* 1.402 + * Whether the property is definitely in a particular slot on all objects 1.403 + * from which it has not been deleted or reconfigured. For singletons 1.404 + * this may be a fixed or dynamic slot, and for other objects this will be 1.405 + * a fixed slot. 1.406 + * 1.407 + * If the property is definite, mask and shift storing the slot + 1. 1.408 + * Otherwise these bits are clear. 1.409 + */ 1.410 + TYPE_FLAG_DEFINITE_MASK = 0xffff0000, 1.411 + TYPE_FLAG_DEFINITE_SHIFT = 16 1.412 +}; 1.413 +typedef uint32_t TypeFlags; 1.414 + 1.415 +/* Flags and other state stored in TypeObject::flags */ 1.416 +enum MOZ_ENUM_TYPE(uint32_t) { 1.417 + /* Whether this type object is associated with some allocation site. */ 1.418 + OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1, 1.419 + 1.420 + /* If set, addendum information should not be installed on this object. */ 1.421 + OBJECT_FLAG_ADDENDUM_CLEARED = 0x2, 1.422 + 1.423 + /* 1.424 + * If set, the object's prototype might be in the nursery and can't be 1.425 + * used during Ion compilation (which may be occurring off thread). 1.426 + */ 1.427 + OBJECT_FLAG_NURSERY_PROTO = 0x4, 1.428 + 1.429 + /* 1.430 + * Whether we have ensured all type sets in the compartment contain 1.431 + * ANYOBJECT instead of this object. 1.432 + */ 1.433 + OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x8, 1.434 + 1.435 + /* Mask/shift for the number of properties in propertySet */ 1.436 + OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff0, 1.437 + OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 4, 1.438 + OBJECT_FLAG_PROPERTY_COUNT_LIMIT = 1.439 + OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT, 1.440 + 1.441 + /* Whether any objects this represents may have sparse indexes. */ 1.442 + OBJECT_FLAG_SPARSE_INDEXES = 0x00010000, 1.443 + 1.444 + /* Whether any objects this represents may not have packed dense elements. */ 1.445 + OBJECT_FLAG_NON_PACKED = 0x00020000, 1.446 + 1.447 + /* 1.448 + * Whether any objects this represents may be arrays whose length does not 1.449 + * fit in an int32. 1.450 + */ 1.451 + OBJECT_FLAG_LENGTH_OVERFLOW = 0x00040000, 1.452 + 1.453 + /* Whether any objects have been iterated over. */ 1.454 + OBJECT_FLAG_ITERATED = 0x00080000, 1.455 + 1.456 + /* For a global object, whether flags were set on the RegExpStatics. */ 1.457 + OBJECT_FLAG_REGEXP_FLAGS_SET = 0x00100000, 1.458 + 1.459 + /* 1.460 + * For the function on a run-once script, whether the function has actually 1.461 + * run multiple times. 1.462 + */ 1.463 + OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000, 1.464 + 1.465 + /* 1.466 + * Whether objects with this type should be allocated directly in the 1.467 + * tenured heap. 1.468 + */ 1.469 + OBJECT_FLAG_PRE_TENURE = 0x00400000, 1.470 + 1.471 + /* 1.472 + * Whether all properties of this object are considered unknown. 1.473 + * If set, all other flags in DYNAMIC_MASK will also be set. 1.474 + */ 1.475 + OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x00800000, 1.476 + 1.477 + /* Flags which indicate dynamic properties of represented objects. */ 1.478 + OBJECT_FLAG_DYNAMIC_MASK = 0x00ff0000, 1.479 + 1.480 + /* Mask for objects created with unknown properties. */ 1.481 + OBJECT_FLAG_UNKNOWN_MASK = 1.482 + OBJECT_FLAG_DYNAMIC_MASK 1.483 + | OBJECT_FLAG_SETS_MARKED_UNKNOWN 1.484 +}; 1.485 +typedef uint32_t TypeObjectFlags; 1.486 + 1.487 +class StackTypeSet; 1.488 +class HeapTypeSet; 1.489 +class TemporaryTypeSet; 1.490 + 1.491 +/* 1.492 + * Information about the set of types associated with an lvalue. There are 1.493 + * three kinds of type sets: 1.494 + * 1.495 + * - StackTypeSet are associated with TypeScripts, for arguments and values 1.496 + * observed at property reads. These are implicitly frozen on compilation 1.497 + * and do not have constraints attached to them. 1.498 + * 1.499 + * - HeapTypeSet are associated with the properties of TypeObjects. These 1.500 + * may have constraints added to them to trigger invalidation of compiled 1.501 + * code. 1.502 + * 1.503 + * - TemporaryTypeSet are created during compilation and do not outlive 1.504 + * that compilation. 1.505 + */ 1.506 +class TypeSet 1.507 +{ 1.508 + protected: 1.509 + /* Flags for this type set. */ 1.510 + TypeFlags flags; 1.511 + 1.512 + /* Possible objects this type set can represent. */ 1.513 + TypeObjectKey **objectSet; 1.514 + 1.515 + public: 1.516 + 1.517 + TypeSet() 1.518 + : flags(0), objectSet(nullptr) 1.519 + {} 1.520 + 1.521 + void print(); 1.522 + 1.523 + /* Whether this set contains a specific type. */ 1.524 + inline bool hasType(Type type) const; 1.525 + 1.526 + TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; } 1.527 + bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); } 1.528 + bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); } 1.529 + bool empty() const { return !baseFlags() && !baseObjectCount(); } 1.530 + 1.531 + bool hasAnyFlag(TypeFlags flags) const { 1.532 + JS_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags); 1.533 + return !!(baseFlags() & flags); 1.534 + } 1.535 + 1.536 + bool nonDataProperty() const { 1.537 + return flags & TYPE_FLAG_NON_DATA_PROPERTY; 1.538 + } 1.539 + bool nonWritableProperty() const { 1.540 + return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY; 1.541 + } 1.542 + bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; } 1.543 + unsigned definiteSlot() const { 1.544 + JS_ASSERT(definiteProperty()); 1.545 + return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1; 1.546 + } 1.547 + 1.548 + /* Join two type sets into a new set. The result should not be modified further. */ 1.549 + static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc); 1.550 + 1.551 + /* Add a type to this set using the specified allocator. */ 1.552 + void addType(Type type, LifoAlloc *alloc); 1.553 + 1.554 + /* Get a list of all types in this set. */ 1.555 + typedef Vector<Type, 1, SystemAllocPolicy> TypeList; 1.556 + bool enumerateTypes(TypeList *list); 1.557 + 1.558 + /* 1.559 + * Iterate through the objects in this set. getObjectCount overapproximates 1.560 + * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject 1.561 + * may return nullptr. 1.562 + */ 1.563 + inline unsigned getObjectCount() const; 1.564 + inline TypeObjectKey *getObject(unsigned i) const; 1.565 + inline JSObject *getSingleObject(unsigned i) const; 1.566 + inline TypeObject *getTypeObject(unsigned i) const; 1.567 + 1.568 + /* The Class of an object in this set. */ 1.569 + inline const Class *getObjectClass(unsigned i) const; 1.570 + 1.571 + bool canSetDefinite(unsigned slot) { 1.572 + // Note: the cast is required to work around an MSVC issue. 1.573 + return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT); 1.574 + } 1.575 + void setDefinite(unsigned slot) { 1.576 + JS_ASSERT(canSetDefinite(slot)); 1.577 + flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT); 1.578 + JS_ASSERT(definiteSlot() == slot); 1.579 + } 1.580 + 1.581 + /* Whether any values in this set might have the specified type. */ 1.582 + bool mightBeMIRType(jit::MIRType type); 1.583 + 1.584 + /* 1.585 + * Get whether this type set is known to be a subset of other. 1.586 + * This variant doesn't freeze constraints. That variant is called knownSubset 1.587 + */ 1.588 + bool isSubset(TypeSet *other); 1.589 + 1.590 + /* Forward all types in this set to the specified constraint. */ 1.591 + bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint); 1.592 + 1.593 + // Clone a type set into an arbitrary allocator. 1.594 + TemporaryTypeSet *clone(LifoAlloc *alloc) const; 1.595 + bool clone(LifoAlloc *alloc, TemporaryTypeSet *result) const; 1.596 + 1.597 + // Create a new TemporaryTypeSet where undefined and/or null has been filtered out. 1.598 + TemporaryTypeSet *filter(LifoAlloc *alloc, bool filterUndefined, bool filterNull) const; 1.599 + 1.600 + protected: 1.601 + uint32_t baseObjectCount() const { 1.602 + return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT; 1.603 + } 1.604 + inline void setBaseObjectCount(uint32_t count); 1.605 + 1.606 + void clearObjects(); 1.607 +}; 1.608 + 1.609 +/* Superclass common to stack and heap type sets. */ 1.610 +class ConstraintTypeSet : public TypeSet 1.611 +{ 1.612 + public: 1.613 + /* Chain of constraints which propagate changes out from this type set. */ 1.614 + TypeConstraint *constraintList; 1.615 + 1.616 + ConstraintTypeSet() : constraintList(nullptr) {} 1.617 + 1.618 + /* 1.619 + * Add a type to this set, calling any constraint handlers if this is a new 1.620 + * possible type. 1.621 + */ 1.622 + void addType(ExclusiveContext *cx, Type type); 1.623 + 1.624 + /* Add a new constraint to this set. */ 1.625 + bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true); 1.626 + 1.627 + inline void sweep(JS::Zone *zone, bool *oom); 1.628 +}; 1.629 + 1.630 +class StackTypeSet : public ConstraintTypeSet 1.631 +{ 1.632 + public: 1.633 +}; 1.634 + 1.635 +class HeapTypeSet : public ConstraintTypeSet 1.636 +{ 1.637 + inline void newPropertyState(ExclusiveContext *cx); 1.638 + 1.639 + public: 1.640 + /* Mark this type set as representing a non-data property. */ 1.641 + inline void setNonDataProperty(ExclusiveContext *cx); 1.642 + inline void setNonDataPropertyIgnoringConstraints(); // Variant for use during GC. 1.643 + 1.644 + /* Mark this type set as representing a non-writable property. */ 1.645 + inline void setNonWritableProperty(ExclusiveContext *cx); 1.646 +}; 1.647 + 1.648 +class CompilerConstraintList; 1.649 + 1.650 +CompilerConstraintList * 1.651 +NewCompilerConstraintList(jit::TempAllocator &alloc); 1.652 + 1.653 +class TemporaryTypeSet : public TypeSet 1.654 +{ 1.655 + public: 1.656 + TemporaryTypeSet() {} 1.657 + TemporaryTypeSet(Type type); 1.658 + 1.659 + TemporaryTypeSet(uint32_t flags, TypeObjectKey **objectSet) { 1.660 + this->flags = flags; 1.661 + this->objectSet = objectSet; 1.662 + } 1.663 + 1.664 + /* 1.665 + * Constraints for JIT compilation. 1.666 + * 1.667 + * Methods for JIT compilation. These must be used when a script is 1.668 + * currently being compiled (see AutoEnterCompilation) and will add 1.669 + * constraints ensuring that if the return value change in the future due 1.670 + * to new type information, the script's jitcode will be discarded. 1.671 + */ 1.672 + 1.673 + /* Get any type tag which all values in this set must have. */ 1.674 + jit::MIRType getKnownMIRType(); 1.675 + 1.676 + bool isMagicArguments() { return getKnownMIRType() == jit::MIRType_MagicOptimizedArguments; } 1.677 + 1.678 + /* Whether this value may be an object. */ 1.679 + bool maybeObject() { return unknownObject() || baseObjectCount() > 0; } 1.680 + 1.681 + /* 1.682 + * Whether this typeset represents a potentially sentineled object value: 1.683 + * the value may be an object or null or undefined. 1.684 + * Returns false if the value cannot ever be an object. 1.685 + */ 1.686 + bool objectOrSentinel() { 1.687 + TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT; 1.688 + if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK)) 1.689 + return false; 1.690 + 1.691 + return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0; 1.692 + } 1.693 + 1.694 + /* Whether the type set contains objects with any of a set of flags. */ 1.695 + bool hasObjectFlags(CompilerConstraintList *constraints, TypeObjectFlags flags); 1.696 + 1.697 + /* Get the class shared by all objects in this set, or nullptr. */ 1.698 + const Class *getKnownClass(); 1.699 + 1.700 + /* Result returned from forAllClasses */ 1.701 + enum ForAllResult { 1.702 + EMPTY=1, // Set empty 1.703 + ALL_TRUE, // Set not empty and predicate returned true for all classes 1.704 + ALL_FALSE, // Set not empty and predicate returned false for all classes 1.705 + MIXED, // Set not empty and predicate returned false for some classes 1.706 + // and true for others, or set contains an unknown or non-object 1.707 + // type 1.708 + }; 1.709 + 1.710 + /* Apply func to the members of the set and return an appropriate result. 1.711 + * The iteration may end early if the result becomes known early. 1.712 + */ 1.713 + ForAllResult forAllClasses(bool (*func)(const Class *clasp)); 1.714 + 1.715 + /* Get the prototype shared by all objects in this set, or nullptr. */ 1.716 + JSObject *getCommonPrototype(); 1.717 + 1.718 + /* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */ 1.719 + int getTypedArrayType(); 1.720 + 1.721 + /* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */ 1.722 + bool isDOMClass(); 1.723 + 1.724 + /* Whether clasp->isCallable() is true for one or more objects in this set. */ 1.725 + bool maybeCallable(); 1.726 + 1.727 + /* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */ 1.728 + bool maybeEmulatesUndefined(); 1.729 + 1.730 + /* Get the single value which can appear in this type set, otherwise nullptr. */ 1.731 + JSObject *getSingleton(); 1.732 + 1.733 + /* Whether any objects in the type set needs a barrier on id. */ 1.734 + bool propertyNeedsBarrier(CompilerConstraintList *constraints, jsid id); 1.735 + 1.736 + /* 1.737 + * Whether this set contains all types in other, except (possibly) the 1.738 + * specified type. 1.739 + */ 1.740 + bool filtersType(const TemporaryTypeSet *other, Type type) const; 1.741 + 1.742 + enum DoubleConversion { 1.743 + /* All types in the set should use eager double conversion. */ 1.744 + AlwaysConvertToDoubles, 1.745 + 1.746 + /* Some types in the set should use eager double conversion. */ 1.747 + MaybeConvertToDoubles, 1.748 + 1.749 + /* No types should use eager double conversion. */ 1.750 + DontConvertToDoubles, 1.751 + 1.752 + /* Some types should use eager double conversion, others cannot. */ 1.753 + AmbiguousDoubleConversion 1.754 + }; 1.755 + 1.756 + /* 1.757 + * Whether known double optimizations are possible for element accesses on 1.758 + * objects in this type set. 1.759 + */ 1.760 + DoubleConversion convertDoubleElements(CompilerConstraintList *constraints); 1.761 +}; 1.762 + 1.763 +bool 1.764 +AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id); 1.765 + 1.766 +bool 1.767 +AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type, 1.768 + JSScript *script, JSScript *calleeScript); 1.769 + 1.770 +/* Is this a reasonable PC to be doing inlining on? */ 1.771 +inline bool isInlinableCall(jsbytecode *pc); 1.772 + 1.773 +/* Type information about a property. */ 1.774 +struct Property 1.775 +{ 1.776 + /* Identifier for this property, JSID_VOID for the aggregate integer index property. */ 1.777 + HeapId id; 1.778 + 1.779 + /* Possible types for this property, including types inherited from prototypes. */ 1.780 + HeapTypeSet types; 1.781 + 1.782 + Property(jsid id) 1.783 + : id(id) 1.784 + {} 1.785 + 1.786 + Property(const Property &o) 1.787 + : id(o.id.get()), types(o.types) 1.788 + {} 1.789 + 1.790 + static uint32_t keyBits(jsid id) { return uint32_t(JSID_BITS(id)); } 1.791 + static jsid getKey(Property *p) { return p->id; } 1.792 +}; 1.793 + 1.794 +struct TypeNewScript; 1.795 +struct TypeTypedObject; 1.796 + 1.797 +struct TypeObjectAddendum 1.798 +{ 1.799 + enum Kind { 1.800 + NewScript, 1.801 + TypedObject 1.802 + }; 1.803 + 1.804 + TypeObjectAddendum(Kind kind); 1.805 + 1.806 + const Kind kind; 1.807 + 1.808 + bool isNewScript() { 1.809 + return kind == NewScript; 1.810 + } 1.811 + 1.812 + TypeNewScript *asNewScript() { 1.813 + JS_ASSERT(isNewScript()); 1.814 + return (TypeNewScript*) this; 1.815 + } 1.816 + 1.817 + bool isTypedObject() { 1.818 + return kind == TypedObject; 1.819 + } 1.820 + 1.821 + TypeTypedObject *asTypedObject() { 1.822 + JS_ASSERT(isTypedObject()); 1.823 + return (TypeTypedObject*) this; 1.824 + } 1.825 + 1.826 + static inline void writeBarrierPre(TypeObjectAddendum *type); 1.827 + 1.828 + static void writeBarrierPost(TypeObjectAddendum *newScript, void *addr) {} 1.829 +}; 1.830 + 1.831 +/* 1.832 + * Information attached to a TypeObject if it is always constructed using 'new' 1.833 + * on a particular script. This is used to manage state related to the definite 1.834 + * properties on the type object: these definite properties depend on type 1.835 + * information which could change as the script executes (e.g. a scripted 1.836 + * setter is added to a prototype object), and we need to ensure both that the 1.837 + * appropriate type constraints are in place when necessary, and that we can 1.838 + * remove the definite property information and repair the JS stack if the 1.839 + * constraints are violated. 1.840 + */ 1.841 +struct TypeNewScript : public TypeObjectAddendum 1.842 +{ 1.843 + TypeNewScript(); 1.844 + 1.845 + HeapPtrFunction fun; 1.846 + 1.847 + /* 1.848 + * Template object to use for newly constructed objects. Reflects all 1.849 + * definite properties the object will have and the allocation kind to use 1.850 + * for the object. The allocation kind --- and template object itself --- 1.851 + * is subject to change if objects allocated with this type are given 1.852 + * dynamic slots later on due to new properties being added after the 1.853 + * constructor function finishes. 1.854 + */ 1.855 + HeapPtrObject templateObject; 1.856 + 1.857 + /* 1.858 + * Order in which properties become initialized. We need this in case a 1.859 + * scripted setter is added to one of the object's prototypes while it is 1.860 + * in the middle of being initialized, so we can walk the stack and fixup 1.861 + * any objects which look for in-progress objects which were prematurely 1.862 + * set with their final shape. Property assignments in inner frames are 1.863 + * preceded by a series of SETPROP_FRAME entries specifying the stack down 1.864 + * to the frame containing the write. 1.865 + */ 1.866 + struct Initializer { 1.867 + enum Kind { 1.868 + SETPROP, 1.869 + SETPROP_FRAME, 1.870 + DONE 1.871 + } kind; 1.872 + uint32_t offset; 1.873 + Initializer(Kind kind, uint32_t offset) 1.874 + : kind(kind), offset(offset) 1.875 + {} 1.876 + }; 1.877 + Initializer *initializerList; 1.878 + 1.879 + static inline void writeBarrierPre(TypeNewScript *newScript); 1.880 +}; 1.881 + 1.882 +struct TypeTypedObject : public TypeObjectAddendum 1.883 +{ 1.884 + private: 1.885 + HeapPtrObject descr_; 1.886 + 1.887 + public: 1.888 + TypeTypedObject(Handle<TypeDescr*> descr); 1.889 + 1.890 + HeapPtrObject &descrHeapPtr() { 1.891 + return descr_; 1.892 + } 1.893 + 1.894 + TypeDescr &descr(); 1.895 +}; 1.896 + 1.897 +/* 1.898 + * Lazy type objects overview. 1.899 + * 1.900 + * Type objects which represent at most one JS object are constructed lazily. 1.901 + * These include types for native functions, standard classes, scripted 1.902 + * functions defined at the top level of global/eval scripts, and in some 1.903 + * other cases. Typical web workloads often create many windows (and many 1.904 + * copies of standard natives) and many scripts, with comparatively few 1.905 + * non-singleton types. 1.906 + * 1.907 + * We can recover the type information for the object from examining it, 1.908 + * so don't normally track the possible types of its properties as it is 1.909 + * updated. Property type sets for the object are only constructed when an 1.910 + * analyzed script attaches constraints to it: the script is querying that 1.911 + * property off the object or another which delegates to it, and the analysis 1.912 + * information is sensitive to changes in the property's type. Future changes 1.913 + * to the property (whether those uncovered by analysis or those occurring 1.914 + * in the VM) will treat these properties like those of any other type object. 1.915 + */ 1.916 + 1.917 +/* Type information about an object accessed by a script. */ 1.918 +struct TypeObject : gc::BarrieredCell<TypeObject> 1.919 +{ 1.920 + private: 1.921 + /* Class shared by object using this type. */ 1.922 + const Class *clasp_; 1.923 + 1.924 + /* Prototype shared by objects using this type. */ 1.925 + HeapPtrObject proto_; 1.926 + 1.927 + /* 1.928 + * Whether there is a singleton JS object with this type. That JS object 1.929 + * must appear in type sets instead of this; we include the back reference 1.930 + * here to allow reverting the JS object to a lazy type. 1.931 + */ 1.932 + HeapPtrObject singleton_; 1.933 + 1.934 + public: 1.935 + 1.936 + const Class *clasp() const { 1.937 + return clasp_; 1.938 + } 1.939 + 1.940 + void setClasp(const Class *clasp) { 1.941 + JS_ASSERT(singleton()); 1.942 + clasp_ = clasp; 1.943 + } 1.944 + 1.945 + TaggedProto proto() const { 1.946 + return TaggedProto(proto_); 1.947 + } 1.948 + 1.949 + JSObject *singleton() const { 1.950 + return singleton_; 1.951 + } 1.952 + 1.953 + // For use during marking, don't call otherwise. 1.954 + HeapPtrObject &protoRaw() { return proto_; } 1.955 + HeapPtrObject &singletonRaw() { return singleton_; } 1.956 + 1.957 + void setProto(JSContext *cx, TaggedProto proto); 1.958 + void setProtoUnchecked(TaggedProto proto) { 1.959 + proto_ = proto.raw(); 1.960 + } 1.961 + 1.962 + void initSingleton(JSObject *singleton) { 1.963 + singleton_ = singleton; 1.964 + } 1.965 + 1.966 + /* 1.967 + * Value held by singleton if this is a standin type for a singleton JS 1.968 + * object whose type has not been constructed yet. 1.969 + */ 1.970 + static const size_t LAZY_SINGLETON = 1; 1.971 + bool lazy() const { return singleton() == (JSObject *) LAZY_SINGLETON; } 1.972 + 1.973 + private: 1.974 + /* Flags for this object. */ 1.975 + TypeObjectFlags flags_; 1.976 + 1.977 + /* 1.978 + * This field allows various special classes of objects to attach 1.979 + * additional information to a type object: 1.980 + * 1.981 + * - `TypeNewScript`: If addendum is a `TypeNewScript`, it 1.982 + * indicates that objects of this type have always been 1.983 + * constructed using 'new' on the specified script, which adds 1.984 + * some number of properties to the object in a definite order 1.985 + * before the object escapes. 1.986 + */ 1.987 + HeapPtr<TypeObjectAddendum> addendum; 1.988 + public: 1.989 + 1.990 + TypeObjectFlags flags() const { 1.991 + return flags_; 1.992 + } 1.993 + 1.994 + void addFlags(TypeObjectFlags flags) { 1.995 + flags_ |= flags; 1.996 + } 1.997 + 1.998 + void clearFlags(TypeObjectFlags flags) { 1.999 + flags_ &= ~flags; 1.1000 + } 1.1001 + 1.1002 + bool hasNewScript() const { 1.1003 + return addendum && addendum->isNewScript(); 1.1004 + } 1.1005 + 1.1006 + TypeNewScript *newScript() { 1.1007 + return addendum->asNewScript(); 1.1008 + } 1.1009 + 1.1010 + bool hasTypedObject() { 1.1011 + return addendum && addendum->isTypedObject(); 1.1012 + } 1.1013 + 1.1014 + TypeTypedObject *typedObject() { 1.1015 + return addendum->asTypedObject(); 1.1016 + } 1.1017 + 1.1018 + void setAddendum(TypeObjectAddendum *addendum); 1.1019 + 1.1020 + /* 1.1021 + * Tag the type object for a binary data type descriptor, instance, 1.1022 + * or handle with the type representation of the data it points at. 1.1023 + * If this type object is already tagged with a binary data addendum, 1.1024 + * this addendum must already be associated with the same TypeRepresentation, 1.1025 + * and the method has no effect. 1.1026 + */ 1.1027 + bool addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr); 1.1028 + 1.1029 + private: 1.1030 + /* 1.1031 + * Properties of this object. This may contain JSID_VOID, representing the 1.1032 + * types of all integer indexes of the object, and/or JSID_EMPTY, holding 1.1033 + * constraints listening to changes to the object's state. 1.1034 + * 1.1035 + * The type sets in the properties of a type object describe the possible 1.1036 + * values that can be read out of that property in actual JS objects. 1.1037 + * Properties only account for native properties (those with a slot and no 1.1038 + * specialized getter hook) and the elements of dense arrays. For accesses 1.1039 + * on such properties, the correspondence is as follows: 1.1040 + * 1.1041 + * 1. If the type has unknownProperties(), the possible properties and 1.1042 + * value types for associated JSObjects are unknown. 1.1043 + * 1.1044 + * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id 1.1045 + * which is a property in obj, before obj->getProperty(id) the property 1.1046 + * in type for id must reflect the result of the getProperty. 1.1047 + * 1.1048 + * There is an exception for properties of global JS objects which 1.1049 + * are undefined at the point where the property was (lazily) generated. 1.1050 + * In such cases the property type set will remain empty, and the 1.1051 + * 'undefined' type will only be added after a subsequent assignment or 1.1052 + * deletion. After these properties have been assigned a defined value, 1.1053 + * the only way they can become undefined again is after such an assign 1.1054 + * or deletion. 1.1055 + * 1.1056 + * There is another exception for array lengths, which are special cased 1.1057 + * by the compiler and VM and are not reflected in property types. 1.1058 + * 1.1059 + * We establish these by using write barriers on calls to setProperty and 1.1060 + * defineProperty which are on native properties, and on any jitcode which 1.1061 + * might update the property with a new type. 1.1062 + */ 1.1063 + Property **propertySet; 1.1064 + public: 1.1065 + 1.1066 + /* If this is an interpreted function, the function object. */ 1.1067 + HeapPtrFunction interpretedFunction; 1.1068 + 1.1069 +#if JS_BITS_PER_WORD == 32 1.1070 + uint32_t padding; 1.1071 +#endif 1.1072 + 1.1073 + inline TypeObject(const Class *clasp, TaggedProto proto, TypeObjectFlags initialFlags); 1.1074 + 1.1075 + bool hasAnyFlags(TypeObjectFlags flags) { 1.1076 + JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); 1.1077 + return !!(this->flags() & flags); 1.1078 + } 1.1079 + bool hasAllFlags(TypeObjectFlags flags) { 1.1080 + JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); 1.1081 + return (this->flags() & flags) == flags; 1.1082 + } 1.1083 + 1.1084 + bool unknownProperties() { 1.1085 + JS_ASSERT_IF(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES, 1.1086 + hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK)); 1.1087 + return !!(flags() & OBJECT_FLAG_UNKNOWN_PROPERTIES); 1.1088 + } 1.1089 + 1.1090 + bool shouldPreTenure() { 1.1091 + return hasAnyFlags(OBJECT_FLAG_PRE_TENURE) && !unknownProperties(); 1.1092 + } 1.1093 + 1.1094 + bool hasTenuredProto() const { 1.1095 + return !(flags() & OBJECT_FLAG_NURSERY_PROTO); 1.1096 + } 1.1097 + 1.1098 + gc::InitialHeap initialHeap(CompilerConstraintList *constraints); 1.1099 + 1.1100 + bool canPreTenure() { 1.1101 + // Only types associated with particular allocation sites or 'new' 1.1102 + // scripts can be marked as needing pretenuring. Other types can be 1.1103 + // used for different purposes across the compartment and can't use 1.1104 + // this bit reliably. 1.1105 + if (unknownProperties()) 1.1106 + return false; 1.1107 + return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript(); 1.1108 + } 1.1109 + 1.1110 + void setShouldPreTenure(ExclusiveContext *cx) { 1.1111 + JS_ASSERT(canPreTenure()); 1.1112 + setFlags(cx, OBJECT_FLAG_PRE_TENURE); 1.1113 + } 1.1114 + 1.1115 + /* 1.1116 + * Get or create a property of this object. Only call this for properties which 1.1117 + * a script accesses explicitly. 1.1118 + */ 1.1119 + inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id); 1.1120 + 1.1121 + /* Get a property only if it already exists. */ 1.1122 + inline HeapTypeSet *maybeGetProperty(jsid id); 1.1123 + 1.1124 + inline unsigned getPropertyCount(); 1.1125 + inline Property *getProperty(unsigned i); 1.1126 + 1.1127 + /* Helpers */ 1.1128 + 1.1129 + void updateNewPropertyTypes(ExclusiveContext *cx, jsid id, HeapTypeSet *types); 1.1130 + bool addDefiniteProperties(ExclusiveContext *cx, JSObject *obj); 1.1131 + bool matchDefiniteProperties(HandleObject obj); 1.1132 + void addPrototype(JSContext *cx, TypeObject *proto); 1.1133 + void addPropertyType(ExclusiveContext *cx, jsid id, Type type); 1.1134 + void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value); 1.1135 + void markPropertyNonData(ExclusiveContext *cx, jsid id); 1.1136 + void markPropertyNonWritable(ExclusiveContext *cx, jsid id); 1.1137 + void markStateChange(ExclusiveContext *cx); 1.1138 + void setFlags(ExclusiveContext *cx, TypeObjectFlags flags); 1.1139 + void markUnknown(ExclusiveContext *cx); 1.1140 + void clearAddendum(ExclusiveContext *cx); 1.1141 + void clearNewScriptAddendum(ExclusiveContext *cx); 1.1142 + void clearTypedObjectAddendum(ExclusiveContext *cx); 1.1143 + void maybeClearNewScriptAddendumOnOOM(); 1.1144 + bool isPropertyNonData(jsid id); 1.1145 + bool isPropertyNonWritable(jsid id); 1.1146 + 1.1147 + void print(); 1.1148 + 1.1149 + inline void clearProperties(); 1.1150 + inline void sweep(FreeOp *fop, bool *oom); 1.1151 + 1.1152 + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 1.1153 + 1.1154 + /* 1.1155 + * Type objects don't have explicit finalizers. Memory owned by a type 1.1156 + * object pending deletion is released when weak references are sweeped 1.1157 + * from all the compartment's type objects. 1.1158 + */ 1.1159 + void finalize(FreeOp *fop) {} 1.1160 + 1.1161 + static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; } 1.1162 + 1.1163 + static inline uint32_t offsetOfClasp() { 1.1164 + return offsetof(TypeObject, clasp_); 1.1165 + } 1.1166 + 1.1167 + static inline uint32_t offsetOfProto() { 1.1168 + return offsetof(TypeObject, proto_); 1.1169 + } 1.1170 + 1.1171 + private: 1.1172 + inline uint32_t basePropertyCount() const; 1.1173 + inline void setBasePropertyCount(uint32_t count); 1.1174 + 1.1175 + static void staticAsserts() { 1.1176 + JS_STATIC_ASSERT(offsetof(TypeObject, proto_) == offsetof(js::shadow::TypeObject, proto)); 1.1177 + } 1.1178 +}; 1.1179 + 1.1180 +/* 1.1181 + * Entries for the per-compartment set of type objects which are 'new' types to 1.1182 + * use for some prototype and constructed with an optional script. This also 1.1183 + * includes entries for the set of lazy type objects in the compartment, which 1.1184 + * use a null script (though there are only a few of these per compartment). 1.1185 + */ 1.1186 +struct TypeObjectWithNewScriptEntry 1.1187 +{ 1.1188 + ReadBarriered<TypeObject> object; 1.1189 + 1.1190 + // Note: This pointer is only used for equality and does not need a read barrier. 1.1191 + JSFunction *newFunction; 1.1192 + 1.1193 + TypeObjectWithNewScriptEntry(TypeObject *object, JSFunction *newFunction) 1.1194 + : object(object), newFunction(newFunction) 1.1195 + {} 1.1196 + 1.1197 + struct Lookup { 1.1198 + const Class *clasp; 1.1199 + TaggedProto hashProto; 1.1200 + TaggedProto matchProto; 1.1201 + JSFunction *newFunction; 1.1202 + 1.1203 + Lookup(const Class *clasp, TaggedProto proto, JSFunction *newFunction) 1.1204 + : clasp(clasp), hashProto(proto), matchProto(proto), newFunction(newFunction) 1.1205 + {} 1.1206 + 1.1207 +#ifdef JSGC_GENERATIONAL 1.1208 + /* 1.1209 + * For use by generational post barriers only. Look up an entry whose 1.1210 + * proto has been moved, but was hashed with the original value. 1.1211 + */ 1.1212 + Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSFunction *newFunction) 1.1213 + : clasp(clasp), hashProto(hashProto), matchProto(matchProto), newFunction(newFunction) 1.1214 + {} 1.1215 +#endif 1.1216 + 1.1217 + }; 1.1218 + 1.1219 + static inline HashNumber hash(const Lookup &lookup); 1.1220 + static inline bool match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup); 1.1221 + static void rekey(TypeObjectWithNewScriptEntry &k, const TypeObjectWithNewScriptEntry& newKey) { k = newKey; } 1.1222 +}; 1.1223 +typedef HashSet<TypeObjectWithNewScriptEntry, 1.1224 + TypeObjectWithNewScriptEntry, 1.1225 + SystemAllocPolicy> TypeObjectWithNewScriptSet; 1.1226 + 1.1227 +/* Whether to use a new type object when calling 'new' at script/pc. */ 1.1228 +bool 1.1229 +UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc); 1.1230 + 1.1231 +bool 1.1232 +UseNewTypeForClone(JSFunction *fun); 1.1233 + 1.1234 +/* 1.1235 + * Whether Array.prototype, or an object on its proto chain, has an 1.1236 + * indexed property. 1.1237 + */ 1.1238 +bool 1.1239 +ArrayPrototypeHasIndexedProperty(CompilerConstraintList *constraints, JSScript *script); 1.1240 + 1.1241 +/* Whether obj or any of its prototypes have an indexed property. */ 1.1242 +bool 1.1243 +TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints, TemporaryTypeSet *types); 1.1244 + 1.1245 +/* Persistent type information for a script, retained across GCs. */ 1.1246 +class TypeScript 1.1247 +{ 1.1248 + friend class ::JSScript; 1.1249 + 1.1250 + // Variable-size array 1.1251 + StackTypeSet typeArray_[1]; 1.1252 + 1.1253 + public: 1.1254 + /* Array of type type sets for variables and JOF_TYPESET ops. */ 1.1255 + StackTypeSet *typeArray() const { 1.1256 + // Ensure typeArray_ is the last data member of TypeScript. 1.1257 + JS_STATIC_ASSERT(sizeof(TypeScript) == 1.1258 + sizeof(typeArray_) + offsetof(TypeScript, typeArray_)); 1.1259 + return const_cast<StackTypeSet *>(typeArray_); 1.1260 + } 1.1261 + 1.1262 + static inline size_t SizeIncludingTypeArray(size_t arraySize) { 1.1263 + // Ensure typeArray_ is the last data member of TypeScript. 1.1264 + JS_STATIC_ASSERT(sizeof(TypeScript) == 1.1265 + sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_)); 1.1266 + return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet); 1.1267 + } 1.1268 + 1.1269 + static inline unsigned NumTypeSets(JSScript *script); 1.1270 + 1.1271 + static inline StackTypeSet *ThisTypes(JSScript *script); 1.1272 + static inline StackTypeSet *ArgTypes(JSScript *script, unsigned i); 1.1273 + 1.1274 + /* Get the type set for values observed at an opcode. */ 1.1275 + static inline StackTypeSet *BytecodeTypes(JSScript *script, jsbytecode *pc); 1.1276 + 1.1277 + template <typename TYPESET> 1.1278 + static inline TYPESET *BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *bytecodeMap, 1.1279 + uint32_t *hint, TYPESET *typeArray); 1.1280 + 1.1281 + /* Get a type object for an allocation site in this script. */ 1.1282 + static inline TypeObject *InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, 1.1283 + JSProtoKey kind); 1.1284 + 1.1285 + /* 1.1286 + * Monitor a bytecode pushing any value. This must be called for any opcode 1.1287 + * which is JOF_TYPESET, and where either the script has not been analyzed 1.1288 + * by type inference or where the pc has type barriers. For simplicity, we 1.1289 + * always monitor JOF_TYPESET opcodes in the interpreter and stub calls, 1.1290 + * and only look at barriers when generating JIT code for the script. 1.1291 + */ 1.1292 + static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, 1.1293 + const js::Value &val); 1.1294 + static inline void Monitor(JSContext *cx, const js::Value &rval); 1.1295 + 1.1296 + /* Monitor an assignment at a SETELEM on a non-integer identifier. */ 1.1297 + static inline void MonitorAssign(JSContext *cx, HandleObject obj, jsid id); 1.1298 + 1.1299 + /* Add a type for a variable in a script. */ 1.1300 + static inline void SetThis(JSContext *cx, JSScript *script, Type type); 1.1301 + static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value); 1.1302 + static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type); 1.1303 + static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, 1.1304 + const js::Value &value); 1.1305 + 1.1306 + /* 1.1307 + * Freeze all the stack type sets in a script, for a compilation. Returns 1.1308 + * copies of the type sets which will be checked against the actual ones 1.1309 + * under FinishCompilation, to detect any type changes. 1.1310 + */ 1.1311 + static bool FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script, 1.1312 + TemporaryTypeSet **pThisTypes, 1.1313 + TemporaryTypeSet **pArgTypes, 1.1314 + TemporaryTypeSet **pBytecodeTypes); 1.1315 + 1.1316 + static void Purge(JSContext *cx, HandleScript script); 1.1317 + 1.1318 + static void Sweep(FreeOp *fop, JSScript *script, bool *oom); 1.1319 + void destroy(); 1.1320 + 1.1321 + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { 1.1322 + return mallocSizeOf(this); 1.1323 + } 1.1324 + 1.1325 +#ifdef DEBUG 1.1326 + void printTypes(JSContext *cx, HandleScript script) const; 1.1327 +#endif 1.1328 +}; 1.1329 + 1.1330 +void 1.1331 +FillBytecodeTypeMap(JSScript *script, uint32_t *bytecodeMap); 1.1332 + 1.1333 +class RecompileInfo; 1.1334 + 1.1335 +// Allocate a CompilerOutput for a finished compilation and generate the type 1.1336 +// constraints for the compilation. Returns whether the type constraints 1.1337 +// still hold. 1.1338 +bool 1.1339 +FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode executionMode, 1.1340 + CompilerConstraintList *constraints, RecompileInfo *precompileInfo); 1.1341 + 1.1342 +// Update the actual types in any scripts queried by constraints with any 1.1343 +// speculative types added during the definite properties analysis. 1.1344 +void 1.1345 +FinishDefinitePropertiesAnalysis(JSContext *cx, CompilerConstraintList *constraints); 1.1346 + 1.1347 +struct ArrayTableKey; 1.1348 +typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable; 1.1349 + 1.1350 +struct ObjectTableKey; 1.1351 +struct ObjectTableEntry; 1.1352 +typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable; 1.1353 + 1.1354 +struct AllocationSiteKey; 1.1355 +typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable; 1.1356 + 1.1357 +class HeapTypeSetKey; 1.1358 + 1.1359 +// Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. 1.1360 +struct TypeObjectKey 1.1361 +{ 1.1362 + static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; } 1.1363 + static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; } 1.1364 + 1.1365 + static TypeObjectKey *get(JSObject *obj) { 1.1366 + JS_ASSERT(obj); 1.1367 + return (TypeObjectKey *) (uintptr_t(obj) | 1); 1.1368 + } 1.1369 + static TypeObjectKey *get(TypeObject *obj) { 1.1370 + JS_ASSERT(obj); 1.1371 + return (TypeObjectKey *) obj; 1.1372 + } 1.1373 + 1.1374 + bool isTypeObject() { 1.1375 + return (uintptr_t(this) & 1) == 0; 1.1376 + } 1.1377 + bool isSingleObject() { 1.1378 + return (uintptr_t(this) & 1) != 0; 1.1379 + } 1.1380 + 1.1381 + TypeObject *asTypeObject() { 1.1382 + JS_ASSERT(isTypeObject()); 1.1383 + return (TypeObject *) this; 1.1384 + } 1.1385 + JSObject *asSingleObject() { 1.1386 + JS_ASSERT(isSingleObject()); 1.1387 + return (JSObject *) (uintptr_t(this) & ~1); 1.1388 + } 1.1389 + 1.1390 + const Class *clasp(); 1.1391 + TaggedProto proto(); 1.1392 + bool hasTenuredProto(); 1.1393 + JSObject *singleton(); 1.1394 + TypeNewScript *newScript(); 1.1395 + 1.1396 + bool unknownProperties(); 1.1397 + bool hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags); 1.1398 + void watchStateChangeForInlinedCall(CompilerConstraintList *constraints); 1.1399 + void watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints); 1.1400 + void watchStateChangeForTypedArrayData(CompilerConstraintList *constraints); 1.1401 + HeapTypeSetKey property(jsid id); 1.1402 + void ensureTrackedProperty(JSContext *cx, jsid id); 1.1403 + 1.1404 + TypeObject *maybeType(); 1.1405 +}; 1.1406 + 1.1407 +// Representation of a heap type property which may or may not be instantiated. 1.1408 +// Heap properties for singleton types are instantiated lazily as they are used 1.1409 +// by the compiler, but this is only done on the main thread. If we are 1.1410 +// compiling off thread and use a property which has not yet been instantiated, 1.1411 +// it will be treated as empty and non-configured and will be instantiated when 1.1412 +// rejoining to the main thread. If it is in fact not empty, the compilation 1.1413 +// will fail; to avoid this, we try to instantiate singleton property types 1.1414 +// during generation of baseline caches. 1.1415 +class HeapTypeSetKey 1.1416 +{ 1.1417 + friend class TypeObjectKey; 1.1418 + 1.1419 + // Object and property being accessed. 1.1420 + TypeObjectKey *object_; 1.1421 + jsid id_; 1.1422 + 1.1423 + // If instantiated, the underlying heap type set. 1.1424 + HeapTypeSet *maybeTypes_; 1.1425 + 1.1426 + public: 1.1427 + HeapTypeSetKey() 1.1428 + : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr) 1.1429 + {} 1.1430 + 1.1431 + TypeObjectKey *object() const { return object_; } 1.1432 + jsid id() const { return id_; } 1.1433 + HeapTypeSet *maybeTypes() const { return maybeTypes_; } 1.1434 + 1.1435 + bool instantiate(JSContext *cx); 1.1436 + 1.1437 + void freeze(CompilerConstraintList *constraints); 1.1438 + jit::MIRType knownMIRType(CompilerConstraintList *constraints); 1.1439 + bool nonData(CompilerConstraintList *constraints); 1.1440 + bool nonWritable(CompilerConstraintList *constraints); 1.1441 + bool isOwnProperty(CompilerConstraintList *constraints); 1.1442 + bool knownSubset(CompilerConstraintList *constraints, const HeapTypeSetKey &other); 1.1443 + JSObject *singleton(CompilerConstraintList *constraints); 1.1444 + bool needsBarrier(CompilerConstraintList *constraints); 1.1445 +}; 1.1446 + 1.1447 +/* 1.1448 + * Information about the result of the compilation of a script. This structure 1.1449 + * stored in the TypeCompartment is indexed by the RecompileInfo. This 1.1450 + * indirection enables the invalidation of all constraints related to the same 1.1451 + * compilation. 1.1452 + */ 1.1453 +class CompilerOutput 1.1454 +{ 1.1455 + // If this compilation has not been invalidated, the associated script and 1.1456 + // kind of compilation being performed. 1.1457 + JSScript *script_; 1.1458 + ExecutionMode mode_ : 2; 1.1459 + 1.1460 + // Whether this compilation is about to be invalidated. 1.1461 + bool pendingInvalidation_ : 1; 1.1462 + 1.1463 + // During sweeping, the list of compiler outputs is compacted and invalidated 1.1464 + // outputs are removed. This gives the new index for a valid compiler output. 1.1465 + uint32_t sweepIndex_ : 29; 1.1466 + 1.1467 + public: 1.1468 + static const uint32_t INVALID_SWEEP_INDEX = (1 << 29) - 1; 1.1469 + 1.1470 + CompilerOutput() 1.1471 + : script_(nullptr), mode_(SequentialExecution), 1.1472 + pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX) 1.1473 + {} 1.1474 + 1.1475 + CompilerOutput(JSScript *script, ExecutionMode mode) 1.1476 + : script_(script), mode_(mode), 1.1477 + pendingInvalidation_(false), sweepIndex_(INVALID_SWEEP_INDEX) 1.1478 + {} 1.1479 + 1.1480 + JSScript *script() const { return script_; } 1.1481 + inline ExecutionMode mode() const { return mode_; } 1.1482 + 1.1483 + inline jit::IonScript *ion() const; 1.1484 + 1.1485 + bool isValid() const { 1.1486 + return script_ != nullptr; 1.1487 + } 1.1488 + void invalidate() { 1.1489 + script_ = nullptr; 1.1490 + } 1.1491 + 1.1492 + void setPendingInvalidation() { 1.1493 + pendingInvalidation_ = true; 1.1494 + } 1.1495 + bool pendingInvalidation() { 1.1496 + return pendingInvalidation_; 1.1497 + } 1.1498 + 1.1499 + void setSweepIndex(uint32_t index) { 1.1500 + if (index >= INVALID_SWEEP_INDEX) 1.1501 + MOZ_CRASH(); 1.1502 + sweepIndex_ = index; 1.1503 + } 1.1504 + void invalidateSweepIndex() { 1.1505 + sweepIndex_ = INVALID_SWEEP_INDEX; 1.1506 + } 1.1507 + uint32_t sweepIndex() { 1.1508 + JS_ASSERT(sweepIndex_ != INVALID_SWEEP_INDEX); 1.1509 + return sweepIndex_; 1.1510 + } 1.1511 +}; 1.1512 + 1.1513 +class RecompileInfo 1.1514 +{ 1.1515 + uint32_t outputIndex; 1.1516 + 1.1517 + public: 1.1518 + RecompileInfo(uint32_t outputIndex = uint32_t(-1)) 1.1519 + : outputIndex(outputIndex) 1.1520 + {} 1.1521 + 1.1522 + bool operator == (const RecompileInfo &o) const { 1.1523 + return outputIndex == o.outputIndex; 1.1524 + } 1.1525 + CompilerOutput *compilerOutput(TypeZone &types) const; 1.1526 + CompilerOutput *compilerOutput(JSContext *cx) const; 1.1527 + bool shouldSweep(TypeZone &types); 1.1528 +}; 1.1529 + 1.1530 +/* Type information for a compartment. */ 1.1531 +struct TypeCompartment 1.1532 +{ 1.1533 + /* Constraint solving worklist structures. */ 1.1534 + 1.1535 + /* Number of scripts in this compartment. */ 1.1536 + unsigned scriptCount; 1.1537 + 1.1538 + /* Table for referencing types of objects keyed to an allocation site. */ 1.1539 + AllocationSiteTable *allocationSiteTable; 1.1540 + 1.1541 + /* Tables for determining types of singleton/JSON objects. */ 1.1542 + 1.1543 + ArrayTypeTable *arrayTypeTable; 1.1544 + ObjectTypeTable *objectTypeTable; 1.1545 + 1.1546 + private: 1.1547 + void setTypeToHomogenousArray(ExclusiveContext *cx, JSObject *obj, Type type); 1.1548 + 1.1549 + public: 1.1550 + void fixArrayType(ExclusiveContext *cx, JSObject *obj); 1.1551 + void fixObjectType(ExclusiveContext *cx, JSObject *obj); 1.1552 + void fixRestArgumentsType(ExclusiveContext *cx, JSObject *obj); 1.1553 + 1.1554 + JSObject *newTypedObject(JSContext *cx, IdValuePair *properties, size_t nproperties); 1.1555 + 1.1556 + TypeCompartment(); 1.1557 + ~TypeCompartment(); 1.1558 + 1.1559 + inline JSCompartment *compartment(); 1.1560 + 1.1561 + /* Prints results of this compartment if spew is enabled or force is set. */ 1.1562 + void print(JSContext *cx, bool force); 1.1563 + 1.1564 + /* 1.1565 + * Make a function or non-function object associated with an optional 1.1566 + * script. The 'key' parameter here may be an array, typed array, function 1.1567 + * or JSProto_Object to indicate a type whose class is unknown (not just 1.1568 + * js_ObjectClass). 1.1569 + */ 1.1570 + TypeObject *newTypeObject(ExclusiveContext *cx, const Class *clasp, Handle<TaggedProto> proto, 1.1571 + TypeObjectFlags initialFlags = 0); 1.1572 + 1.1573 + /* Get or make an object for an allocation site, and add to the allocation site table. */ 1.1574 + TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key); 1.1575 + 1.1576 + /* Mark any type set containing obj as having a generic object type. */ 1.1577 + void markSetsUnknown(JSContext *cx, TypeObject *obj); 1.1578 + 1.1579 + void clearTables(); 1.1580 + void sweep(FreeOp *fop); 1.1581 + void finalizeObjects(); 1.1582 + 1.1583 + void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, 1.1584 + size_t *allocationSiteTables, 1.1585 + size_t *arrayTypeTables, 1.1586 + size_t *objectTypeTables); 1.1587 +}; 1.1588 + 1.1589 +void FixRestArgumentsType(ExclusiveContext *cxArg, JSObject *obj); 1.1590 + 1.1591 +struct TypeZone 1.1592 +{ 1.1593 + JS::Zone *zone_; 1.1594 + 1.1595 + /* Pool for type information in this zone. */ 1.1596 + static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024; 1.1597 + js::LifoAlloc typeLifoAlloc; 1.1598 + 1.1599 + /* 1.1600 + * All Ion compilations that have occured in this zone, for indexing via 1.1601 + * RecompileInfo. This includes both valid and invalid compilations, though 1.1602 + * invalidated compilations are swept on GC. 1.1603 + */ 1.1604 + Vector<CompilerOutput> *compilerOutputs; 1.1605 + 1.1606 + /* Pending recompilations to perform before execution of JIT code can resume. */ 1.1607 + Vector<RecompileInfo> *pendingRecompiles; 1.1608 + 1.1609 + TypeZone(JS::Zone *zone); 1.1610 + ~TypeZone(); 1.1611 + 1.1612 + JS::Zone *zone() const { return zone_; } 1.1613 + 1.1614 + void sweep(FreeOp *fop, bool releaseTypes, bool *oom); 1.1615 + void clearAllNewScriptAddendumsOnOOM(); 1.1616 + 1.1617 + /* Mark a script as needing recompilation once inference has finished. */ 1.1618 + void addPendingRecompile(JSContext *cx, const RecompileInfo &info); 1.1619 + void addPendingRecompile(JSContext *cx, JSScript *script); 1.1620 + 1.1621 + void processPendingRecompiles(FreeOp *fop); 1.1622 +}; 1.1623 + 1.1624 +enum SpewChannel { 1.1625 + ISpewOps, /* ops: New constraints and types. */ 1.1626 + ISpewResult, /* result: Final type sets. */ 1.1627 + SPEW_COUNT 1.1628 +}; 1.1629 + 1.1630 +#ifdef DEBUG 1.1631 + 1.1632 +const char * InferSpewColorReset(); 1.1633 +const char * InferSpewColor(TypeConstraint *constraint); 1.1634 +const char * InferSpewColor(TypeSet *types); 1.1635 + 1.1636 +void InferSpew(SpewChannel which, const char *fmt, ...); 1.1637 +const char * TypeString(Type type); 1.1638 +const char * TypeObjectString(TypeObject *type); 1.1639 + 1.1640 +/* Check that the type property for id in obj contains value. */ 1.1641 +bool TypeHasProperty(JSContext *cx, TypeObject *obj, jsid id, const Value &value); 1.1642 + 1.1643 +#else 1.1644 + 1.1645 +inline const char * InferSpewColorReset() { return nullptr; } 1.1646 +inline const char * InferSpewColor(TypeConstraint *constraint) { return nullptr; } 1.1647 +inline const char * InferSpewColor(TypeSet *types) { return nullptr; } 1.1648 +inline void InferSpew(SpewChannel which, const char *fmt, ...) {} 1.1649 +inline const char * TypeString(Type type) { return nullptr; } 1.1650 +inline const char * TypeObjectString(TypeObject *type) { return nullptr; } 1.1651 + 1.1652 +#endif 1.1653 + 1.1654 +/* Print a warning, dump state and abort the program. */ 1.1655 +MOZ_NORETURN void TypeFailure(JSContext *cx, const char *fmt, ...); 1.1656 + 1.1657 +} /* namespace types */ 1.1658 +} /* namespace js */ 1.1659 + 1.1660 +#endif /* jsinfer_h */