Bug 1491736 - Split out type-set classes and related data types from vm/TypeInference.h into vm/TypeSet.h, and move TypeNewScript from vm/TypeInference.h to vm/TypeInference-inl.h, so code can use TypeSet types without needing JSFunction, Shape, and other super-complex types as well (via HeapPtr<T*> fields in TypeNewScript). r=jandem

--HG--
rename : js/src/vm/TypeInference.h => js/src/vm/TypeSet.h
extra : rebase_source : 330bc27597e8a178129988d973ba4724450a43c6
This commit is contained in:
Jeff Walden 2018-09-15 20:24:30 -07:00
Родитель aec3d8264b
Коммит c2719f1ecf
18 изменённых файлов: 1216 добавлений и 1112 удалений

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozilla/TimeStamp.h"
#include "threading/ConditionVariable.h"
#include "threading/ProtectedData.h" // js::ThreadData
#include "vm/JSObject.h"
#include "vm/MutexIDs.h"
#include "vm/NativeObject.h"

Просмотреть файл

@ -14,6 +14,7 @@
#include "js/GCHashTable.h"
#include "vm/MallocProvider.h"
#include "vm/Runtime.h"
#include "vm/TypeInference.h"
namespace js {

Просмотреть файл

@ -18,6 +18,7 @@
#include "vm/EnvironmentObject-inl.h"
#include "vm/JSContext-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/TypeInference-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;

Просмотреть файл

@ -22,6 +22,7 @@
#include "vm/BytecodeUtil-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/JSScript-inl.h"
#include "vm/TypeInference-inl.h"
using namespace js;
using namespace js::jit;
@ -4367,7 +4368,7 @@ static bool
AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
MDefinition* thisValue, MInstruction* ins, bool definitelyExecuted,
HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList,
Vector<TypeNewScriptInitializer>* initializerList,
Vector<PropertyName*>* accessedProperties,
bool* phandled)
{
@ -4436,16 +4437,16 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
for (int i = callerResumePoints.length() - 1; i >= 0; i--) {
MResumePoint* rp = callerResumePoints[i];
JSScript* script = rp->block()->info().script();
TypeNewScript::Initializer entry(TypeNewScript::Initializer::SETPROP_FRAME,
script->pcToOffset(rp->pc()));
TypeNewScriptInitializer entry(TypeNewScriptInitializer::SETPROP_FRAME,
script->pcToOffset(rp->pc()));
if (!initializerList->append(entry)) {
return false;
}
}
JSScript* script = ins->block()->info().script();
TypeNewScript::Initializer entry(TypeNewScript::Initializer::SETPROP,
script->pcToOffset(setprop->resumePoint()->pc()));
TypeNewScriptInitializer entry(TypeNewScriptInitializer::SETPROP,
script->pcToOffset(setprop->resumePoint()->pc()));
if (!initializerList->append(entry)) {
return false;
}
@ -4501,7 +4502,7 @@ CmpInstructions(const void* a, const void* b)
bool
jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
ObjectGroup* group, HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList)
Vector<TypeNewScriptInitializer>* initializerList)
{
MOZ_ASSERT(cx->zone()->types.activeAnalysis);

Просмотреть файл

@ -203,7 +203,7 @@ ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSu
MOZ_MUST_USE bool
AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
ObjectGroup* group, HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList);
Vector<TypeNewScriptInitializer>* initializerList);
MOZ_MUST_USE bool
AnalyzeArgumentsUsage(JSContext* cx, JSScript* script);

Просмотреть файл

