/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. *//* Definitions related to javascript type inference. */#ifndef jsinfer_h#define jsinfer_h#include"mozilla/MemoryReporting.h"#include"mozilla/TypedEnum.h"#include"jsalloc.h"#include"jsfriendapi.h"#include"jstypes.h"#include"ds/IdValuePair.h"#include"ds/LifoAlloc.h"#include"gc/Barrier.h"#include"gc/Marking.h"#include"js/Utility.h"#include"js/Vector.h"namespacejs{classTypeDescr;classTaggedProto{public:staticJSObject*constLazyProto;TaggedProto():proto(nullptr){}TaggedProto(JSObject*proto):proto(proto){}uintptr_ttoWord()const{returnuintptr_t(proto);}boolisLazy()const{returnproto==LazyProto;}boolisObject()const{/* Skip nullptr and LazyProto. */returnuintptr_t(proto)>uintptr_t(TaggedProto::LazyProto);}JSObject*toObject()const{JS_ASSERT(isObject());returnproto;}JSObject*toObjectOrNull()const{JS_ASSERT(!proto||isObject());returnproto;}JSObject*raw()const{returnproto;}booloperator==(constTaggedProto&other){returnproto==other.proto;}booloperator!=(constTaggedProto&other){returnproto!=other.proto;}private:JSObject*proto;};template<>structRootKind<TaggedProto>{staticThingRootKindrootKind(){returnTHING_ROOT_OBJECT;}};template<>structGCMethods<constTaggedProto>{staticTaggedProtoinitial(){returnTaggedProto();}staticThingRootKindkind(){returnTHING_ROOT_OBJECT;}staticboolpoisoned(constTaggedProto&v){returnIsPoisonedPtr(v.raw());}};template<>structGCMethods<TaggedProto>{staticTaggedProtoinitial(){returnTaggedProto();}staticThingRootKindkind(){returnTHING_ROOT_OBJECT;}staticboolpoisoned(constTaggedProto&v){returnIsPoisonedPtr(v.raw());}};template<classOuter>classTaggedProtoOperations{constTaggedProto*value()const{returnstatic_cast<constOuter*>(this)->extract();}public:uintptr_ttoWord()const{returnvalue()->toWord();}inlineboolisLazy()const{returnvalue()->isLazy();}inlineboolisObject()const{returnvalue()->isObject();}inlineJSObject*toObject()const{returnvalue()->toObject();}inlineJSObject*toObjectOrNull()const{returnvalue()->toObjectOrNull();}JSObject*raw()const{returnvalue()->raw();}};template<>classHandleBase<TaggedProto>:publicTaggedProtoOperations<Handle<TaggedProto>>{friendclassTaggedProtoOperations<Handle<TaggedProto>>;constTaggedProto*extract()const{returnstatic_cast<constHandle<TaggedProto>*>(this)->address();}};template<>classRootedBase<TaggedProto>:publicTaggedProtoOperations<Rooted<TaggedProto>>{friendclassTaggedProtoOperations<Rooted<TaggedProto>>;constTaggedProto*extract()const{returnstatic_cast<constRooted<TaggedProto>*>(this)->address();}};classCallObject;/* * Execution Mode Overview * * JavaScript code can execute either sequentially or in parallel, such as in * PJS. Functions which behave identically in either execution mode can take a * ThreadSafeContext, and functions which have similar but not identical * behavior between execution modes can be templated on the mode. Such * functions use a context parameter type from ExecutionModeTraits below * indicating whether they are only permitted constrained operations (such as * thread safety, and side effects limited to being thread-local), or whether * they can have arbitrary side effects. */enumExecutionMode{/* Normal JavaScript execution. */SequentialExecution,/* * JavaScript code to be executed in parallel worker threads in PJS in a * fork join fashion. */ParallelExecution,/* * Modes after this point are internal and are not counted in * NumExecutionModes below. *//* * MIR analysis performed when invoking 'new' on a script, to determine * definite properties. Used by the optimizing JIT. */DefinitePropertiesAnalysis};/* * Not as part of the enum so we don't get warnings about unhandled enum * values. */staticconstunsignedNumExecutionModes=ParallelExecution+1;template<ExecutionModemode>structExecutionModeTraits{};template<>structExecutionModeTraits<SequentialExecution>{typedefJSContext*ContextType;typedefExclusiveContext*ExclusiveContextType;staticinlineJSContext*toContextType(ExclusiveContext*cx);};template<>structExecutionModeTraits<ParallelExecution>{typedefForkJoinContext*ContextType;typedefForkJoinContext*ExclusiveContextType;staticinlineForkJoinContext*toContextType(ForkJoinContext*cx){returncx;}};namespacejit{structIonScript;classIonAllocPolicy;classTempAllocator;}namespaceanalyze{classScriptAnalysis;}namespacetypes{classTypeZone;classTypeSet;classTypeObjectKey;/* * Information about a single concrete type. We pack this into a single word, * where small values are particular primitive or other singleton types, and * larger values are either specific JS objects or type objects. */classType{uintptr_tdata;Type(uintptr_tdata):data(data){}public:uintptr_traw()const{returndata;}boolisPrimitive()const{returndata<JSVAL_TYPE_OBJECT;}boolisPrimitive(JSValueTypetype)const{JS_ASSERT(type<JSVAL_TYPE_OBJECT);return(uintptr_t)type==data;}JSValueTypeprimitive()const{JS_ASSERT(isPrimitive());return(JSValueType)data;}boolisSomeObject()const{returndata==JSVAL_TYPE_OBJECT||data>JSVAL_TYPE_UNKNOWN;}boolisAnyObject()const{returndata==JSVAL_TYPE_OBJECT;}boolisUnknown()const{returndata==JSVAL_TYPE_UNKNOWN;}/* Accessors for types that are either JSObject or TypeObject. */boolisObject()const{JS_ASSERT(!isAnyObject()&&!isUnknown());returndata>JSVAL_TYPE_UNKNOWN;}boolisObjectUnchecked()const{returndata>JSVAL_TYPE_UNKNOWN;}inlineTypeObjectKey*objectKey()const;/* Accessors for JSObject types */boolisSingleObject()const{returnisObject()&&!!(data&1);}inlineJSObject*singleObject()const;/* Accessors for TypeObject types */boolisTypeObject()const{returnisObject()&&!(data&1);}inlineTypeObject*typeObject()const;booloperator==(Typeo)const{returndata==o.data;}booloperator!=(Typeo)const{returndata!=o.data;}staticinlineTypeUndefinedType(){returnType(JSVAL_TYPE_UNDEFINED);}staticinlineTypeNullType(){returnType(JSVAL_TYPE_NULL);}staticinlineTypeBooleanType(){returnType(JSVAL_TYPE_BOOLEAN);}staticinlineTypeInt32Type(){returnType(JSVAL_TYPE_INT32);}staticinlineTypeDoubleType(){returnType(JSVAL_TYPE_DOUBLE);}staticinlineTypeStringType(){returnType(JSVAL_TYPE_STRING);}staticinlineTypeMagicArgType(){returnType(JSVAL_TYPE_MAGIC);}staticinlineTypeAnyObjectType(){returnType(JSVAL_TYPE_OBJECT);}staticinlineTypeUnknownType(){returnType(JSVAL_TYPE_UNKNOWN);}staticinlineTypePrimitiveType(JSValueTypetype){JS_ASSERT(type<JSVAL_TYPE_UNKNOWN);returnType(type);}staticinlineTypeObjectType(JSObject*obj);staticinlineTypeObjectType(TypeObject*obj);staticinlineTypeObjectType(TypeObjectKey*obj);};/* Get the type of a jsval, or zero for an unknown special value. */inlineTypeGetValueType(constValue&val);/* * Type inference memory management overview. * * Type information about the values observed within scripts and about the * contents of the heap is accumulated as the program executes. Compilation * accumulates constraints relating type information on the heap with the * compilations that should be invalidated when those types change. Type * information and constraints are allocated in the zone's typeLifoAlloc, * and on GC all data referring to live things is copied into a new allocator. * Thus, type set and constraints only hold weak references. *//* * A constraint which listens to additions to a type set and propagates those * changes to other type sets. */classTypeConstraint{public:/* Next constraint listening to the same type set. */TypeConstraint*next;TypeConstraint():next(nullptr){}/* Debugging name for this kind of constraint. */virtualconstchar*kind()=0;/* Register a new type for the set this constraint is listening to. */virtualvoidnewType(JSContext*cx,TypeSet*source,Typetype)=0;/* * For constraints attached to an object property's type set, mark the * property as having its configuration changed. */virtualvoidnewPropertyState(JSContext*cx,TypeSet*source){}/* * For constraints attached to the JSID_EMPTY type set on an object, * indicate a change in one of the object's dynamic property flags or other * state. */virtualvoidnewObjectState(JSContext*cx,TypeObject*object){}/* * If the data this constraint refers to is still live, copy it into the * zone's new allocator. Type constraints only hold weak references. */virtualboolsweep(TypeZone&zone,TypeConstraint**res)=0;};/* Flags and other state stored in TypeSet::flags */enumMOZ_ENUM_TYPE(uint32_t){TYPE_FLAG_UNDEFINED=0x1,TYPE_FLAG_NULL=0x2,TYPE_FLAG_BOOLEAN=0x4,TYPE_FLAG_INT32=0x8,TYPE_FLAG_DOUBLE=0x10,TYPE_FLAG_STRING=0x20,TYPE_FLAG_LAZYARGS=0x40,TYPE_FLAG_ANYOBJECT=0x80,/* Mask containing all primitives */TYPE_FLAG_PRIMITIVE=TYPE_FLAG_UNDEFINED|TYPE_FLAG_NULL|TYPE_FLAG_BOOLEAN|TYPE_FLAG_INT32|TYPE_FLAG_DOUBLE|TYPE_FLAG_STRING,/* Mask/shift for the number of objects in objectSet */TYPE_FLAG_OBJECT_COUNT_MASK=0x1f00,TYPE_FLAG_OBJECT_COUNT_SHIFT=8,TYPE_FLAG_OBJECT_COUNT_LIMIT=TYPE_FLAG_OBJECT_COUNT_MASK>>TYPE_FLAG_OBJECT_COUNT_SHIFT,/* Whether the contents of this type set are totally unknown. */TYPE_FLAG_UNKNOWN=0x00002000,/* Mask of normal type flags on a type set. */TYPE_FLAG_BASE_MASK=0x000020ff,/* Additional flags for HeapTypeSet sets. *//* * Whether the property has ever been deleted or reconfigured to behave * differently from a plain data property, other than making the property * non-writable. */TYPE_FLAG_NON_DATA_PROPERTY=0x00004000,/* Whether the property has ever been made non-writable. */TYPE_FLAG_NON_WRITABLE_PROPERTY=0x00008000,/* * Whether the property is definitely in a particular slot on all objects * from which it has not been deleted or reconfigured. For singletons * this may be a fixed or dynamic slot, and for other objects this will be * a fixed slot. * * If the property is definite, mask and shift storing the slot + 1. * Otherwise these bits are clear. */TYPE_FLAG_DEFINITE_MASK=0xffff0000,TYPE_FLAG_DEFINITE_SHIFT=16};typedefuint32_tTypeFlags;/* Flags and other state stored in TypeObject::flags */enumMOZ_ENUM_TYPE(uint32_t){/* Whether this type object is associated with some allocation site. */OBJECT_FLAG_FROM_ALLOCATION_SITE=0x1,/* If set, addendum information should not be installed on this object. */OBJECT_FLAG_ADDENDUM_CLEARED=0x2,/* * If set, the object's prototype might be in the nursery and can't be * used during Ion compilation (which may be occurring off thread). */OBJECT_FLAG_NURSERY_PROTO=0x4,/* * Whether we have ensured all type sets in the compartment contain * ANYOBJECT instead of this object. */OBJECT_FLAG_SETS_MARKED_UNKNOWN=0x8,/* Mask/shift for the number of properties in propertySet */OBJECT_FLAG_PROPERTY_COUNT_MASK=0xfff0,OBJECT_FLAG_PROPERTY_COUNT_SHIFT=4,OBJECT_FLAG_PROPERTY_COUNT_LIMIT=OBJECT_FLAG_PROPERTY_COUNT_MASK>>OBJECT_FLAG_PROPERTY_COUNT_SHIFT,/* Whether any objects this represents may have sparse indexes. */OBJECT_FLAG_SPARSE_INDEXES=0x00010000,/* Whether any objects this represents may not have packed dense elements. */OBJECT_FLAG_NON_PACKED=0x00020000,/* * Whether any objects this represents may be arrays whose length does not * fit in an int32. */OBJECT_FLAG_LENGTH_OVERFLOW=0x00040000,/* Whether any objects have been iterated over. */OBJECT_FLAG_ITERATED=0x00080000,/* For a global object, whether flags were set on the RegExpStatics. */OBJECT_FLAG_REGEXP_FLAGS_SET=0x00100000,/* * For the function on a run-once script, whether the function has actually * run multiple times. */OBJECT_FLAG_RUNONCE_INVALIDATED=0x00200000,/* * Whether objects with this type should be allocated directly in the * tenured heap. */OBJECT_FLAG_PRE_TENURE=0x00400000,/* * Whether all properties of this object are considered unknown. * If set, all other flags in DYNAMIC_MASK will also be set. */OBJECT_FLAG_UNKNOWN_PROPERTIES=0x00800000,/* Flags which indicate dynamic properties of represented objects. */OBJECT_FLAG_DYNAMIC_MASK=0x00ff0000,/* Mask for objects created with unknown properties. */OBJECT_FLAG_UNKNOWN_MASK=OBJECT_FLAG_DYNAMIC_MASK|OBJECT_FLAG_SETS_MARKED_UNKNOWN};typedefuint32_tTypeObjectFlags;classStackTypeSet;classHeapTypeSet;classTemporaryTypeSet;/* * Information about the set of types associated with an lvalue. There are * three kinds of type sets: * * - StackTypeSet are associated with TypeScripts, for arguments and values * observed at property reads. These are implicitly frozen on compilation * and do not have constraints attached to them. * * - HeapTypeSet are associated with the properties of TypeObjects. These * may have constraints added to them to trigger invalidation of compiled * code. * * - TemporaryTypeSet are created during compilation and do not outlive * that compilation. */classTypeSet{protected:/* Flags for this type set. */TypeFlagsflags;/* Possible objects this type set can represent. */TypeObjectKey**objectSet;public:TypeSet():flags(0),objectSet(nullptr){}voidprint();/* Whether this set contains a specific type. */inlineboolhasType(Typetype)const;TypeFlagsbaseFlags()const{returnflags&TYPE_FLAG_BASE_MASK;}boolunknown()const{return!!(flags&TYPE_FLAG_UNKNOWN);}boolunknownObject()const{return!!(flags&(TYPE_FLAG_UNKNOWN|TYPE_FLAG_ANYOBJECT));}boolempty()const{return!baseFlags()&&!baseObjectCount();}boolhasAnyFlag(TypeFlagsflags)const{JS_ASSERT((flags&TYPE_FLAG_BASE_MASK)==flags);return!!(baseFlags()&flags);}boolnonDataProperty()const{returnflags&TYPE_FLAG_NON_DATA_PROPERTY;}boolnonWritableProperty()const{returnflags&TYPE_FLAG_NON_WRITABLE_PROPERTY;}booldefiniteProperty()const{returnflags&TYPE_FLAG_DEFINITE_MASK;}unsigneddefiniteSlot()const{JS_ASSERT(definiteProperty());return(flags>>TYPE_FLAG_DEFINITE_SHIFT)-1;}/* Join two type sets into a new set. The result should not be modified further. */staticTemporaryTypeSet*unionSets(TypeSet*a,TypeSet*b,LifoAlloc*alloc);/* Add a type to this set using the specified allocator. */inlinevoidaddType(Typetype,LifoAlloc*alloc);/* Get a list of all types in this set. */typedefVector<Type,1,SystemAllocPolicy>TypeList;boolenumerateTypes(TypeList*list);/* * Iterate through the objects in this set. getObjectCount overapproximates * in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject * may return nullptr. */inlineunsignedgetObjectCount()const;inlineTypeObjectKey*getObject(unsignedi)const;inlineJSObject*getSingleObject(unsignedi)const;inlineTypeObject*getTypeObject(unsignedi)const;/* The Class of an object in this set. */inlineconstClass*getObjectClass(unsignedi)const;boolcanSetDefinite(unsignedslot){// Note: the cast is required to work around an MSVC issue.return(slot+1)<=(unsigned(TYPE_FLAG_DEFINITE_MASK)>>TYPE_FLAG_DEFINITE_SHIFT);}voidsetDefinite(unsignedslot){JS_ASSERT(canSetDefinite(slot));flags|=((slot+1)<<TYPE_FLAG_DEFINITE_SHIFT);JS_ASSERT(definiteSlot()==slot);}/* Whether any values in this set might have the specified type. */boolmightBeType(JSValueTypetype);/* * Get whether this type set is known to be a subset of other. * This variant doesn't freeze constraints. That variant is called knownSubset */boolisSubset(TypeSet*other);/* Forward all types in this set to the specified constraint. */booladdTypesToConstraint(JSContext*cx,TypeConstraint*constraint);// Clone a type set into an arbitrary allocator.TemporaryTypeSet*clone(LifoAlloc*alloc)const;boolclone(LifoAlloc*alloc,TemporaryTypeSet*result)const;// Create a new TemporaryTypeSet where undefined and/or null has been filtered out.TemporaryTypeSet*filter(LifoAlloc*alloc,boolfilterUndefined,boolfilterNull)const;protected:uint32_tbaseObjectCount()const{return(flags&TYPE_FLAG_OBJECT_COUNT_MASK)>>TYPE_FLAG_OBJECT_COUNT_SHIFT;}inlinevoidsetBaseObjectCount(uint32_tcount);inlinevoidclearObjects();};/* Superclass common to stack and heap type sets. */classConstraintTypeSet:publicTypeSet{public:/* Chain of constraints which propagate changes out from this type set. */TypeConstraint*constraintList;ConstraintTypeSet():constraintList(nullptr){}/* * Add a type to this set, calling any constraint handlers if this is a new * possible type. */inlinevoidaddType(ExclusiveContext*cx,Typetype);/* Add a new constraint to this set. */booladdConstraint(JSContext*cx,TypeConstraint*constraint,boolcallExisting=true);inlinevoidsweep(JS::Zone*zone,bool*oom);};classStackTypeSet:publicConstraintTypeSet{public:};classHeapTypeSet:publicConstraintTypeSet{inlinevoidnewPropertyState(ExclusiveContext*cx);public:/* Mark this type set as representing a non-data property. */inlinevoidsetNonDataProperty(ExclusiveContext*cx);inlinevoidsetNonDataProperty();// Variant for use during GC./* Mark this type set as representing a non-writable property. */inlinevoidsetNonWritableProperty(ExclusiveContext*cx);};classCompilerConstraintList;CompilerConstraintList*NewCompilerConstraintList(jit::TempAllocator&alloc);classTemporaryTypeSet:publicTypeSet{public:TemporaryTypeSet(){}TemporaryTypeSet(Typetype);TemporaryTypeSet(uint32_tflags,TypeObjectKey**objectSet){this->flags=flags;this->objectSet=objectSet;}/* * Constraints for JIT compilation. * * Methods for JIT compilation. These must be used when a script is * currently being compiled (see AutoEnterCompilation) and will add * constraints ensuring that if the return value change in the future due * to new type information, the script's jitcode will be discarded. *//* Get any type tag which all values in this set must have. */JSValueTypegetKnownTypeTag();boolisMagicArguments(){returngetKnownTypeTag()==JSVAL_TYPE_MAGIC;}/* Whether this value may be an object. */boolmaybeObject(){returnunknownObject()||baseObjectCount()>0;}/* * Whether this typeset represents a potentially sentineled object value: * the value may be an object or null or undefined. * Returns false if the value cannot ever be an object. */boolobjectOrSentinel(){TypeFlagsflags=TYPE_FLAG_UNDEFINED|TYPE_FLAG_NULL|TYPE_FLAG_ANYOBJECT;if(baseFlags()&(~flags&TYPE_FLAG_BASE_MASK))returnfalse;returnhasAnyFlag(TYPE_FLAG_ANYOBJECT)||baseObjectCount()>0;}/* Whether the type set contains objects with any of a set of flags. */boolhasObjectFlags(CompilerConstraintList*constraints,TypeObjectFlagsflags);/* Get the class shared by all objects in this set, or nullptr. */constClass*getKnownClass();/* Result returned from forAllClasses */enumForAllResult{EMPTY=1,// Set emptyALL_TRUE,// Set not empty and predicate returned true for all classesALL_FALSE,// Set not empty and predicate returned false for all classesMIXED,// Set not empty and predicate returned false for some classes// and true for others, or set contains an unknown or non-object// type};/* Apply func to the members of the set and return an appropriate result. * The iteration may end early if the result becomes known early. */ForAllResultforAllClasses(bool(*func)(constClass*clasp));/* Get the prototype shared by all objects in this set, or nullptr. */JSObject*getCommonPrototype();/* Get the typed array type of all objects in this set, or TypedArrayObject::TYPE_MAX. */intgetTypedArrayType();/* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */boolisDOMClass();/* Whether clasp->isCallable() is true for one or more objects in this set. */boolmaybeCallable();/* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */boolmaybeEmulatesUndefined();/* Get the single value which can appear in this type set, otherwise nullptr. */JSObject*getSingleton();/* Whether any objects in the type set needs a barrier on id. */boolpropertyNeedsBarrier(CompilerConstraintList*constraints,jsidid);/* * Whether this set contains all types in other, except (possibly) the * specified type. */boolfiltersType(constTemporaryTypeSet*other,Typetype)const;enumDoubleConversion{/* All types in the set should use eager double conversion. */AlwaysConvertToDoubles,/* Some types in the set should use eager double conversion. */MaybeConvertToDoubles,/* No types should use eager double conversion. */DontConvertToDoubles,/* Some types should use eager double conversion, others cannot. */AmbiguousDoubleConversion};/* * Whether known double optimizations are possible for element accesses on * objects in this type set. */DoubleConversionconvertDoubleElements(CompilerConstraintList*constraints);};boolAddClearDefiniteGetterSetterForPrototypeChain(JSContext*cx,TypeObject*type,HandleIdid);boolAddClearDefiniteFunctionUsesInScript(JSContext*cx,TypeObject*type,JSScript*script,JSScript*calleeScript);/* Is this a reasonable PC to be doing inlining on? */inlineboolisInlinableCall(jsbytecode*pc);/* Type information about a property. */structProperty{/* Identifier for this property, JSID_VOID for the aggregate integer index property. */HeapIdid;/* Possible types for this property, including types inherited from prototypes. */HeapTypeSettypes;Property(jsidid):id(id){}Property(constProperty&o):id(o.id.get()),types(o.types){}staticuint32_tkeyBits(jsidid){returnuint32_t(JSID_BITS(id));}staticjsidgetKey(Property*p){returnp->id;}};structTypeNewScript;structTypeTypedObject;structTypeObjectAddendum{enumKind{NewScript,TypedObject};TypeObjectAddendum(Kindkind);constKindkind;boolisNewScript(){returnkind==NewScript;}TypeNewScript*asNewScript(){JS_ASSERT(isNewScript());return(TypeNewScript*)this;}boolisTypedObject(){returnkind==TypedObject;}TypeTypedObject*asTypedObject(){JS_ASSERT(isTypedObject());return(TypeTypedObject*)this;}staticinlinevoidwriteBarrierPre(TypeObjectAddendum*type);staticvoidwriteBarrierPost(TypeObjectAddendum*newScript,void*addr){}};/* * Information attached to a TypeObject if it is always constructed using 'new' * on a particular script. This is used to manage state related to the definite * properties on the type object: these definite properties depend on type * information which could change as the script executes (e.g. a scripted * setter is added to a prototype object), and we need to ensure both that the * appropriate type constraints are in place when necessary, and that we can * remove the definite property information and repair the JS stack if the * constraints are violated. */structTypeNewScript:publicTypeObjectAddendum{TypeNewScript();HeapPtrFunctionfun;/* * Template object to use for newly constructed objects. Reflects all * definite properties the object will have and the allocation kind to use * for the object. The allocation kind --- and template object itself --- * is subject to change if objects allocated with this type are given * dynamic slots later on due to new properties being added after the * constructor function finishes. */HeapPtrObjecttemplateObject;/* * Order in which properties become initialized. We need this in case a * scripted setter is added to one of the object's prototypes while it is * in the middle of being initialized, so we can walk the stack and fixup * any objects which look for in-progress objects which were prematurely * set with their final shape. Property assignments in inner frames are * preceded by a series of SETPROP_FRAME entries specifying the stack down * to the frame containing the write. */structInitializer{enumKind{SETPROP,SETPROP_FRAME,DONE}kind;uint32_toffset;Initializer(Kindkind,uint32_toffset):kind(kind),offset(offset){}};Initializer*initializerList;staticinlinevoidwriteBarrierPre(TypeNewScript*newScript);};structTypeTypedObject:publicTypeObjectAddendum{private:HeapPtrObjectdescr_;public:TypeTypedObject(Handle<TypeDescr*>descr);HeapPtrObject&descrHeapPtr(){returndescr_;}TypeDescr&descr();};/* * Lazy type objects overview. * * Type objects which represent at most one JS object are constructed lazily. * These include types for native functions, standard classes, scripted * functions defined at the top level of global/eval scripts, and in some * other cases. Typical web workloads often create many windows (and many * copies of standard natives) and many scripts, with comparatively few * non-singleton types. * * We can recover the type information for the object from examining it, * so don't normally track the possible types of its properties as it is * updated. Property type sets for the object are only constructed when an * analyzed script attaches constraints to it: the script is querying that * property off the object or another which delegates to it, and the analysis * information is sensitive to changes in the property's type. Future changes * to the property (whether those uncovered by analysis or those occurring * in the VM) will treat these properties like those of any other type object. *//* Type information about an object accessed by a script. */structTypeObject:gc::BarrieredCell<TypeObject>{private:/* Class shared by object using this type. */constClass*clasp_;/* Prototype shared by objects using this type. */HeapPtrObjectproto_;/* * Whether there is a singleton JS object with this type. That JS object * must appear in type sets instead of this; we include the back reference * here to allow reverting the JS object to a lazy type. */HeapPtrObjectsingleton_;public:constClass*clasp()const{returnclasp_;}voidsetClasp(constClass*clasp){JS_ASSERT(singleton());clasp_=clasp;}TaggedProtoproto()const{returnTaggedProto(proto_);}JSObject*singleton()const{returnsingleton_;}// For use during marking, don't call otherwise.HeapPtrObject&protoRaw(){returnproto_;}HeapPtrObject&singletonRaw(){returnsingleton_;}voidsetProto(JSContext*cx,TaggedProtoproto);voidsetProtoUnchecked(TaggedProtoproto){proto_=proto.raw();}voidinitSingleton(JSObject*singleton){singleton_=singleton;}/* * Value held by singleton if this is a standin type for a singleton JS * object whose type has not been constructed yet. */staticconstsize_tLAZY_SINGLETON=1;boollazy()const{returnsingleton()==(JSObject*)LAZY_SINGLETON;}private:/* Flags for this object. */TypeObjectFlagsflags_;/* * This field allows various special classes of objects to attach * additional information to a type object: * * - `TypeNewScript`: If addendum is a `TypeNewScript`, it * indicates that objects of this type have always been * constructed using 'new' on the specified script, which adds * some number of properties to the object in a definite order * before the object escapes. */HeapPtr<TypeObjectAddendum>addendum;public:TypeObjectFlagsflags()const{returnflags_;}voidaddFlags(TypeObjectFlagsflags){flags_|=flags;}voidclearFlags(TypeObjectFlagsflags){flags_&=~flags;}boolhasNewScript()const{returnaddendum&&addendum->isNewScript();}TypeNewScript*newScript(){returnaddendum->asNewScript();}boolhasTypedObject(){returnaddendum&&addendum->isTypedObject();}TypeTypedObject*typedObject(){returnaddendum->asTypedObject();}voidsetAddendum(TypeObjectAddendum*addendum);/* * Tag the type object for a binary data type descriptor, instance, * or handle with the type representation of the data it points at. * If this type object is already tagged with a binary data addendum, * this addendum must already be associated with the same TypeRepresentation, * and the method has no effect. */booladdTypedObjectAddendum(JSContext*cx,Handle<TypeDescr*>descr);private:/* * Properties of this object. This may contain JSID_VOID, representing the * types of all integer indexes of the object, and/or JSID_EMPTY, holding * constraints listening to changes to the object's state. * * The type sets in the properties of a type object describe the possible * values that can be read out of that property in actual JS objects. * Properties only account for native properties (those with a slot and no * specialized getter hook) and the elements of dense arrays. For accesses * on such properties, the correspondence is as follows: * * 1. If the type has unknownProperties(), the possible properties and * value types for associated JSObjects are unknown. * * 2. Otherwise, for any JSObject obj with TypeObject type, and any jsid id * which is a property in obj, before obj->getProperty(id) the property * in type for id must reflect the result of the getProperty. * * There is an exception for properties of global JS objects which * are undefined at the point where the property was (lazily) generated. * In such cases the property type set will remain empty, and the * 'undefined' type will only be added after a subsequent assignment or * deletion. After these properties have been assigned a defined value, * the only way they can become undefined again is after such an assign * or deletion. * * There is another exception for array lengths, which are special cased * by the compiler and VM and are not reflected in property types. * * We establish these by using write barriers on calls to setProperty and * defineProperty which are on native properties, and on any jitcode which * might update the property with a new type. */Property**propertySet;public:/* If this is an interpreted function, the function object. */HeapPtrFunctioninterpretedFunction;#if JS_BITS_PER_WORD == 32uint32_tpadding;#endifinlineTypeObject(constClass*clasp,TaggedProtoproto,TypeObjectFlagsinitialFlags);boolhasAnyFlags(TypeObjectFlagsflags){JS_ASSERT((flags&OBJECT_FLAG_DYNAMIC_MASK)==flags);return!!(this->flags()&flags);}boolhasAllFlags(TypeObjectFlagsflags){JS_ASSERT((flags&OBJECT_FLAG_DYNAMIC_MASK)==flags);return(this->flags()&flags)==flags;}boolunknownProperties(){JS_ASSERT_IF(flags()&OBJECT_FLAG_UNKNOWN_PROPERTIES,hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK));return!!(flags()&OBJECT_FLAG_UNKNOWN_PROPERTIES);}boolshouldPreTenure(){returnhasAnyFlags(OBJECT_FLAG_PRE_TENURE)&&!unknownProperties();}boolhasTenuredProto()const{return!(flags()&OBJECT_FLAG_NURSERY_PROTO);}gc::InitialHeapinitialHeap(CompilerConstraintList*constraints);boolcanPreTenure(){// Only types associated with particular allocation sites or 'new'// scripts can be marked as needing pretenuring. Other types can be// used for different purposes across the compartment and can't use// this bit reliably.if(unknownProperties())returnfalse;return(flags()&OBJECT_FLAG_FROM_ALLOCATION_SITE)||hasNewScript();}voidsetShouldPreTenure(ExclusiveContext*cx){JS_ASSERT(canPreTenure());setFlags(cx,OBJECT_FLAG_PRE_TENURE);}/* * Get or create a property of this object. Only call this for properties which * a script accesses explicitly. */inlineHeapTypeSet*getProperty(ExclusiveContext*cx,jsidid);/* Get a property only if it already exists. */inlineHeapTypeSet*maybeGetProperty(jsidid);inlineunsignedgetPropertyCount();inlineProperty*getProperty(unsignedi);/* Helpers */booladdProperty(ExclusiveContext*cx,jsidid,Property**pprop);booladdDefiniteProperties(ExclusiveContext*cx,JSObject*obj);boolmatchDefiniteProperties(HandleObjectobj);voidaddPrototype(JSContext*cx,TypeObject*proto);voidaddPropertyType(ExclusiveContext*cx,jsidid,Typetype);voidaddPropertyType(ExclusiveContext*cx,jsidid,constValue&value);voidmarkPropertyNonData(ExclusiveContext*cx,jsidid);voidmarkPropertyNonWritable(ExclusiveContext*cx,jsidid);voidmarkStateChange(ExclusiveContext*cx);voidsetFlags(ExclusiveContext*cx,TypeObjectFlagsflags);voidmarkUnknown(ExclusiveContext*cx);voidclearAddendum(ExclusiveContext*cx);voidclearNewScriptAddendum(ExclusiveContext*cx);voidclearTypedObjectAddendum(ExclusiveContext*cx);voidmaybeClearNewScriptAddendumOnOOM();boolisPropertyNonData(jsidid);boolisPropertyNonWritable(jsidid);voidprint();inlinevoidclearProperties();inlinevoidsweep(FreeOp*fop,bool*oom);size_tsizeOfExcludingThis(mozilla::MallocSizeOfmallocSizeOf)const;/* * Type objects don't have explicit finalizers. Memory owned by a type * object pending deletion is released when weak references are sweeped * from all the compartment's type objects. */voidfinalize(FreeOp*fop){}staticinlineThingRootKindrootKind(){returnTHING_ROOT_TYPE_OBJECT;}staticinlineuint32_toffsetOfClasp(){returnoffsetof(TypeObject,clasp_);}staticinlineuint32_toffsetOfProto(){returnoffsetof(TypeObject,proto_);}private:inlineuint32_tbasePropertyCount()const;inlinevoidsetBasePropertyCount(uint32_tcount);staticvoidstaticAsserts(){JS_STATIC_ASSERT(offsetof(TypeObject,proto_)==offsetof(js::shadow::TypeObject,proto));}};/* * Entries for the per-compartment set of type objects which are 'new' types to * use for some prototype and constructed with an optional script. This also * includes entries for the set of lazy type objects in the compartment, which * use a null script (though there are only a few of these per compartment). */structTypeObjectWithNewScriptEntry{ReadBarriered<TypeObject>object;// Note: This pointer is only used for equality and does not need a read barrier.JSFunction*newFunction;TypeObjectWithNewScriptEntry(TypeObject*object,JSFunction*newFunction):object(object),newFunction(newFunction){}structLookup{constClass*clasp;TaggedProtohashProto;TaggedProtomatchProto;JSFunction*newFunction;Lookup(constClass*clasp,TaggedProtoproto,JSFunction*newFunction):clasp(clasp),hashProto(proto),matchProto(proto),newFunction(newFunction){}#ifdef JSGC_GENERATIONAL/* * For use by generational post barriers only. Look up an entry whose * proto has been moved, but was hashed with the original value. */Lookup(constClass*clasp,TaggedProtohashProto,TaggedProtomatchProto,JSFunction*newFunction):clasp(clasp),hashProto(hashProto),matchProto(matchProto),newFunction(newFunction){}#endif};staticinlineHashNumberhash(constLookup&lookup);staticinlineboolmatch(constTypeObjectWithNewScriptEntry&key,constLookup&lookup);staticvoidrekey(TypeObjectWithNewScriptEntry&k,constTypeObjectWithNewScriptEntry&newKey){k=newKey;}};typedefHashSet<TypeObjectWithNewScriptEntry,TypeObjectWithNewScriptEntry,SystemAllocPolicy>TypeObjectWithNewScriptSet;/* Whether to use a new type object when calling 'new' at script/pc. */boolUseNewType(JSContext*cx,JSScript*script,jsbytecode*pc);boolUseNewTypeForClone(JSFunction*fun);/* * Whether Array.prototype, or an object on its proto chain, has an * indexed property. */boolArrayPrototypeHasIndexedProperty(CompilerConstraintList*constraints,JSScript*script);/* Whether obj or any of its prototypes have an indexed property. */boolTypeCanHaveExtraIndexedProperties(CompilerConstraintList*constraints,TemporaryTypeSet*types);/* Persistent type information for a script, retained across GCs. */classTypeScript{friendclass::JSScript;/* Analysis information for the script, cleared on each GC. */analyze::ScriptAnalysis*analysis;public:/* Array of type type sets for variables and JOF_TYPESET ops. */StackTypeSet*typeArray()const{return(StackTypeSet*)(uintptr_t(this)+sizeof(TypeScript));}staticinlineunsignedNumTypeSets(JSScript*script);staticinlineStackTypeSet*ThisTypes(JSScript*script);staticinlineStackTypeSet*ArgTypes(JSScript*script,unsignedi);/* Get the type set for values observed at an opcode. */staticinlineStackTypeSet*BytecodeTypes(JSScript*script,jsbytecode*pc);template<typenameTYPESET>staticinlineTYPESET*BytecodeTypes(JSScript*script,jsbytecode*pc,uint32_t*hint,TYPESET*typeArray);/* Get a type object for an allocation site in this script. */staticinlineTypeObject*InitObject(JSContext*cx,JSScript*script,jsbytecode*pc,JSProtoKeykind);/* * Monitor a bytecode pushing any value. This must be called for any opcode * which is JOF_TYPESET, and where either the script has not been analyzed * by type inference or where the pc has type barriers. For simplicity, we * always monitor JOF_TYPESET opcodes in the interpreter and stub calls, * and only look at barriers when generating JIT code for the script. */staticinlinevoidMonitor(JSContext*cx,JSScript*script,jsbytecode*pc,constjs::Value&val);staticinlinevoidMonitor(JSContext*cx,constjs::Value&rval);/* Monitor an assignment at a SETELEM on a non-integer identifier. */staticinlinevoidMonitorAssign(JSContext*cx,HandleObjectobj,jsidid);/* Add a type for a variable in a script. */staticinlinevoidSetThis(JSContext*cx,JSScript*script,Typetype);staticinlinevoidSetThis(JSContext*cx,JSScript*script,constjs::Value&value);staticinlinevoidSetArgument(JSContext*cx,JSScript*script,unsignedarg,Typetype);staticinlinevoidSetArgument(JSContext*cx,JSScript*script,unsignedarg,constjs::Value&value);/* * Freeze all the stack type sets in a script, for a compilation. Returns * copies of the type sets which will be checked against the actual ones * under FinishCompilation, to detect any type changes. */staticboolFreezeTypeSets(CompilerConstraintList*constraints,JSScript*script,TemporaryTypeSet**pThisTypes,TemporaryTypeSet**pArgTypes,TemporaryTypeSet**pBytecodeTypes);staticvoidPurge(JSContext*cx,HandleScriptscript);staticvoidSweep(FreeOp*fop,JSScript*script,bool*oom);voiddestroy();size_tsizeOfIncludingThis(mozilla::MallocSizeOfmallocSizeOf)const{returnmallocSizeOf(this);}#ifdef DEBUGvoidprintTypes(JSContext*cx,HandleScriptscript)const;#endif};classRecompileInfo;// Allocate a CompilerOutput for a finished compilation and generate the type// constraints for the compilation. Returns whether the type constraints// still hold.boolFinishCompilation(JSContext*cx,HandleScriptscript,ExecutionModeexecutionMode,CompilerConstraintList*constraints,RecompileInfo*precompileInfo);// Update the actual types in any scripts queried by constraints with any// speculative types added during the definite properties analysis.voidFinishDefinitePropertiesAnalysis(JSContext*cx,CompilerConstraintList*constraints);structArrayTableKey;typedefHashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy>ArrayTypeTable;structObjectTableKey;structObjectTableEntry;typedefHashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy>ObjectTypeTable;structAllocationSiteKey;typedefHashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy>AllocationSiteTable;classHeapTypeSetKey;// Type set entry for either a JSObject with singleton type or a non-singleton TypeObject.structTypeObjectKey{staticintptr_tkeyBits(TypeObjectKey*obj){return(intptr_t)obj;}staticTypeObjectKey*getKey(TypeObjectKey*obj){returnobj;}staticTypeObjectKey*get(JSObject*obj){JS_ASSERT(obj);return(TypeObjectKey*)(uintptr_t(obj)|1);}staticTypeObjectKey*get(TypeObject*obj){JS_ASSERT(obj);return(TypeObjectKey*)obj;}boolisTypeObject(){return(uintptr_t(this)&1)==0;}boolisSingleObject(){return(uintptr_t(this)&1)!=0;}TypeObject*asTypeObject(){JS_ASSERT(isTypeObject());return(TypeObject*)this;}JSObject*asSingleObject(){JS_ASSERT(isSingleObject());return(JSObject*)(uintptr_t(this)&~1);}constClass*clasp();TaggedProtoproto();boolhasTenuredProto();JSObject*singleton();TypeNewScript*newScript();boolunknownProperties();boolhasFlags(CompilerConstraintList*constraints,TypeObjectFlagsflags);voidwatchStateChangeForInlinedCall(CompilerConstraintList*constraints);voidwatchStateChangeForNewScriptTemplate(CompilerConstraintList*constraints);voidwatchStateChangeForTypedArrayBuffer(CompilerConstraintList*constraints);HeapTypeSetKeyproperty(jsidid);voidensureTrackedProperty(JSContext*cx,jsidid);TypeObject*maybeType();};// Representation of a heap type property which may or may not be instantiated.// Heap properties for singleton types are instantiated lazily as they are used// by the compiler, but this is only done on the main thread. If we are// compiling off thread and use a property which has not yet been instantiated,// it will be treated as empty and non-configured and will be instantiated when// rejoining to the main thread. If it is in fact not empty, the compilation// will fail; to avoid this, we try to instantiate singleton property types// during generation of baseline caches.classHeapTypeSetKey{friendclassTypeObjectKey;// Object and property being accessed.TypeObjectKey*object_;jsidid_;// If instantiated, the underlying heap type set.HeapTypeSet*maybeTypes_;public:HeapTypeSetKey():object_(nullptr),id_(JSID_EMPTY),maybeTypes_(nullptr){}TypeObjectKey*object()const{returnobject_;}jsidid()const{returnid_;}HeapTypeSet*maybeTypes()const{returnmaybeTypes_;}boolinstantiate(JSContext*cx);voidfreeze(CompilerConstraintList*constraints);JSValueTypeknownTypeTag(CompilerConstraintList*constraints);boolnonData(CompilerConstraintList*constraints);boolnonWritable(CompilerConstraintList*constraints);boolisOwnProperty(CompilerConstraintList*constraints);boolknownSubset(CompilerConstraintList*constraints,constHeapTypeSetKey&other);JSObject*singleton(CompilerConstraintList*constraints);boolneedsBarrier(CompilerConstraintList*constraints);};/* * Information about the result of the compilation of a script. This structure * stored in the TypeCompartment is indexed by the RecompileInfo. This * indirection enables the invalidation of all constraints related to the same * compilation. */classCompilerOutput{// If this compilation has not been invalidated, the associated script and// kind of compilation being performed.JSScript*script_;ExecutionModemode_:2;// Whether this compilation is about to be invalidated.boolpendingInvalidation_:1;// During sweeping, the list of compiler outputs is compacted and invalidated// outputs are removed. This gives the new index for a valid compiler output.uint32_tsweepIndex_:29;public:CompilerOutput():script_(nullptr),mode_(SequentialExecution),pendingInvalidation_(false){}CompilerOutput(JSScript*script,ExecutionModemode):script_(script),mode_(mode),pendingInvalidation_(false){}JSScript*script()const{returnscript_;}inlineExecutionModemode()const{returnmode_;}inlinejit::IonScript*ion()const;boolisValid()const{returnscript_!=nullptr;}voidinvalidate(){script_=nullptr;}voidsetPendingInvalidation(){pendingInvalidation_=true;}boolpendingInvalidation(){returnpendingInvalidation_;}voidsetSweepIndex(uint32_tindex){if(index>=1<<29)MOZ_CRASH();sweepIndex_=index;}uint32_tsweepIndex(){returnsweepIndex_;}};classRecompileInfo{uint32_toutputIndex;public:RecompileInfo(uint32_toutputIndex=uint32_t(-1)):outputIndex(outputIndex){}booloperator==(constRecompileInfo&o)const{returnoutputIndex==o.outputIndex;}CompilerOutput*compilerOutput(TypeZone&types)const;CompilerOutput*compilerOutput(JSContext*cx)const;boolshouldSweep(TypeZone&types);};/* Type information for a compartment. */structTypeCompartment{/* Constraint solving worklist structures. *//* Number of scripts in this compartment. */unsignedscriptCount;/* Table for referencing types of objects keyed to an allocation site. */AllocationSiteTable*allocationSiteTable;/* Tables for determining types of singleton/JSON objects. */ArrayTypeTable*arrayTypeTable;ObjectTypeTable*objectTypeTable;private:voidsetTypeToHomogenousArray(ExclusiveContext*cx,JSObject*obj,Typetype);public:voidfixArrayType(ExclusiveContext*cx,JSObject*obj);voidfixObjectType(ExclusiveContext*cx,JSObject*obj);voidfixRestArgumentsType(ExclusiveContext*cx,JSObject*obj);JSObject*newTypedObject(JSContext*cx,IdValuePair*properties,size_tnproperties);TypeCompartment();~TypeCompartment();inlineJSCompartment*compartment();/* Prints results of this compartment if spew is enabled or force is set. */voidprint(JSContext*cx,boolforce);/* * Make a function or non-function object associated with an optional * script. The 'key' parameter here may be an array, typed array, function * or JSProto_Object to indicate a type whose class is unknown (not just * js_ObjectClass). */TypeObject*newTypeObject(ExclusiveContext*cx,constClass*clasp,Handle<TaggedProto>proto,TypeObjectFlagsinitialFlags=0);/* Get or make an object for an allocation site, and add to the allocation site table. */TypeObject*addAllocationSiteTypeObject(JSContext*cx,AllocationSiteKeykey);/* Mark any type set containing obj as having a generic object type. */voidmarkSetsUnknown(JSContext*cx,TypeObject*obj);voidclearTables();voidsweep(FreeOp*fop);voidfinalizeObjects();voidaddSizeOfExcludingThis(mozilla::MallocSizeOfmallocSizeOf,size_t*allocationSiteTables,size_t*arrayTypeTables,size_t*objectTypeTables);};voidFixRestArgumentsType(ExclusiveContext*cxArg,JSObject*obj);structTypeZone{JS::Zone*zone_;/* Pool for type information in this zone. */staticconstsize_tTYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE=8*1024;js::LifoAlloctypeLifoAlloc;/* * All Ion compilations that have occured in this zone, for indexing via * RecompileInfo. This includes both valid and invalid compilations, though * invalidated compilations are swept on GC. */Vector<CompilerOutput>*compilerOutputs;/* Pending recompilations to perform before execution of JIT code can resume. */Vector<RecompileInfo>*pendingRecompiles;/* Whether type inference is enabled in this compartment. */boolinferenceEnabled;TypeZone(JS::Zone*zone);~TypeZone();voidinit(JSContext*cx);JS::Zone*zone()const{returnzone_;}voidsweep(FreeOp*fop,boolreleaseTypes,bool*oom);voidclearAllNewScriptAddendumsOnOOM();/* Mark a script as needing recompilation once inference has finished. */voidaddPendingRecompile(JSContext*cx,constRecompileInfo&info);voidaddPendingRecompile(JSContext*cx,JSScript*script);voidprocessPendingRecompiles(FreeOp*fop);};enumSpewChannel{ISpewOps,/* ops: New constraints and types. */ISpewResult,/* result: Final type sets. */SPEW_COUNT};#ifdef DEBUGconstchar*InferSpewColorReset();constchar*InferSpewColor(TypeConstraint*constraint);constchar*InferSpewColor(TypeSet*types);voidInferSpew(SpewChannelwhich,constchar*fmt,...);constchar*TypeString(Typetype);constchar*TypeObjectString(TypeObject*type);/* Check that the type property for id in obj contains value. */boolTypeHasProperty(JSContext*cx,TypeObject*obj,jsidid,constValue&value);#elseinlineconstchar*InferSpewColorReset(){returnnullptr;}inlineconstchar*InferSpewColor(TypeConstraint*constraint){returnnullptr;}inlineconstchar*InferSpewColor(TypeSet*types){returnnullptr;}inlinevoidInferSpew(SpewChannelwhich,constchar*fmt,...){}inlineconstchar*TypeString(Typetype){returnnullptr;}inlineconstchar*TypeObjectString(TypeObject*type){returnnullptr;}#endif/* Print a warning, dump state and abort the program. */MOZ_NORETURNvoidTypeFailure(JSContext*cx,constchar*fmt,...);}/* namespace types */}/* namespace js */#endif /* jsinfer_h */