author | Jeff Walden <jwalden@mit.edu> |
Sat, 15 Sep 2018 20:24:30 -0700 | |
changeset 436739 | 60df00079cd46d23309f0637633f62908ba17d45 |
parent 436738 | efcfd2f95057ea622a735a015a9cd3f547281fc1 |
child 436740 | 740b790557b9b70298dee6093753c4d2552001cc |
push id | 34658 |
push user | rgurzau@mozilla.com |
push date | Mon, 17 Sep 2018 16:46:41 +0000 |
treeherder | mozilla-central@5ecae696c54f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jandem |
bugs | 1491736 |
milestone | 64.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/builtin/AtomicsObject.h +++ b/js/src/builtin/AtomicsObject.h @@ -6,16 +6,17 @@ #ifndef builtin_AtomicsObject_h #define builtin_AtomicsObject_h #include "mozilla/Maybe.h" #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" namespace js { class GlobalObject; class SharedArrayRawBuffer;
--- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -9,16 +9,17 @@ #include "mozilla/Atomics.h" #include "mozilla/HashFunctions.h" #include "gc/FindSCCs.h" #include "js/GCHashTable.h" #include "vm/MallocProvider.h" #include "vm/Runtime.h" +#include "vm/TypeInference.h" namespace js { class Debugger; class RegExpZone; namespace jit { class JitZone;
--- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -13,16 +13,17 @@ #include "jit/BaselineIC.h" #include "jit/CacheIRSpewer.h" #include "vm/SelfHosting.h" #include "jit/MacroAssembler-inl.h" #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; using namespace js::jit; using mozilla::DebugOnly; using mozilla::Maybe;
--- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -17,16 +17,17 @@ #include "jit/MIRGraph.h" #include "vm/RegExpObject.h" #include "vm/SelfHosting.h" #include "jit/shared/Lowering-shared-inl.h" #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; using mozilla::DebugOnly; typedef Vector<MPhi*, 16, SystemAllocPolicy> MPhiVector; @@ -4362,17 +4363,17 @@ jit::ConvertLinearInequality(TempAllocat return compare; } 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) { // Determine the effect that a use of the |this| value when calling |new| // on a script has on the properties definitely held by the new object. if (ins->isCallSetProperty()) { MCallSetProperty* setprop = ins->toCallSetProperty(); @@ -4431,26 +4432,26 @@ AnalyzePoppedThis(JSContext* cx, ObjectG if (!callerResumePoints.append(rp)) { return false; } } 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; } *phandled = true; return true; } @@ -4496,17 +4497,17 @@ CmpInstructions(const void* a, const voi { return (*static_cast<MInstruction * const*>(a))->id() - (*static_cast<MInstruction * const*>(b))->id(); } bool jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun, ObjectGroup* group, HandlePlainObject baseobj, - Vector<TypeNewScript::Initializer>* initializerList) + Vector<TypeNewScriptInitializer>* initializerList) { MOZ_ASSERT(cx->zone()->types.activeAnalysis); // When invoking 'new' on the specified script, try to find some properties // which will definitely be added to the created object before it has a // chance to escape and be accessed elsewhere. RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
--- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -198,17 +198,17 @@ ConvertLinearSum(TempAllocator& alloc, M // Convert the test 'sum >= 0' to a comparison, adding any necessary // instructions to the end of block. MCompare* ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum); 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); bool DeadIfUnused(const MDefinition* def); bool
--- a/js/src/vm/ArrayObject-inl.h +++ b/js/src/vm/ArrayObject-inl.h @@ -8,16 +8,17 @@ #define vm_ArrayObject_inl_h #include "vm/ArrayObject.h" #include "gc/GCTrace.h" #include "vm/StringType.h" #include "vm/JSObject-inl.h" +#include "vm/ObjectGroup-inl.h" #include "vm/TypeInference-inl.h" namespace js { inline void ArrayObject::setLength(JSContext* cx, uint32_t length) { MOZ_ASSERT(lengthIsWritable());
--- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -64,20 +64,22 @@ #include "vm/Caches-inl.h" #include "vm/Compartment-inl.h" #include "vm/Interpreter-inl.h" #include "vm/JSAtom-inl.h" #include "vm/JSContext-inl.h" #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; void js::ReportNotObject(JSContext* cx, HandleValue v) { MOZ_ASSERT(!v.isObject());
--- a/js/src/vm/JSScript.h +++ b/js/src/vm/JSScript.h @@ -44,23 +44,26 @@ namespace jit { } // namespace jit # define ION_DISABLED_SCRIPT ((js::jit::IonScript*)0x1) # define ION_COMPILING_SCRIPT ((js::jit::IonScript*)0x2) # define ION_PENDING_SCRIPT ((js::jit::IonScript*)0x3) # define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript*)0x1) +class AutoKeepTypeScripts; +class AutoSweepTypeScript; class BreakpointSite; class Debugger; class LazyScript; class ModuleObject; class RegExpObject; class SourceCompressionTask; class Shape; +class TypeScript; namespace frontend { struct BytecodeEmitter; class FunctionBox; class ModuleSharedContext; } // namespace frontend namespace detail {
--- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -18,16 +18,17 @@ #include "vm/TypedArrayObject.h" #include "vm/UnboxedObject.h" #include "gc/Nursery-inl.h" #include "vm/ArrayObject-inl.h" #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; using JS::AutoCheckCannotGC; using mozilla::ArrayLength; using mozilla::CheckedInt; using mozilla::DebugOnly;
--- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -20,16 +20,17 @@ #include "js/UniquePtr.h" #include "vm/ArrayObject.h" #include "vm/JSObject.h" #include "vm/RegExpObject.h" #include "vm/Shape.h" #include "vm/TaggedProto.h" #include "gc/Marking-inl.h" +#include "vm/TypeInference-inl.h" #include "vm/UnboxedObject-inl.h" using namespace js; ///////////////////////////////////////////////////////////////////// // ObjectGroup /////////////////////////////////////////////////////////////////////
--- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -11,26 +11,25 @@ #include "ds/IdValuePair.h" #include "gc/Barrier.h" #include "gc/GCTrace.h" #include "js/CharacterEncoding.h" #include "js/GCHashTable.h" #include "js/TypeDecls.h" #include "vm/TaggedProto.h" -#include "vm/TypeInference.h" +#include "vm/TypeSet.h" namespace js { class TypeDescr; class UnboxedLayout; class PreliminaryObjectArrayWithTemplate; class TypeNewScript; -class HeapTypeSet; class AutoClearTypeInferenceStateOnOOM; class AutoSweepObjectGroup; class CompilerConstraintList; class ObjectGroupRealm; namespace gc { void MergeRealms(JS::Realm* source, JS::Realm* target); } // namespace gc @@ -321,20 +320,17 @@ class ObjectGroup : public gc::TenuredCe setAddendum(Addendum_PreliminaryObjects, preliminaryObjects); } void detachPreliminaryObjects() { MOZ_ASSERT(maybePreliminaryObjectsDontCheckGeneration()); 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); UnboxedLayout* maybeUnboxedLayoutDontCheckGeneration() const { if (addendumKind() == Addendum_UnboxedLayout) { return &unboxedLayoutDontCheckGeneration(); }
--- a/js/src/vm/TypeInference-inl.h +++ b/js/src/vm/TypeInference-inl.h @@ -13,19 +13,24 @@ #include "mozilla/BinarySearch.h" #include "mozilla/Casting.h" #include "mozilla/PodOperations.h" #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" #include "vm/UnboxedObject.h" #include "vm/JSContext-inl.h" #include "vm/ObjectGroup-inl.h" @@ -263,16 +268,171 @@ TypeIdString(jsid id) { #ifdef DEBUG return TypeIdStringImpl(id); #else return "(missing)"; #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 * intermediate types (i.e. JITs) can use this to ensure that intermediate * information is not collected and does not change. * * Ensures that GC cannot occur. Does additional sanity checking that inference * is not reentrant and that recompilations occur properly.
--- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -4060,21 +4060,24 @@ TypeNewScript::makeNativeVersion(JSConte auto nativeNewScript = cx->make_unique<TypeNewScript>(); if (!nativeNewScript) { return nullptr; } 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; } PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength); return nativeNewScript.release(); } @@ -4227,17 +4230,17 @@ TypeNewScript::maybeAnalyze(JSContext* c } RootedObjectGroup groupRoot(cx, group); templateObject_ = NewObjectWithGroup<PlainObject>(cx, groupRoot, kind, TenuredObject); if (!templateObject_) { return false; } - Vector<Initializer> initializerVector(cx); + Vector<TypeNewScriptInitializer> initializerVector(cx); RootedPlainObject templateRoot(cx, templateObject()); RootedFunction fun(cx, function()); if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector)) { return false; } if (!group->newScript(sweep)) { @@ -4272,23 +4275,24 @@ TypeNewScript::maybeAnalyze(JSContext* c shape = shape->previous(); templateShape = templateShape->previous(); } if (!templateShape->isEmptyShape()) { return true; } } - 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; } PodCopy(initializerList, initializerVector.begin(), initializerVector.length()); } // Try to use an unboxed representation for the group. @@ -4439,44 +4443,44 @@ TypeNewScript::rollbackPartiallyInitiali bool pastProperty = false; // Index in pcOffsets of the outermost frame. int callDepth = pcOffsets.length() - 1; // 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; } // This setprop has executed, reset state for the next one. 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. break; } else if (pcOffsets[setpropDepth] > init->offset) { // Have advanced past this inner call. pastProperty = true; } else if (setpropDepth == 0) { // Have reached this call but not yet in it. break; } else { // Somewhere inside this inner call. setpropDepth--; } } } else { - MOZ_ASSERT(init->kind == Initializer::DONE); + MOZ_ASSERT(init->kind == TypeNewScriptInitializer::DONE); finished = true; break; } } if (!finished) { (void) NativeObject::rollbackProperties(cx, obj, numProperties); found = true;
--- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -4,663 +4,47 @@ * 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 vm_TypeInference_h #define vm_TypeInference_h +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "jsfriendapi.h" #include "jstypes.h" -#include "ds/IdValuePair.h" #include "ds/LifoAlloc.h" #include "gc/Barrier.h" #include "jit/IonTypes.h" #include "js/AllocPolicy.h" +#include "js/HeapAPI.h" // js::CurrentThreadCanAccessZone #include "js/UbiNode.h" #include "js/Utility.h" #include "js/Vector.h" -#include "threading/ProtectedData.h" -#include "vm/TaggedProto.h" +#include "threading/ProtectedData.h" // js::ZoneData +#include "vm/TypeSet.h" namespace js { -namespace jit { - struct IonScript; - class JitAllocPolicy; - class TempAllocator; -} // namespace jit - class TypeConstraint; -class TypeNewScript; class TypeZone; class CompilerConstraintList; class HeapTypeSetKey; -/* - * 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 -}; -typedef uint32_t TypeFlags; - -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, -}; -typedef uint32_t ObjectGroupFlags; - -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 -{ - public: - // 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 */ +namespace jit { - 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 UniqueChars TypeString(Type type); - static UniqueChars ObjectGroupString(ObjectGroup* group); - - protected: - /* Flags for this type set. */ - TypeFlags flags; - - /* Possible objects this type set can represent. */ - ObjectKey** objectSet; - - public: - - TypeSet() - : flags(0), objectSet(nullptr) - {} - - 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. */ - typedef Vector<Type, 1, SystemAllocPolicy> TypeList; - 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); - } +struct IonScript; +class TempAllocator; - /* 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 Value& val); - - static inline bool IsUntrackedValue(const 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 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 -{ -#ifdef JS_CRASH_DIAGNOSTICS - uintptr_t magic_; -#endif - - /* Next constraint listening to the same type set. */ - TypeConstraint* next_; - - public: - TypeConstraint() - : next_(nullptr) - { -#ifdef JS_CRASH_DIAGNOSTICS - magic_ = TypeConstraintMagic; -#endif - } - - 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; -}; +} // namespace jit // If there is an OOM while sweeping types, the type information is deoptimized // so that it stays correct (i.e. overapproximates the possible types in the // zone), but constraints might not have been triggered on the deoptimization // or even copied over completely. In this case, destroy all JIT code and new // script information in the zone, the only things whose correctness depends on // the type constraints. class AutoClearTypeInferenceStateOnOOM @@ -725,261 +109,19 @@ class MOZ_RAII AutoSweepTypeScript : pub inline ~AutoSweepTypeScript(); JSScript* script() const { return script_; } #endif }; -/* Superclass common to stack and heap type sets. */ -class ConstraintTypeSet : public TypeSet -{ -#ifdef JS_CRASH_DIAGNOSTICS - uintptr_t magic_; -#endif - - protected: - /* Chain of constraints which propagate changes out from this type set. */ - TypeConstraint* constraintList_; - - public: - ConstraintTypeSet() - : constraintList_(nullptr) - { -#ifdef JS_CRASH_DIAGNOSTICS - magic_ = ConstraintTypeSetMagic; -#endif - } - -#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); -}; - CompilerConstraintList* NewCompilerConstraintList(jit::TempAllocator& alloc); -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). - */ - 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); -}; - bool AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id); bool AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group, JSScript* script, JSScript* calleeScript); // For groups where only a small number of objects have been allocated, this @@ -1032,159 +174,33 @@ class PreliminaryObjectArrayWithTemplate void maybeAnalyze(JSContext* cx, ObjectGroup* group, bool force = false); void trace(JSTracer* trc); static void writeBarrierPre(PreliminaryObjectArrayWithTemplate* preliminaryObjects); }; -// 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 +/** + * A type representing the initializer of a property within a script being 'new'd. + */ +class TypeNewScriptInitializer { public: - struct Initializer { - enum Kind { - SETPROP, - SETPROP_FRAME, - DONE - } kind; - uint32_t offset; - Initializer(Kind kind, uint32_t offset) - : kind(kind), offset(offset) - {} - }; - - 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. - Initializer* 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_ = {}; + enum Kind + { + SETPROP, + SETPROP_FRAME, + DONE + } kind; + uint32_t offset; - 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); - } + TypeNewScriptInitializer(Kind kind, uint32_t offset) + : kind(kind), offset(offset) + {} }; /* Is this a reasonable PC to be doing inlining on? */ inline bool isInlinableCall(jsbytecode* pc); bool ClassCanHaveExtraProperties(const Class* clasp); @@ -1343,64 +359,16 @@ bool FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints, IonCompilationId compilationId, bool* isValidOut); // Update the actual types in any scripts queried by constraints with any // speculative types added during the definite properties analysis. void FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints); -// 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); -}; - struct AutoEnterAnalysis; class TypeZone { JS::Zone* const zone_; /* Pool for type information in this zone. */ static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024;
copy from js/src/vm/TypeInference.h copy to js/src/vm/TypeSet.h --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeSet.h @@ -1,63 +1,87 @@ /* -*- 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. */ +/* TypeSet classes and functions. */ -#ifndef vm_TypeInference_h -#define vm_TypeInference_h +#ifndef vm_TypeSet_h +#define vm_TypeSet_h -#include "mozilla/MemoryReporting.h" +#include "mozilla/Assertions.h" // MOZ_ASSERT +#include "mozilla/Attributes.h" // MOZ_ALWAYS_INLINE +#include "mozilla/Likely.h" // MOZ_UNLIKELY -#include "jsfriendapi.h" -#include "jstypes.h" +#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 "ds/IdValuePair.h" -#include "ds/LifoAlloc.h" -#include "gc/Barrier.h" -#include "jit/IonTypes.h" -#include "js/AllocPolicy.h" -#include "js/UbiNode.h" -#include "js/Utility.h" -#include "js/Vector.h" -#include "threading/ProtectedData.h" -#include "vm/TaggedProto.h" +#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 JitAllocPolicy; - class TempAllocator; + +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; -class CompilerConstraintList; -class HeapTypeSetKey; /* * 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 { +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 @@ -115,24 +139,25 @@ enum : uint32_t { * 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 }; -typedef uint32_t TypeFlags; +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 { +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 @@ -201,17 +226,17 @@ enum : uint32_t { 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, }; -typedef uint32_t ObjectGroupFlags; +using ObjectGroupFlags = uint32_t; class StackTypeSet; class HeapTypeSet; class TemporaryTypeSet; /* * [SMDOC] Type-Inference TypeSet * @@ -242,20 +267,34 @@ class TemporaryTypeSet; * - 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 { + 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() { @@ -397,32 +436,20 @@ class TypeSet } 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 UniqueChars TypeString(Type type); - static UniqueChars ObjectGroupString(ObjectGroup* group); - - protected: - /* Flags for this type set. */ - TypeFlags flags; - - /* Possible objects this type set can represent. */ - ObjectKey** objectSet; + static JS::UniqueChars TypeString(Type type); + static JS::UniqueChars ObjectGroupString(ObjectGroup* group); public: - - TypeSet() - : flags(0), objectSet(nullptr) - {} - 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)); } @@ -458,17 +485,17 @@ class TypeSet * 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. */ - typedef Vector<Type, 1, SystemAllocPolicy> TypeList; + 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; @@ -549,24 +576,24 @@ class TypeSet 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 Value& val); + static inline Type GetValueType(const JS::Value& val); - static inline bool IsUntrackedValue(const 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 Value& val); + 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 @@ -583,31 +610,26 @@ ReportMagicWordFailure(uintptr_t actual, #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_; + uintptr_t magic_ = TypeConstraintMagic; #endif /* Next constraint listening to the same type set. */ - TypeConstraint* next_; + TypeConstraint* next_ = nullptr; public: - TypeConstraint() - : next_(nullptr) - { -#ifdef JS_CRASH_DIAGNOSTICS - magic_ = TypeConstraintMagic; -#endif - } + TypeConstraint() = default; void checkMagic() const { #ifdef JS_CRASH_DIAGNOSTICS if (MOZ_UNLIKELY(magic_ != TypeConstraintMagic)) { ReportMagicWordFailure(magic_, TypeConstraintMagic); } #endif } @@ -652,108 +674,30 @@ class TypeConstraint * 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; }; -// If there is an OOM while sweeping types, the type information is deoptimized -// so that it stays correct (i.e. overapproximates the possible types in the -// zone), but constraints might not have been triggered on the deoptimization -// or even copied over completely. In this case, destroy all JIT code and new -// script information in the zone, the only things whose correctness depends on -// the type constraints. -class AutoClearTypeInferenceStateOnOOM -{ - Zone* zone; - bool oom; - - AutoClearTypeInferenceStateOnOOM(const AutoClearTypeInferenceStateOnOOM&) = delete; - void operator=(const AutoClearTypeInferenceStateOnOOM&) = delete; - - public: - explicit AutoClearTypeInferenceStateOnOOM(Zone* zone); - ~AutoClearTypeInferenceStateOnOOM(); - - void setOOM() { - oom = true; - } - bool hadOOM() const { - return oom; - } -}; - -class MOZ_RAII AutoSweepBase -{ - // Make sure we don't GC while this class is live since GC might trigger - // (incremental) sweeping. - JS::AutoCheckCannotGC nogc; -}; - -// Sweep an ObjectGroup. Functions that expect a swept group should take a -// reference to this class. -class MOZ_RAII AutoSweepObjectGroup : public AutoSweepBase -{ -#ifdef DEBUG - ObjectGroup* group_; -#endif - - public: - inline explicit AutoSweepObjectGroup(ObjectGroup* group); - inline AutoSweepObjectGroup(ObjectGroup* group, AutoClearTypeInferenceStateOnOOM& oom); -#ifdef DEBUG - inline ~AutoSweepObjectGroup(); - - ObjectGroup* group() const { - return group_; - } -#endif -}; - -// Sweep a TypeScript. Functions that expect a swept script should take a -// reference to this class. -class MOZ_RAII AutoSweepTypeScript : public AutoSweepBase -{ -#ifdef DEBUG - JSScript* script_; -#endif - - public: - inline explicit AutoSweepTypeScript(JSScript* script); - inline AutoSweepTypeScript(JSScript* script, AutoClearTypeInferenceStateOnOOM& oom); -#ifdef DEBUG - inline ~AutoSweepTypeScript(); - - JSScript* script() const { - return script_; - } -#endif -}; - /* Superclass common to stack and heap type sets. */ class ConstraintTypeSet : public TypeSet { + private: #ifdef JS_CRASH_DIAGNOSTICS - uintptr_t magic_; + uintptr_t magic_ = ConstraintTypeSetMagic; #endif protected: /* Chain of constraints which propagate changes out from this type set. */ - TypeConstraint* constraintList_; + TypeConstraint* constraintList_ = nullptr; public: - ConstraintTypeSet() - : constraintList_(nullptr) - { -#ifdef JS_CRASH_DIAGNOSTICS - magic_ = ConstraintTypeSetMagic; -#endif - } + ConstraintTypeSet() = default; #ifdef JS_CRASH_DIAGNOSTICS void initMagic() { MOZ_ASSERT(!magic_); magic_ = ConstraintTypeSetMagic; } #endif @@ -821,19 +765,16 @@ class HeapTypeSet : public ConstraintTyp /* 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); }; -CompilerConstraintList* -NewCompilerConstraintList(jit::TempAllocator& alloc); - enum class DOMObjectKind : uint8_t { Proxy, Native, Unknown }; class TemporaryTypeSet : public TypeSet { public: TemporaryTypeSet() {} TemporaryTypeSet(LifoAlloc* alloc, Type type); @@ -885,21 +826,22 @@ class TemporaryTypeSet : public TypeSet /* 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). */ - Realm* getKnownRealm(CompilerConstraintList* constraints); + JS::Realm* getKnownRealm(CompilerConstraintList* constraints); /* Result returned from forAllClasses */ - enum ForAllResult { - EMPTY=1, // Set empty + 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. @@ -910,23 +852,25 @@ class TemporaryTypeSet : public TypeSet /* * 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 + 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. + /* + * 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); @@ -945,17 +889,18 @@ class TemporaryTypeSet : public TypeSet 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 { + 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, @@ -970,389 +915,16 @@ class TemporaryTypeSet : public TypeSet */ DoubleConversion convertDoubleElements(CompilerConstraintList* constraints); private: void getTypedArraySharedness(CompilerConstraintList* constraints, TypedArraySharedness* sharedness); }; -bool -AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id); - -bool -AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group, - JSScript* script, JSScript* calleeScript); - -// For groups where only a small number of objects have been allocated, this -// structure keeps track of all objects in the group. Once COUNT objects have -// been allocated, this structure is cleared and the objects are analyzed, to -// perform the new script properties analyses or determine if an unboxed -// representation can be used. -class PreliminaryObjectArray -{ - public: - static const uint32_t COUNT = 20; - - private: - // All objects with the type which have been allocated. The pointers in - // this array are weak. - JSObject* objects[COUNT] = {}; // zeroes - - public: - PreliminaryObjectArray() = default; - - void registerNewObject(PlainObject* res); - void unregisterObject(PlainObject* obj); - - JSObject* get(size_t i) const { - MOZ_ASSERT(i < COUNT); - return objects[i]; - } - - bool full() const; - bool empty() const; - void sweep(); -}; - -class PreliminaryObjectArrayWithTemplate : public PreliminaryObjectArray -{ - HeapPtr<Shape*> shape_; - - public: - explicit PreliminaryObjectArrayWithTemplate(Shape* shape) - : shape_(shape) - {} - - void clear() { - shape_.init(nullptr); - } - - Shape* shape() { - return shape_; - } - - void maybeAnalyze(JSContext* cx, ObjectGroup* group, bool force = false); - - void trace(JSTracer* trc); - - static void writeBarrierPre(PreliminaryObjectArrayWithTemplate* preliminaryObjects); -}; - -// 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 -{ - public: - struct Initializer { - enum Kind { - SETPROP, - SETPROP_FRAME, - DONE - } kind; - uint32_t offset; - Initializer(Kind kind, uint32_t offset) - : kind(kind), offset(offset) - {} - }; - - 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. - Initializer* 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); - } -}; - -/* Is this a reasonable PC to be doing inlining on? */ -inline bool isInlinableCall(jsbytecode* pc); - -bool -ClassCanHaveExtraProperties(const Class* clasp); - -class RecompileInfo -{ - JSScript* script_; - IonCompilationId id_; - - public: - RecompileInfo(JSScript* script, IonCompilationId id) - : script_(script), - id_(id) - {} - - JSScript* script() const { - return script_; - } - - inline jit::IonScript* maybeIonScriptToInvalidate(const TypeZone& zone) const; - - inline bool shouldSweep(const TypeZone& zone); - - bool operator==(const RecompileInfo& other) const { - return script_== other.script_ && id_ == other.id_; - } -}; - -// The RecompileInfoVector has a MinInlineCapacity of one so that invalidating a -// single IonScript doesn't require an allocation. -typedef Vector<RecompileInfo, 1, SystemAllocPolicy> RecompileInfoVector; - -/* Persistent type information for a script, retained across GCs. */ -class TypeScript -{ - friend class ::JSScript; - - // The freeze constraints added to stack type sets will only directly - // invalidate the script containing those stack type sets. This Vector - // contains compilations that inlined this script, so we can invalidate - // them as well. - RecompileInfoVector inlinedCompilations_; - - // Variable-size array - StackTypeSet typeArray_[1]; - - public: - RecompileInfoVector& inlinedCompilations() { - return inlinedCompilations_; - } - MOZ_MUST_USE bool addInlinedCompilation(RecompileInfo info) { - if (!inlinedCompilations_.empty() && inlinedCompilations_.back() == info) { - return true; - } - return inlinedCompilations_.append(info); - } - - /* Array of type sets for variables and JOF_TYPESET ops. */ - StackTypeSet* typeArray() const { - // Ensure typeArray_ is the last data member of TypeScript. - JS_STATIC_ASSERT(sizeof(TypeScript) == - sizeof(typeArray_) + offsetof(TypeScript, typeArray_)); - return const_cast<StackTypeSet*>(typeArray_); - } - - static inline size_t SizeIncludingTypeArray(size_t arraySize) { - // Ensure typeArray_ is the last data member of TypeScript. - JS_STATIC_ASSERT(sizeof(TypeScript) == - sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_)); - return offsetof(TypeScript, typeArray_) + arraySize * sizeof(StackTypeSet); - } - - static inline unsigned NumTypeSets(JSScript* script); - - static inline StackTypeSet* ThisTypes(JSScript* script); - static inline StackTypeSet* ArgTypes(JSScript* script, unsigned i); - - /* Get the type set for values observed at an opcode. */ - static inline StackTypeSet* BytecodeTypes(JSScript* script, jsbytecode* pc); - - template <typename TYPESET> - static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc, uint32_t* bytecodeMap, - uint32_t* hint, TYPESET* typeArray); - - /* - * 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. - */ - static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc, - const js::Value& val); - static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc, - TypeSet::Type type); - static inline void Monitor(JSContext* cx, const js::Value& rval); - - static inline void Monitor(JSContext* cx, JSScript* script, jsbytecode* pc, - StackTypeSet* types, const js::Value& val); - - /* Monitor an assignment at a SETELEM on a non-integer identifier. */ - static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id); - - /* Add a type for a variable in a script. */ - static inline void SetThis(JSContext* cx, JSScript* script, TypeSet::Type type); - static inline void SetThis(JSContext* cx, JSScript* script, const js::Value& value); - static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg, - TypeSet::Type type); - static inline void SetArgument(JSContext* cx, JSScript* script, unsigned arg, - const js::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. - */ - static bool FreezeTypeSets(CompilerConstraintList* constraints, JSScript* script, - TemporaryTypeSet** pThisTypes, - TemporaryTypeSet** pArgTypes, - TemporaryTypeSet** pBytecodeTypes); - - static void Purge(JSContext* cx, HandleScript script); - - void destroy(); - - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this); - } - -#ifdef DEBUG - void printTypes(JSContext* cx, HandleScript script) const; -#endif -}; - -// Ensures no TypeScripts are purged in the current zone. -class MOZ_RAII AutoKeepTypeScripts -{ - TypeZone& zone_; - bool prev_; - - AutoKeepTypeScripts(const AutoKeepTypeScripts&) = delete; - void operator=(const AutoKeepTypeScripts&) = delete; - - public: - explicit inline AutoKeepTypeScripts(JSContext* cx); - inline ~AutoKeepTypeScripts(); -}; - -void -FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap); - -class RecompileInfo; - -// Generate the type constraints for the compilation. Sets |isValidOut| based on -// whether the type constraints still hold. -bool -FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints, - IonCompilationId compilationId, bool* isValidOut); - -// Update the actual types in any scripts queried by constraints with any -// speculative types added during the definite properties analysis. -void -FinishDefinitePropertiesAnalysis(JSContext* cx, CompilerConstraintList* constraints); - // 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. @@ -1391,136 +963,11 @@ class HeapTypeSetKey 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); }; -struct AutoEnterAnalysis; - -class TypeZone -{ - JS::Zone* const zone_; - - /* Pool for type information in this zone. */ - static const size_t TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 8 * 1024; - ZoneData<LifoAlloc> typeLifoAlloc_; - - // Under CodeGenerator::link, the id of the current compilation. - ZoneData<mozilla::Maybe<IonCompilationId>> currentCompilationId_; - - TypeZone(const TypeZone&) = delete; - void operator=(const TypeZone&) = delete; - - public: - // Current generation for sweeping. - ZoneOrGCTaskOrIonCompileData<uint32_t> generation; - - // During incremental sweeping, allocator holding the old type information - // for the zone. - ZoneData<LifoAlloc> sweepTypeLifoAlloc; - - // During incremental sweeping, whether to try to destroy all type - // information attached to scripts. - ZoneData<bool> sweepReleaseTypes; - - ZoneData<bool> sweepingTypes; - - ZoneData<bool> keepTypeScripts; - - // The topmost AutoEnterAnalysis on the stack, if there is one. - ZoneData<AutoEnterAnalysis*> activeAnalysis; - - explicit TypeZone(JS::Zone* zone); - ~TypeZone(); - - JS::Zone* zone() const { return zone_; } - - LifoAlloc& typeLifoAlloc() { -#ifdef JS_CRASH_DIAGNOSTICS - MOZ_RELEASE_ASSERT(CurrentThreadCanAccessZone(zone_)); -#endif - return typeLifoAlloc_.ref(); - } - - void beginSweep(bool releaseTypes); - void endSweep(JSRuntime* rt); - void clearAllNewScriptsOnOOM(AutoClearTypeInferenceStateOnOOM& oom); - - /* Mark a script as needing recompilation once inference has finished. */ - void addPendingRecompile(JSContext* cx, const RecompileInfo& info); - void addPendingRecompile(JSContext* cx, JSScript* script); - - void processPendingRecompiles(FreeOp* fop, RecompileInfoVector& recompiles); - - void setSweepingTypes(bool sweeping) { - MOZ_RELEASE_ASSERT(sweepingTypes != sweeping); - sweepingTypes = sweeping; - } - - mozilla::Maybe<IonCompilationId> currentCompilationId() const { - return currentCompilationId_.ref(); - } - mozilla::Maybe<IonCompilationId>& currentCompilationIdRef() { - return currentCompilationId_.ref(); - } -}; - -enum SpewChannel { - ISpewOps, /* ops: New constraints and types. */ - ISpewResult, /* result: Final type sets. */ - SPEW_COUNT -}; - -#ifdef DEBUG - -bool InferSpewActive(SpewChannel channel); -const char * InferSpewColorReset(); -const char * InferSpewColor(TypeConstraint* constraint); -const char * InferSpewColor(TypeSet* types); - -#define InferSpew(channel, ...) if (InferSpewActive(channel)) { InferSpewImpl(__VA_ARGS__); } else {} -void InferSpewImpl(const char* fmt, ...) MOZ_FORMAT_PRINTF(1, 2); - -/* Check that the type property for id in group contains value. */ -bool ObjectGroupHasProperty(JSContext* cx, ObjectGroup* group, jsid id, const Value& value); - -#else - -inline const char * InferSpewColorReset() { return nullptr; } -inline const char * InferSpewColor(TypeConstraint* constraint) { return nullptr; } -inline const char * InferSpewColor(TypeSet* types) { return nullptr; } - -#define InferSpew(channel, ...) do {} while (0) - -#endif - -// Prints type information for a context if spew is enabled or force is set. -void -PrintTypes(JSContext* cx, JS::Compartment* comp, bool force); - } /* namespace js */ -// JS::ubi::Nodes can point to object groups; they're js::gc::Cell instances -// with no associated compartment. -namespace JS { -namespace ubi { - -template<> -class Concrete<js::ObjectGroup> : TracerConcrete<js::ObjectGroup> { - protected: - explicit Concrete(js::ObjectGroup *ptr) : TracerConcrete<js::ObjectGroup>(ptr) { } - - public: - static void construct(void *storage, js::ObjectGroup *ptr) { new (storage) Concrete(ptr); } - - Size size(mozilla::MallocSizeOf mallocSizeOf) const override; - - const char16_t* typeName() const override { return concreteTypeName; } - static const char16_t concreteTypeName[]; -}; - -} // namespace ubi -} // namespace JS - -#endif /* vm_TypeInference_h */ +#endif /* vm_TypeSet_h */
--- a/js/src/vm/UnboxedObject-inl.h +++ b/js/src/vm/UnboxedObject-inl.h @@ -4,18 +4,19 @@ * 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/. */ #ifndef vm_UnboxedObject_inl_h #define vm_UnboxedObject_inl_h #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 { ///////////////////////////////////////////////////////////////////// // UnboxedPlainObject /////////////////////////////////////////////////////////////////////
--- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -13,16 +13,17 @@ #include "jit/ExecutableAllocator.h" #include "jit/JitCommon.h" #include "jit/Linker.h" #include "gc/Nursery-inl.h" #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; using namespace js; ///////////////////////////////////////////////////////////////////// // UnboxedLayout
--- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -8,16 +8,19 @@ #define vm_UnboxedObject_h #include "gc/DeletePolicy.h" #include "vm/JSObject.h" #include "vm/Runtime.h" 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 UnboxedTypeSize(JSValueType type) { switch (type) { case JSVAL_TYPE_BOOLEAN: return 1; case JSVAL_TYPE_INT32: return 4; @@ -39,95 +42,81 @@ UnboxedTypeNeedsPostBarrier(JSValueType { return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT; } // Class tracking information specific to unboxed objects. 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_; // 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. // All properties on objects with this layout, in enumeration order. 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) { size_ = size; 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 { return properties_; } TypeNewScript* newScript() const { return newScript_;