@ -13,6 +13,7 @@
#include "vm/StringType.h"
#include "vm/JSObject-inl.h"
#include "vm/ObjectGroup-inl.h"
#include "vm/TypeInference-inl.h"
namespace js {

Просмотреть файл

@ -69,10 +69,12 @@
#include "vm/JSFunction-inl.h"
#include "vm/NativeObject-inl.h"
#include "vm/NumberObject-inl.h"
#include "vm/ObjectGroup-inl.h"
#include "vm/Realm-inl.h"
#include "vm/Shape-inl.h"
#include "vm/StringObject-inl.h"
#include "vm/TypedArrayObject-inl.h"
#include "vm/TypeInference-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;

Просмотреть файл

@ -49,6 +49,8 @@ namespace jit {
# define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript*)0x1)
class AutoKeepTypeScripts;
class AutoSweepTypeScript;
class BreakpointSite;
class Debugger;
class LazyScript;
@ -56,6 +58,7 @@ class ModuleObject;
class RegExpObject;
class SourceCompressionTask;
class Shape;
class TypeScript;
namespace frontend {
struct BytecodeEmitter;

Просмотреть файл

@ -23,6 +23,7 @@
#include "vm/EnvironmentObject-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/Shape-inl.h"
#include "vm/TypeInference-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;

Просмотреть файл

@ -25,6 +25,7 @@
#include "vm/TaggedProto.h"
#include "gc/Marking-inl.h"
#include "vm/TypeInference-inl.h"
#include "vm/UnboxedObject-inl.h"
using namespace js;

Просмотреть файл

@ -16,7 +16,7 @@
#include "js/GCHashTable.h"
#include "js/TypeDecls.h"
#include "vm/TaggedProto.h"
#include "vm/TypeInference.h"
#include "vm/TypeSet.h"
namespace js {
@ -25,7 +25,6 @@ class UnboxedLayout;
class PreliminaryObjectArrayWithTemplate;
class TypeNewScript;
class HeapTypeSet;
class AutoClearTypeInferenceStateOnOOM;
class AutoSweepObjectGroup;
class CompilerConstraintList;
@ -326,10 +325,7 @@ class ObjectGroup : public gc::TenuredCell
setAddendum(Addendum_None, nullptr);
}
bool hasUnanalyzedPreliminaryObjects() {
return (newScriptDontCheckGeneration() && !newScriptDontCheckGeneration()->analyzed()) ||
maybePreliminaryObjectsDontCheckGeneration();
}
inline bool hasUnanalyzedPreliminaryObjects();
inline UnboxedLayout* maybeUnboxedLayout(const AutoSweepObjectGroup& sweep);
inline UnboxedLayout& unboxedLayout(const AutoSweepObjectGroup& sweep);

Просмотреть файл

@ -18,9 +18,14 @@
#include "builtin/Symbol.h"
#include "gc/GC.h"
#include "jit/BaselineJIT.h"
#include "js/HeapAPI.h"
#include "vm/ArrayObject.h"
#include "vm/BooleanObject.h"
#include "vm/JSFunction.h"
#include "vm/NativeObject.h"
#include "vm/NumberObject.h"
#include "vm/ObjectGroup.h"
#include "vm/Shape.h"
#include "vm/SharedArrayObject.h"
#include "vm/StringObject.h"
#include "vm/TypedArrayObject.h"
@ -268,6 +273,161 @@ TypeIdString(jsid id)
#endif
}
// New script properties analyses overview.
//
// When constructing objects using 'new' on a script, we attempt to determine
// the properties which that object will eventually have. This is done via two
// analyses. One of these, the definite properties analysis, is static, and the
// other, the acquired properties analysis, is dynamic. As objects are
// constructed using 'new' on some script to create objects of group G, our
// analysis strategy is as follows:
//
// - When the first objects are created, no analysis is immediately performed.
// Instead, all objects of group G are accumulated in an array.
//
// - After a certain number of such objects have been created, the definite
// properties analysis is performed. This analyzes the body of the
// constructor script and any other functions it calls to look for properties
// which will definitely be added by the constructor in a particular order,
// creating an object with shape S.
//
// - The properties in S are compared with the greatest common prefix P of the
// shapes of the objects that have been created. If P has more properties
// than S, the acquired properties analysis is performed.
//
// - The acquired properties analysis marks all properties in P as definite
// in G, and creates a new group IG for objects which are partially
// initialized. Objects of group IG are initially created with shape S, and if
// they are later given shape P, their group can be changed to G.
//
// For objects which are rarely created, the definite properties analysis can
// be triggered after only one or a few objects have been allocated, when code
// being Ion compiled might access them. In this case type information in the
// constructor might not be good enough for the definite properties analysis to
// compute useful information, but the acquired properties analysis will still
// be able to identify definite properties in this case.
//
// This layered approach is designed to maximize performance on easily
// analyzable code, while still allowing us to determine definite properties
// robustly when code consistently adds the same properties to objects, but in
// complex ways which can't be understood statically.
class TypeNewScript
{
private:
// Scripted function which this information was computed for.
HeapPtr<JSFunction*> function_ = {};
// Any preliminary objects with the type. The analyses are not performed
// until this array is cleared.
PreliminaryObjectArray* preliminaryObjects = nullptr;
// After the new script properties analyses have been performed, a template
// object to use for newly constructed objects. The shape of this object
// reflects all definite properties the object will have, and the
// allocation kind to use. This is null if the new objects have an unboxed
// layout, in which case the UnboxedLayout provides the initial structure
// of the object.
HeapPtr<PlainObject*> templateObject_ = {};
// Order in which definite properties become initialized. We need this in
// case the definite properties are invalidated (such as by adding a setter
// to an object on the prototype chain) while an object 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 an incorrect
// 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.
TypeNewScriptInitializer* initializerList = nullptr;
// If there are additional properties found by the acquired properties
// analysis which were not found by the definite properties analysis, this
// shape contains all such additional properties (plus the definite
// properties). When an object of this group acquires this shape, it is
// fully initialized and its group can be changed to initializedGroup.
HeapPtr<Shape*> initializedShape_ = {};
// Group with definite properties set for all properties found by
// both the definite and acquired properties analyses.
HeapPtr<ObjectGroup*> initializedGroup_ = {};
public:
TypeNewScript() = default;
~TypeNewScript() {
js_delete(preliminaryObjects);
js_free(initializerList);
}
void clear() {
function_ = nullptr;
templateObject_ = nullptr;
initializedShape_ = nullptr;
initializedGroup_ = nullptr;
}
static void writeBarrierPre(TypeNewScript* newScript);
bool analyzed() const {
return preliminaryObjects == nullptr;
}
PlainObject* templateObject() const {
return templateObject_;
}
Shape* initializedShape() const {
return initializedShape_;
}
ObjectGroup* initializedGroup() const {
return initializedGroup_;
}
JSFunction* function() const {
return function_;
}
void trace(JSTracer* trc);
void sweep();
void registerNewObject(PlainObject* res);
bool maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force = false);
bool rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* group);
static bool make(JSContext* cx, ObjectGroup* group, JSFunction* fun);
static TypeNewScript* makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
PlainObject* templateObject);
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
static size_t offsetOfPreliminaryObjects() {
return offsetof(TypeNewScript, preliminaryObjects);
}
};
inline
UnboxedLayout::~UnboxedLayout()
{
if (newScript_) {
newScript_->clear();
}
js_delete(newScript_);
js_free(traceList_);
nativeGroup_.init(nullptr);
nativeShape_.init(nullptr);
replacementGroup_.init(nullptr);
constructorCode_.init(nullptr);
}
inline bool
ObjectGroup::hasUnanalyzedPreliminaryObjects()
{
return (newScriptDontCheckGeneration() && !newScriptDontCheckGeneration()->analyzed()) ||
maybePreliminaryObjectsDontCheckGeneration();
}
/*
* Structure for type inference entry point functions. All functions which can
* change type information must use this, and functions which depend on

Просмотреть файл

@ -4065,11 +4065,14 @@ TypeNewScript::makeNativeVersion(JSContext* cx, TypeNewScript* newScript,
nativeNewScript->function_ = newScript->function();
nativeNewScript->templateObject_ = templateObject;
Initializer* cursor = newScript->initializerList;
while (cursor->kind != Initializer::DONE) { cursor++; }
TypeNewScriptInitializer* cursor = newScript->initializerList;
while (cursor->kind != TypeNewScriptInitializer::DONE) {
cursor++;
}
size_t initializerLength = cursor - newScript->initializerList + 1;
nativeNewScript->initializerList = cx->pod_calloc<Initializer>(initializerLength);
nativeNewScript->initializerList = cx->pod_calloc<TypeNewScriptInitializer>(initializerLength);
if (!nativeNewScript->initializerList) {
return nullptr;
}
@ -4232,7 +4235,7 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
return false;
}
Vector<Initializer> initializerVector(cx);
Vector<TypeNewScriptInitializer> initializerVector(cx);
RootedPlainObject templateRoot(cx, templateObject());
RootedFunction fun(cx, function());
@ -4277,13 +4280,14 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
}
}
Initializer done(Initializer::DONE, 0);
TypeNewScriptInitializer done(TypeNewScriptInitializer::DONE, 0);
if (!initializerVector.append(done)) {
return false;
}
initializerList = group->zone()->pod_calloc<Initializer>(initializerVector.length());
initializerList =
group->zone()->pod_calloc<TypeNewScriptInitializer>(initializerVector.length());
if (!initializerList) {
ReportOutOfMemory(cx);
return false;
@ -4444,8 +4448,8 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
// Index in pcOffsets of the frame currently being checked for a SETPROP.
int setpropDepth = callDepth;
for (Initializer* init = initializerList;; init++) {
if (init->kind == Initializer::SETPROP) {
for (TypeNewScriptInitializer* init = initializerList; ; init++) {
if (init->kind == TypeNewScriptInitializer::SETPROP) {
if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
// Have not yet reached this setprop.
break;
@ -4454,7 +4458,7 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
numProperties++;
pastProperty = false;
setpropDepth = callDepth;
} else if (init->kind == Initializer::SETPROP_FRAME) {
} else if (init->kind == TypeNewScriptInitializer::SETPROP_FRAME) {
if (!pastProperty) {
if (pcOffsets[setpropDepth] < init->offset) {
// Have not yet reached this inner call.
@ -4471,7 +4475,7 @@ TypeNewScript::rollbackPartiallyInitializedObjects(JSContext* cx, ObjectGroup* g
}
}
} else {
MOZ_ASSERT(init->kind == Initializer::DONE);
MOZ_ASSERT(init->kind == TypeNewScriptInitializer::DONE);
finished = true;
break;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

973
js/src/vm/TypeSet.h Normal file
Просмотреть файл

@ -0,0 +1,973 @@
/* -*- 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/. */
/* TypeSet classes and functions. */
#ifndef vm_TypeSet_h
#define vm_TypeSet_h
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE
#include "mozilla/Likely.h" // MOZ_UNLIKELY
#include <stdint.h> // intptr_t, uintptr_t, uint8_t, uint32_t
#include <stdio.h> // FILE
#include "jstypes.h" // JS_BITS_PER_WORD
#include "jsutil.h" // JS_CRASH_DIAGNOSTICS
#include "jit/IonTypes.h" // jit::MIRType
#include "js/GCAnnotations.h" // JS_HAZ_GC_POINTER
#include "js/TracingAPI.h" // JSTracer
#include "js/TypeDecls.h" // IF_BIGINT
#include "js/Utility.h" // UniqueChars
#include "js/Value.h" // JSVAL_TYPE_*
#include "js/Vector.h" // js::Vector
#include "vm/TaggedProto.h" // js::TaggedProto
struct JSContext;
struct jsid;
class JSObject;
namespace JS {
class Compartment;
class Realm;
class Zone;
} // namespace JS
namespace js {
namespace jit {
struct IonScript;
class TempAllocator;
} // namespace jit
class AutoClearTypeInferenceStateOnOOM;
class AutoSweepBase;
class AutoSweepObjectGroup;
struct Class;
class CompilerConstraintList;
class HeapTypeSetKey;
class LifoAlloc;
class ObjectGroup;
class SystemAllocPolicy;
class TypeConstraint;
class TypeNewScript;
class TypeZone;
/*
* 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.
*/
/* Flags and other state stored in TypeSet::flags */
enum : 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_SYMBOL = 0x40,
#ifdef ENABLE_BIGINT
TYPE_FLAG_BIGINT = 0x80,
TYPE_FLAG_LAZYARGS = 0x100,
TYPE_FLAG_ANYOBJECT = 0x200,
#else
TYPE_FLAG_LAZYARGS = 0x80,
TYPE_FLAG_ANYOBJECT = 0x100,
#endif
/* 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 |
TYPE_FLAG_SYMBOL |
IF_BIGINT(TYPE_FLAG_BIGINT, 0),
/* Mask/shift for the number of objects in objectSet */
#ifdef ENABLE_BIGINT
TYPE_FLAG_OBJECT_COUNT_MASK = 0x3c00,
TYPE_FLAG_OBJECT_COUNT_SHIFT = 10,
#else
TYPE_FLAG_OBJECT_COUNT_MASK = 0x3e00,
TYPE_FLAG_OBJECT_COUNT_SHIFT = 9,
#endif
TYPE_FLAG_OBJECT_COUNT_LIMIT = 7,
TYPE_FLAG_DOMOBJECT_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 = 0x00004000,
/* Mask of normal type flags on a type set. */
TYPE_FLAG_BASE_MASK = TYPE_FLAG_PRIMITIVE | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT | TYPE_FLAG_UNKNOWN,
/* 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 = 0x00008000,
/* Whether the property has ever been made non-writable. */
TYPE_FLAG_NON_WRITABLE_PROPERTY = 0x00010000,
/* Whether the property might not be constant. */
TYPE_FLAG_NON_CONSTANT_PROPERTY = 0x00020000,
/*
* 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 = 0xfffc0000,
TYPE_FLAG_DEFINITE_SHIFT = 18
};
using TypeFlags = uint32_t;
static_assert(TYPE_FLAG_PRIMITIVE < TYPE_FLAG_ANYOBJECT &&
TYPE_FLAG_LAZYARGS < TYPE_FLAG_ANYOBJECT,
"TYPE_FLAG_ANYOBJECT should be greater than primitive type flags");
/* Flags and other state stored in ObjectGroup::Flags */
enum : uint32_t
{
/* Whether this group is associated with some allocation site. */
OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1,
/* Whether this group is associated with a single object. */
OBJECT_FLAG_SINGLETON = 0x2,
/*
* Whether this group is used by objects whose singleton groups have not
* been created yet.
*/
OBJECT_FLAG_LAZY_SINGLETON = 0x4,
/* Mask/shift for the number of properties in propertySet */
OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff8,
OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 3,
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,
/* Whether any object this represents may have non-extensible elements. */
OBJECT_FLAG_NON_EXTENSIBLE_ELEMENTS = 0x00100000,
/*
* For the function on a run-once script, whether the function has actually
* run multiple times.
*/
OBJECT_FLAG_RUNONCE_INVALIDATED = 0x00200000,
/*
* For a global object, whether any array buffers in this compartment with
* typed object views have ever been detached.
*/
OBJECT_FLAG_TYPED_OBJECT_HAS_DETACHED_BUFFER = 0x00400000,
/*
* Whether objects with this type should be allocated directly in the
* tenured heap.
*/
OBJECT_FLAG_PRE_TENURE = 0x00800000,
/* Whether objects with this type might have copy on write elements. */
OBJECT_FLAG_COPY_ON_WRITE = 0x01000000,
/* Whether this type has had its 'new' script cleared in the past. */
OBJECT_FLAG_NEW_SCRIPT_CLEARED = 0x02000000,
/*
* 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 = 0x04000000,
/* Flags which indicate dynamic properties of represented objects. */
OBJECT_FLAG_DYNAMIC_MASK = 0x07ff0000,
// Mask/shift for the kind of addendum attached to this group.
OBJECT_FLAG_ADDENDUM_MASK = 0x38000000,
OBJECT_FLAG_ADDENDUM_SHIFT = 27,
// Mask/shift for this group's generation. If out of sync with the
// TypeZone's generation, this group hasn't been swept yet.
OBJECT_FLAG_GENERATION_MASK = 0x40000000,
OBJECT_FLAG_GENERATION_SHIFT = 30,
};
using ObjectGroupFlags = uint32_t;
class StackTypeSet;
class HeapTypeSet;
class TemporaryTypeSet;
/*
* [SMDOC] Type-Inference TypeSet
*
* 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 only have constraints added to them which can trigger invalidation of
* TypeNewScript information.
*
* - HeapTypeSet are associated with the properties of ObjectGroups. These
* may have constraints added to them to trigger invalidation of either
* compiled code or TypeNewScript information.
*
* - TemporaryTypeSet are created during compilation and do not outlive
* that compilation.
*
* The contents of a type set completely describe the values that a particular
* lvalue might have, except for the following cases:
*
* - If an object's prototype or class is dynamically mutated, its group will
* change. Type sets containing the old group will not necessarily contain
* the new group. When this occurs, the properties of the old and new group
* will both be marked as unknown, which will prevent Ion from optimizing
* based on the object's type information.
*
* - If an unboxed object is converted to a native object, its group will also
* change and type sets containing the old group will not necessarily contain
* the new group. Unlike the above case, this will not degrade property type
* information, but Ion will no longer optimize unboxed objects with the old
* group.
*/
class TypeSet
{
protected:
/* Flags for this type set. */
TypeFlags flags = 0;
public:
class ObjectKey;
protected:
/* Possible objects this type set can represent. */
ObjectKey** objectSet = nullptr;
public:
TypeSet() = default;
// Type set entry for either a JSObject with singleton type or a
// non-singleton ObjectGroup.
class ObjectKey
{
public:
static intptr_t keyBits(ObjectKey* obj) { return (intptr_t) obj; }
static ObjectKey* getKey(ObjectKey* obj) { return obj; }
static inline ObjectKey* get(JSObject* obj);
static inline ObjectKey* get(ObjectGroup* group);
bool isGroup() {
return (uintptr_t(this) & 1) == 0;
}
bool isSingleton() {
return (uintptr_t(this) & 1) != 0;
}
inline ObjectGroup* group();
inline JSObject* singleton();
inline ObjectGroup* groupNoBarrier();
inline JSObject* singletonNoBarrier();
const Class* clasp();
TaggedProto proto();
TypeNewScript* newScript();
bool unknownProperties();
bool hasFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
bool hasStableClassAndProto(CompilerConstraintList* constraints);
void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints);
void watchStateChangeForUnboxedConvertedToNative(CompilerConstraintList* constraints);
HeapTypeSetKey property(jsid id);
void ensureTrackedProperty(JSContext* cx, jsid id);
ObjectGroup* maybeGroup();
JS::Compartment* maybeCompartment();
} JS_HAZ_GC_POINTER;
// Information about a single concrete type. We pack this into one word,
// where small values are particular primitive or other singleton types and
// larger values are either specific JS objects or object groups.
class Type
{
friend class TypeSet;
uintptr_t data;
explicit Type(uintptr_t data) : data(data) {}
public:
uintptr_t raw() const { return data; }
bool isPrimitive() const {
return data < JSVAL_TYPE_OBJECT;
}
bool isPrimitive(JSValueType type) const {
MOZ_ASSERT(type < JSVAL_TYPE_OBJECT);
return (uintptr_t) type == data;
}
JSValueType primitive() const {
MOZ_ASSERT(isPrimitive());
return (JSValueType) data;
}
bool isMagicArguments() const {
return primitive() == JSVAL_TYPE_MAGIC;
}
bool isSomeObject() const {
return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
}
bool isAnyObject() const {
return data == JSVAL_TYPE_OBJECT;
}
bool isUnknown() const {
return data == JSVAL_TYPE_UNKNOWN;
}
/* Accessors for types that are either JSObject or ObjectGroup. */
bool isObject() const {
MOZ_ASSERT(!isAnyObject() && !isUnknown());
return data > JSVAL_TYPE_UNKNOWN;
}
bool isObjectUnchecked() const {
return data > JSVAL_TYPE_UNKNOWN;
}
inline ObjectKey* objectKey() const;
/* Accessors for JSObject types */
bool isSingleton() const {
return isObject() && !!(data & 1);
}
bool isSingletonUnchecked() const {
return isObjectUnchecked() && !!(data & 1);
}
inline JSObject* singleton() const;
inline JSObject* singletonNoBarrier() const;
/* Accessors for ObjectGroup types */
bool isGroup() const {
return isObject() && !(data & 1);
}
bool isGroupUnchecked() const {
return isObjectUnchecked() && !(data & 1);
}
inline ObjectGroup* group() const;
inline ObjectGroup* groupNoBarrier() const;
inline void trace(JSTracer* trc);
JS::Compartment* maybeCompartment();
bool operator == (Type o) const { return data == o.data; }
bool operator != (Type o) const { return data != o.data; }
} JS_HAZ_GC_POINTER;
static inline Type UndefinedType() { return Type(JSVAL_TYPE_UNDEFINED); }
static inline Type NullType() { return Type(JSVAL_TYPE_NULL); }
static inline Type BooleanType() { return Type(JSVAL_TYPE_BOOLEAN); }
static inline Type Int32Type() { return Type(JSVAL_TYPE_INT32); }
static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
static inline Type SymbolType() { return Type(JSVAL_TYPE_SYMBOL); }
#ifdef ENABLE_BIGINT
static inline Type BigIntType() { return Type(JSVAL_TYPE_BIGINT); }
#endif
static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); }
static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }
static inline Type PrimitiveType(JSValueType type) {
MOZ_ASSERT(type < JSVAL_TYPE_UNKNOWN);
return Type(type);
}
static inline Type ObjectType(JSObject* obj);
static inline Type ObjectType(ObjectGroup* group);
static inline Type ObjectType(ObjectKey* key);
static const char* NonObjectTypeString(Type type);
static JS::UniqueChars TypeString(Type type);
static JS::UniqueChars ObjectGroupString(ObjectGroup* group);
public:
void print(FILE* fp = stderr);
/* Whether this set contains a specific type. */
MOZ_ALWAYS_INLINE bool hasType(Type type) const;
TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
bool unknownObject() const { return !!(flags & (TYPE_FLAG_UNKNOWN | TYPE_FLAG_ANYOBJECT)); }
bool empty() const { return !baseFlags() && !baseObjectCount(); }
bool hasAnyFlag(TypeFlags flags) const {
MOZ_ASSERT((flags & TYPE_FLAG_BASE_MASK) == flags);
return !!(baseFlags() & flags);
}
bool nonDataProperty() const {
return flags & TYPE_FLAG_NON_DATA_PROPERTY;
}
bool nonWritableProperty() const {
return flags & TYPE_FLAG_NON_WRITABLE_PROPERTY;
}
bool nonConstantProperty() const {
return flags & TYPE_FLAG_NON_CONSTANT_PROPERTY;
}
bool definiteProperty() const { return flags & TYPE_FLAG_DEFINITE_MASK; }
unsigned definiteSlot() const {
MOZ_ASSERT(definiteProperty());
return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1;
}
/* Join two type sets into a new set. The result should not be modified further. */
static TemporaryTypeSet* unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc);
/* Return the intersection of the 2 TypeSets. The result should not be modified further */
static TemporaryTypeSet* intersectSets(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
/*
* Returns a copy of TypeSet a excluding/removing the types in TypeSet b.
* TypeSet b can only contain primitives or be any object. No support for
* specific objects. The result should not be modified further.
*/
static TemporaryTypeSet* removeSet(TemporaryTypeSet* a, TemporaryTypeSet* b, LifoAlloc* alloc);
/* Add a type to this set using the specified allocator. */
void addType(Type type, LifoAlloc* alloc);
/* Get a list of all types in this set. */
using TypeList = Vector<Type, 1, SystemAllocPolicy>;
template <class TypeListT> bool enumerateTypes(TypeListT* list) const;
/*
* Iterate through the objects in this set. getObjectCount overapproximates
* in the hash case (see SET_ARRAY_SIZE in TypeInference-inl.h), and
* getObject may return nullptr.
*/
inline unsigned getObjectCount() const;
inline bool hasGroup(unsigned i) const;
inline bool hasSingleton(unsigned i) const;
inline ObjectKey* getObject(unsigned i) const;
inline JSObject* getSingleton(unsigned i) const;
inline ObjectGroup* getGroup(unsigned i) const;
/*
* Get the objects in the set without triggering barriers. This is
* potentially unsafe and you should only call these methods if you know
* what you're doing. For JIT compilation, use the following methods
* instead:
* - MacroAssembler::getSingletonAndDelayBarrier()
* - MacroAssembler::getGroupAndDelayBarrier()
*/
inline JSObject* getSingletonNoBarrier(unsigned i) const;
inline ObjectGroup* getGroupNoBarrier(unsigned i) const;
/* The Class of an object in this set. */
inline const Class* getObjectClass(unsigned i) const;
bool canSetDefinite(unsigned slot) {
// Note: the cast is required to work around an MSVC issue.
return (slot + 1) <= (unsigned(TYPE_FLAG_DEFINITE_MASK) >> TYPE_FLAG_DEFINITE_SHIFT);
}
void setDefinite(unsigned slot) {
MOZ_ASSERT(canSetDefinite(slot));
flags |= ((slot + 1) << TYPE_FLAG_DEFINITE_SHIFT);
MOZ_ASSERT(definiteSlot() == slot);
}
/* Whether any values in this set might have the specified type. */
bool mightBeMIRType(jit::MIRType type) const;
/*
* Get whether this type set is known to be a subset of other.
* This variant doesn't freeze constraints. That variant is called knownSubset
*/
bool isSubset(const TypeSet* other) const;
/*
* Get whether the objects in this TypeSet are a subset of the objects
* in other.
*/
bool objectsAreSubset(TypeSet* other);
/* Whether this TypeSet contains exactly the same types as other. */
bool equals(const TypeSet* other) const {
return this->isSubset(other) && other->isSubset(this);
}
bool objectsIntersect(const TypeSet* other) const;
/* Forward all types in this set to the specified constraint. */
bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint);
// Clone a type set into an arbitrary allocator.
TemporaryTypeSet* clone(LifoAlloc* alloc) const;
// |*result| is not even partly initialized when this function is called:
// this function placement-new's its contents into existence.
bool cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const;
// Create a new TemporaryTypeSet where undefined and/or null has been filtered out.
TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, bool filterNull) const;
// Create a new TemporaryTypeSet where the type has been set to object.
TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc);
TemporaryTypeSet* cloneWithoutObjects(LifoAlloc* alloc);
JS::Compartment* maybeCompartment();
// Trigger a read barrier on all the contents of a type set.
static void readBarrier(const TypeSet* types);
protected:
uint32_t baseObjectCount() const {
return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
}
inline void setBaseObjectCount(uint32_t count);
void clearObjects();
public:
static inline Type GetValueType(const JS::Value& val);
static inline bool IsUntrackedValue(const JS::Value& val);
// Get the type of a possibly optimized out or uninitialized let value.
// This generally only happens on unconditional type monitors on bailing
// out of Ion, such as for argument and local types.
static inline Type GetMaybeUntrackedValueType(const JS::Value& val);
static bool IsTypeMarked(JSRuntime* rt, Type* v);
static bool IsTypeAboutToBeFinalized(Type* v);
} JS_HAZ_GC_POINTER;
#if JS_BITS_PER_WORD == 32
static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4;
#else
static const uintptr_t BaseTypeInferenceMagic = 0xa1a2b3b4c5c6d7d8;
#endif
static const uintptr_t TypeConstraintMagic = BaseTypeInferenceMagic + 1;
static const uintptr_t ConstraintTypeSetMagic = BaseTypeInferenceMagic + 2;
#ifdef JS_CRASH_DIAGNOSTICS
extern void
ReportMagicWordFailure(uintptr_t actual, uintptr_t expected);
extern void
ReportMagicWordFailure(uintptr_t actual, uintptr_t expected, uintptr_t flags, uintptr_t objectSet);
#endif
/*
* A constraint which listens to additions to a type set and propagates those
* changes to other type sets.
*/
class TypeConstraint
{
private:
#ifdef JS_CRASH_DIAGNOSTICS
uintptr_t magic_ = TypeConstraintMagic;
#endif
/* Next constraint listening to the same type set. */
TypeConstraint* next_ = nullptr;
public:
TypeConstraint() = default;
void checkMagic() const {
#ifdef JS_CRASH_DIAGNOSTICS
if (MOZ_UNLIKELY(magic_ != TypeConstraintMagic)) {
ReportMagicWordFailure(magic_, TypeConstraintMagic);
}
#endif
}
TypeConstraint* next() const {
checkMagic();
if (next_) {
next_->checkMagic();
}
return next_;
}
void setNext(TypeConstraint* next) {
MOZ_ASSERT(!next_);
checkMagic();
if (next) {
next->checkMagic();
}
next_ = next;
}
/* Debugging name for this kind of constraint. */
virtual const char* kind() = 0;
/* Register a new type for the set this constraint is listening to. */
virtual void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) = 0;
/*
* For constraints attached to an object property's type set, mark the
* property as having changed somehow.
*/
virtual void newPropertyState(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.
*/
virtual void newObjectState(JSContext* cx, ObjectGroup* group) {}
/*
* If the data this constraint refers to is still live, copy it into the
* zone's new allocator. Type constraints only hold weak references.
*/
virtual bool sweep(TypeZone& zone, TypeConstraint** res) = 0;
/* The associated compartment, if any. */
virtual JS::Compartment* maybeCompartment() = 0;
};
/* Superclass common to stack and heap type sets. */
class ConstraintTypeSet : public TypeSet
{
private:
#ifdef JS_CRASH_DIAGNOSTICS
uintptr_t magic_ = ConstraintTypeSetMagic;
#endif
protected:
/* Chain of constraints which propagate changes out from this type set. */
TypeConstraint* constraintList_ = nullptr;
public:
ConstraintTypeSet() = default;
#ifdef JS_CRASH_DIAGNOSTICS
void initMagic() {
MOZ_ASSERT(!magic_);
magic_ = ConstraintTypeSetMagic;
}
#endif
void checkMagic() const {
#ifdef JS_CRASH_DIAGNOSTICS
if (MOZ_UNLIKELY(magic_ != ConstraintTypeSetMagic)) {
ReportMagicWordFailure(magic_, ConstraintTypeSetMagic, uintptr_t(flags), uintptr_t(objectSet));
}
#endif
}
// This takes a reference to AutoSweepBase to ensure we swept the owning
// ObjectGroup or TypeScript.
TypeConstraint* constraintList(const AutoSweepBase& sweep) const {
checkMagic();
if (constraintList_) {
constraintList_->checkMagic();
}
return constraintList_;
}
void setConstraintList(TypeConstraint* constraint) {
MOZ_ASSERT(!constraintList_);
checkMagic();
if (constraint) {
constraint->checkMagic();
}
constraintList_ = constraint;
}
/*
* Add a type to this set, calling any constraint handlers if this is a new
* possible type.
*/
void addType(const AutoSweepBase& sweep, JSContext* cx, Type type);
/* Generalize to any type. */
void makeUnknown(const AutoSweepBase& sweep, JSContext* cx) {
addType(sweep, cx, UnknownType());
}
// Trigger a post barrier when writing to this set, if necessary.
// addType(cx, type) takes care of this automatically.
void postWriteBarrier(JSContext* cx, Type type);
/* Add a new constraint to this set. */
bool addConstraint(JSContext* cx, TypeConstraint* constraint, bool callExisting = true);
inline void sweep(const AutoSweepBase& sweep, JS::Zone* zone,
AutoClearTypeInferenceStateOnOOM& oom);
inline void trace(JS::Zone* zone, JSTracer* trc);
};
class StackTypeSet : public ConstraintTypeSet
{
public:
};
class HeapTypeSet : public ConstraintTypeSet
{
inline void newPropertyState(const AutoSweepObjectGroup& sweep, JSContext* cx);
public:
/* Mark this type set as representing a non-data property. */
inline void setNonDataProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
/* Mark this type set as representing a non-writable property. */
inline void setNonWritableProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
// Mark this type set as being non-constant.
inline void setNonConstantProperty(const AutoSweepObjectGroup& sweep, JSContext* cx);
};
enum class DOMObjectKind : uint8_t { Proxy, Native, Unknown };
class TemporaryTypeSet : public TypeSet
{
public:
TemporaryTypeSet() {}
TemporaryTypeSet(LifoAlloc* alloc, Type type);
TemporaryTypeSet(uint32_t flags, ObjectKey** objectSet) {
this->flags = flags;
this->objectSet = objectSet;
}
TemporaryTypeSet(LifoAlloc* alloc, jit::MIRType type)
: TemporaryTypeSet(alloc, PrimitiveType(ValueTypeFromMIRType(type)))
{
MOZ_ASSERT(type != jit::MIRType::Value);
}
/*
* 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. */
jit::MIRType getKnownMIRType();
bool isMagicArguments() { return getKnownMIRType() == jit::MIRType::MagicOptimizedArguments; }
/* Whether this value may be an object. */
bool maybeObject() { return unknownObject() || 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.
*/
bool objectOrSentinel() {
TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT;
if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK)) {
return false;
}
return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0;
}
/* Whether the type set contains objects with any of a set of flags. */
bool hasObjectFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags);
/* Get the class shared by all objects in this set, or nullptr. */
const Class* getKnownClass(CompilerConstraintList* constraints);
/*
* Get the realm shared by all objects in this set, or nullptr. Returns
* nullptr if the set contains proxies (because cross-compartment wrappers
* don't have a single realm associated with them).
*/
JS::Realm* getKnownRealm(CompilerConstraintList* constraints);
/* Result returned from forAllClasses */
enum ForAllResult
{
EMPTY = 1, // Set empty
ALL_TRUE, // Set not empty and predicate returned true for all classes
ALL_FALSE, // Set not empty and predicate returned false for all classes
MIXED, // 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.
*/
ForAllResult forAllClasses(CompilerConstraintList* constraints,
bool (*func)(const Class* clasp));
/*
* Returns true if all objects in this set have the same prototype, and
* assigns this object to *proto. The proto can be nullptr.
*/
bool getCommonPrototype(CompilerConstraintList* constraints, JSObject** proto);
/* Whether the buffer mapped by a TypedArray is shared memory or not */
enum TypedArraySharedness
{
UnknownSharedness = 1, // We can't determine sharedness
KnownShared, // We know for sure the buffer is shared
KnownUnshared // We know for sure the buffer is unshared
};
/*
* Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType.
* If there is such a common type and sharedness is not nullptr then
* *sharedness is set to what we know about the sharedness of the memory.
*/
Scalar::Type getTypedArrayType(CompilerConstraintList* constraints,
TypedArraySharedness* sharedness = nullptr);
/* Whether all objects have JSCLASS_IS_DOMJSCLASS set. */
bool isDOMClass(CompilerConstraintList* constraints, DOMObjectKind* kind);
/* Whether clasp->isCallable() is true for one or more objects in this set. */
bool maybeCallable(CompilerConstraintList* constraints);
/* Whether clasp->emulatesUndefined() is true for one or more objects in this set. */
bool maybeEmulatesUndefined(CompilerConstraintList* constraints);
/* Get the single value which can appear in this type set, otherwise nullptr. */
JSObject* maybeSingleton();
ObjectKey* maybeSingleObject();
/* Whether any objects in the type set needs a barrier on id. */
bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id);
/*
* Whether this set contains all types in other, except (possibly) the
* specified type.
*/
bool filtersType(const TemporaryTypeSet* other, Type type) const;
enum DoubleConversion
{
/* 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.
*/
DoubleConversion convertDoubleElements(CompilerConstraintList* constraints);
private:
void getTypedArraySharedness(CompilerConstraintList* constraints,
TypedArraySharedness* sharedness);
};
// 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.
class HeapTypeSetKey
{
friend class TypeSet::ObjectKey;
// Object and property being accessed.
TypeSet::ObjectKey* object_;
jsid id_;
// If instantiated, the underlying heap type set.
HeapTypeSet* maybeTypes_;
public:
HeapTypeSetKey()
: object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr)
{}
TypeSet::ObjectKey* object() const { return object_; }
jsid id() const { return id_; }
HeapTypeSet* maybeTypes() const {
if (maybeTypes_) {
maybeTypes_->checkMagic();
}
return maybeTypes_;
}
bool instantiate(JSContext* cx);
void freeze(CompilerConstraintList* constraints);
jit::MIRType knownMIRType(CompilerConstraintList* constraints);
bool nonData(CompilerConstraintList* constraints);
bool nonWritable(CompilerConstraintList* constraints);
bool isOwnProperty(CompilerConstraintList* constraints, bool allowEmptyTypesForGlobal = false);
bool knownSubset(CompilerConstraintList* constraints, const HeapTypeSetKey& other);
JSObject* singleton(CompilerConstraintList* constraints);
bool needsBarrier(CompilerConstraintList* constraints);
bool constant(CompilerConstraintList* constraints, Value* valOut);
bool couldBeConstant(CompilerConstraintList* constraints);
};
} /* namespace js */
#endif /* vm_TypeSet_h */

Просмотреть файл

@ -9,8 +9,9 @@
#include "vm/UnboxedObject.h"
#include "vm/TypeInference.h"
#include "gc/StoreBuffer-inl.h"
#include "vm/ArrayObject-inl.h"
#include "vm/NativeObject-inl.h"
namespace js {

Просмотреть файл

@ -18,6 +18,7 @@
#include "jit/MacroAssembler-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/Shape-inl.h"
#include "vm/TypeInference-inl.h"
using mozilla::ArrayLength;
using mozilla::PodCopy;

Просмотреть файл

@ -13,6 +13,9 @@
namespace js {
struct AutoEnterAnalysis;
class PreliminaryObjectArray;
// Memory required for an unboxed value of a given type. Returns zero for types
// which can't be used for unboxed objects.
static inline size_t
@ -44,17 +47,16 @@ UnboxedTypeNeedsPostBarrier(JSValueType type)
class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
{
public:
struct Property {
PropertyName* name;
uint32_t offset;
JSValueType type;
struct Property
{
PropertyName* name = nullptr;
uint32_t offset = UINT32_MAX;
JSValueType type = JSVAL_TYPE_MAGIC;
Property()
: name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC)
{}
Property() = default;
};
typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
using PropertyVector = Vector<Property, 0, SystemAllocPolicy>;
private:
JS::Zone* zone_;
@ -62,19 +64,19 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
// If objects in this group have ever been converted to native objects,
// these store the corresponding native group and initial shape for such
// objects. Type information for this object is reflected in nativeGroup.
GCPtrObjectGroup nativeGroup_;
GCPtrShape nativeShape_;
GCPtrObjectGroup nativeGroup_ = {};
GCPtrShape nativeShape_ = {};
// Any script/pc which the associated group is created for.
GCPtrScript allocationScript_;
jsbytecode* allocationPc_;
GCPtrScript allocationScript_ = {};
jsbytecode* allocationPc_ = {};
// If nativeGroup is set and this object originally had a TypeNewScript or
// was keyed to an allocation site, this points to the group which replaced
// this one. This link is only needed to keep the replacement group from
// being GC'ed. If it were GC'ed and a new one regenerated later, that new
// group might have a different allocation kind from this group.
GCPtrObjectGroup replacementGroup_;
GCPtrObjectGroup replacementGroup_ = {};
// The following members are only used for unboxed plain objects.
@ -82,27 +84,27 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
PropertyVector properties_;
// Byte size of the data for objects with this layout.
size_t size_;
size_t size_ = 0;
// Any 'new' script information associated with this layout.
TypeNewScript* newScript_;
TypeNewScript* newScript_ = nullptr;
// List for use in tracing objects with this layout. This has the same
// structure as the trace list on a TypeDescr.
int32_t* traceList_;
int32_t* traceList_ = nullptr;
// If this layout has been used to construct script or JSON constant
// objects, this code might be filled in to more quickly fill in objects
// from an array of values.
GCPtrJitCode constructorCode_;
GCPtrJitCode constructorCode_ = {};
public:
explicit UnboxedLayout(JS::Zone* zone)
: zone_(zone), nativeGroup_(nullptr), nativeShape_(nullptr),
allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr),
size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr)
: zone_(zone)
{}
inline ~UnboxedLayout();
JS::Zone* zone() const { return zone_; }
bool initProperties(const PropertyVector& properties, size_t size) {
@ -110,19 +112,6 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
return properties_.appendAll(properties);
}
~UnboxedLayout() {
if (newScript_) {
newScript_->clear();
}
js_delete(newScript_);
js_free(traceList_);
nativeGroup_.init(nullptr);
nativeShape_.init(nullptr);
replacementGroup_.init(nullptr);
constructorCode_.init(nullptr);
}
void detachFromRealm();
const PropertyVector& properties() const {