diff --git a/js/public/ProfilingFrameIterator.h b/js/public/ProfilingFrameIterator.h index 0cbe2172d2c5..4f48034318a4 100644 --- a/js/public/ProfilingFrameIterator.h +++ b/js/public/ProfilingFrameIterator.h @@ -103,8 +103,6 @@ class JS_PUBLIC_API(ProfilingFrameIterator) void *returnAddress; void *activation; const char *label; - bool hasTrackedOptimizations; - uint8_t trackedOptimizationIndex; }; uint32_t extractStack(Frame *frames, uint32_t offset, uint32_t end) const; diff --git a/js/public/TrackedOptimizationInfo.h b/js/public/TrackedOptimizationInfo.h deleted file mode 100644 index 7d3626b38adb..000000000000 --- a/js/public/TrackedOptimizationInfo.h +++ /dev/null @@ -1,316 +0,0 @@ -/* -*- 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/. */ - -#ifndef js_TrackedOptimizationInfo_h -#define js_TrackedOptimizationInfo_h - -namespace JS { - -#define TRACKED_STRATEGY_LIST(_) \ - _(GetProp_ArgumentsLength, \ - "getprop arguments.length") \ - _(GetProp_ArgumentsCallee, \ - "getprop arguments.callee") \ - _(GetProp_InferredConstant, \ - "getprop inferred constant") \ - _(GetProp_Constant, \ - "getprop constant") \ - _(GetProp_TypedObject, \ - "getprop TypedObject") \ - _(GetProp_DefiniteSlot, \ - "getprop definite slot") \ - _(GetProp_Unboxed, \ - "getprop unboxed object") \ - _(GetProp_CommonGetter, \ - "getprop common getter") \ - _(GetProp_InlineAccess, \ - "getprop inline access") \ - _(GetProp_Innerize, \ - "getprop innerize (access on global window)") \ - _(GetProp_InlineCache, \ - "getprop IC") \ - \ - _(SetProp_CommonSetter, \ - "setprop common setter") \ - _(SetProp_TypedObject, \ - "setprop TypedObject") \ - _(SetProp_DefiniteSlot, \ - "setprop definite slot") \ - _(SetProp_Unboxed, \ - "setprop unboxed object") \ - _(SetProp_InlineAccess, \ - "setprop inline access") \ - \ - _(GetElem_TypedObject, \ - "getprop TypedObject") \ - _(GetElem_Dense, \ - "getelem dense") \ - _(GetElem_TypedStatic, \ - "getelem TypedArray static") \ - _(GetElem_TypedArray, \ - "getelem TypedArray") \ - _(GetElem_String, \ - "getelem string") \ - _(GetElem_Arguments, \ - "getelem arguments") \ - _(GetElem_ArgumentsInlined, \ - "getelem arguments inlined") \ - _(GetElem_InlineCache, \ - "getelem IC") \ - \ - _(SetElem_TypedObject, \ - "setelem TypedObject") \ - _(SetElem_TypedStatic, \ - "setelem TypedArray static") \ - _(SetElem_TypedArray, \ - "setelem TypedArray") \ - _(SetElem_Dense, \ - "setelem dense") \ - _(SetElem_Arguments, \ - "setelem arguments") \ - _(SetElem_InlineCache, \ - "setelem IC") \ - \ - _(Call_Inline, \ - "call inline") - - -// Ordering is important below. All outcomes before GenericSuccess will be -// considered failures, and all outcomes after GenericSuccess will be -// considered successes. -#define TRACKED_OUTCOME_LIST(_) \ - _(GenericFailure, \ - "failure") \ - _(Disabled, \ - "disabled") \ - _(NoTypeInfo, \ - "no type info") \ - _(NoAnalysisInfo, \ - "no newscript analysis") \ - _(NoShapeInfo, \ - "cannot determine shape") \ - _(UnknownObject, \ - "unknown object") \ - _(UnknownProperties, \ - "unknown properties") \ - _(Singleton, \ - "is singleton") \ - _(NotSingleton, \ - "is not singleton") \ - _(NotFixedSlot, \ - "property not in fixed slot") \ - _(InconsistentFixedSlot, \ - "property not in a consistent fixed slot") \ - _(NotObject, \ - "not definitely an object") \ - _(NotStruct, \ - "not definitely a TypedObject struct") \ - _(NotUnboxed, \ - "not definitely an unboxed object") \ - _(StructNoField, \ - "struct doesn't definitely have field") \ - _(InconsistentFieldType, \ - "unboxed property does not have consistent type") \ - _(InconsistentFieldOffset, \ - "unboxed property does not have consistent offset") \ - _(NeedsTypeBarrier, \ - "needs type barrier") \ - _(InDictionaryMode, \ - "object in dictionary mode") \ - _(NoProtoFound, \ - "no proto found") \ - _(MultiProtoPaths, \ - "not all paths to property go through same proto") \ - _(NonWritableProperty, \ - "non-writable property") \ - _(ProtoIndexedProps, \ - "prototype has indexed properties") \ - _(ArrayBadFlags, \ - "array observed to be sparse, overflowed .length, or has been iterated") \ - _(ArrayDoubleConversion, \ - "array has ambiguous double conversion") \ - _(ArrayRange, \ - "array range issue (.length problems)") \ - _(ArraySeenNegativeIndex, \ - "has seen array access with negative index") \ - _(TypedObjectNeutered, \ - "TypedObject might have been neutered") \ - _(TypedObjectArrayRange, \ - "TypedObject array of unknown length") \ - _(AccessNotDense, \ - "access not on dense native (check receiver, index, and result types)") \ - _(AccessNotTypedObject, \ - "access not on typed array (check receiver and index types)") \ - _(AccessNotTypedArray, \ - "access not on typed array (check receiver, index, and result types)") \ - _(AccessNotString, \ - "getelem not on string (check receiver and index types)") \ - _(StaticTypedArrayUint32, \ - "static uint32 arrays currently cannot be optimized") \ - _(StaticTypedArrayCantComputeMask, \ - "can't compute mask for static typed array access (index isn't constant or not int32)") \ - _(OutOfBounds, \ - "observed out of bounds access") \ - _(GetElemStringNotCached, \ - "getelem on strings is not inline cached") \ - _(NonNativeReceiver, \ - "observed non-native receiver") \ - _(IndexType, \ - "index type must be int32, string, or symbol") \ - _(SetElemNonDenseNonTANotCached, \ - "setelem on non-dense non-TAs are not inline cached") \ - \ - _(CantInlineGeneric, \ - "can't inline") \ - _(CantInlineNoTarget, \ - "can't inline: no target") \ - _(CantInlineNotInterpreted, \ - "can't inline: not interpreted") \ - _(CantInlineNoBaseline, \ - "can't inline: no baseline code") \ - _(CantInlineLazy, \ - "can't inline: lazy script") \ - _(CantInlineNotConstructor, \ - "can't inline: calling non-constructor with 'new'") \ - _(CantInlineDisabledIon, \ - "can't inline: ion disabled for callee") \ - _(CantInlineTooManyArgs, \ - "can't inline: too many arguments") \ - _(CantInlineRecursive, \ - "can't inline: recursive") \ - _(CantInlineHeavyweight, \ - "can't inline: heavyweight") \ - _(CantInlineNeedsArgsObj, \ - "can't inline: needs arguments object") \ - _(CantInlineDebuggee, \ - "can't inline: debuggee") \ - _(CantInlineUnknownProps, \ - "can't inline: type has unknown properties") \ - _(CantInlineExceededDepth, \ - "can't inline: exceeded inlining depth") \ - _(CantInlineBigLoop, \ - "can't inline: big function with a loop") \ - _(CantInlineBigCaller, \ - "can't inline: big caller") \ - _(CantInlineBigCallee, \ - "can't inline: big callee") \ - _(CantInlineNotHot, \ - "can't inline: not hot enough") \ - _(CantInlineNotInDispatch, \ - "can't inline: not in dispatch table") \ - _(CantInlineNativeBadForm, \ - "can't inline native: bad form (arity mismatch/constructing)") \ - _(CantInlineNativeBadType, \ - "can't inline native: bad argument or return type observed") \ - _(CantInlineNativeNoTemplateObj, \ - "can't inline native: no template object") \ - _(CantInlineBound, \ - "can't inline bound function invocation") \ - \ - _(GenericSuccess, \ - "success") \ - _(Inlined, \ - "inlined") \ - _(DOM, \ - "DOM") \ - _(Monomorphic, \ - "monomorphic") \ - _(Polymorphic, \ - "polymorphic") - -#define TRACKED_TYPESITE_LIST(_) \ - _(Receiver, \ - "receiver object") \ - _(Index, \ - "index") \ - _(Value, \ - "value") \ - _(Call_Target, \ - "call target") \ - _(Call_This, \ - "call 'this'") \ - _(Call_Arg, \ - "call argument") \ - _(Call_Return, \ - "call return") - -enum class TrackedStrategy : uint32_t { -#define STRATEGY_OP(name, msg) name, - TRACKED_STRATEGY_LIST(STRATEGY_OP) -#undef STRATEGY_OPT - - Count -}; - -enum class TrackedOutcome : uint32_t { -#define OUTCOME_OP(name, msg) name, - TRACKED_OUTCOME_LIST(OUTCOME_OP) -#undef OUTCOME_OP - - Count -}; - -enum class TrackedTypeSite : uint32_t { -#define TYPESITE_OP(name, msg) name, - TRACKED_TYPESITE_LIST(TYPESITE_OP) -#undef TYPESITE_OP - - Count -}; - -extern JS_PUBLIC_API(const char *) -TrackedStrategyString(TrackedStrategy strategy); - -extern JS_PUBLIC_API(const char *) -TrackedOutcomeString(TrackedOutcome outcome); - -extern JS_PUBLIC_API(const char *) -TrackedTypeSiteString(TrackedTypeSite site); - -struct ForEachTrackedOptimizationAttemptOp -{ - virtual void operator()(TrackedStrategy strategy, TrackedOutcome outcome) = 0; -}; - -JS_PUBLIC_API(void) -ForEachTrackedOptimizationAttempt(JSRuntime *rt, void *addr, uint8_t index, - ForEachTrackedOptimizationAttemptOp &op); - -struct ForEachTrackedOptimizationTypeInfoOp -{ - // Called 0+ times per entry, once for each type in the type set that Ion - // saw during MIR construction. readType is always called _before_ - // operator() on the same entry. - // - // The keyedBy parameter describes how the type is keyed: - // - "primitive" for primitive types - // - "constructor" for object types tied to a scripted constructor - // function. - // - "alloc site" for object types tied to an allocation site. - // - "prototype" for object types tied neither to a constructor nor - // to an allocation site. - // - // The name parameter is the string representation of the type. If the - // type is keyed by "constructor", or if the type itself refers to a - // scripted function, the name is the function's displayAtom. - // - // If the type is keyed by "constructor", "alloc site", or if the type - // itself refers to a scripted function, the location and lineno - // parameters will be respectively non-nullptr and non-0. - virtual void readType(const char *keyedBy, const char *name, - const char *location, unsigned lineno) = 0; - - // Called once per entry. - virtual void operator()(TrackedTypeSite site, const char *mirType) = 0; -}; - -extern JS_PUBLIC_API(void) -ForEachTrackedOptimizationTypeInfo(JSRuntime *rt, void *addr, uint8_t index, - ForEachTrackedOptimizationTypeInfoOp &op); - -} // namespace JS - -#endif // js_TrackedOptimizationInfo_h diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 42e9bdd6a4c4..59bb89a62236 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7328,7 +7328,7 @@ CodeGenerator::link(JSContext *cx, types::CompilerConstraintList *constraints) // Generate the tracked optimizations map. if (isOptimizationTrackingEnabled()) { // Treat OOMs and failures as if optimization tracking were turned off. - IonTrackedTypeVector *allTypes = cx->new_(); + types::TypeSet::TypeList *allTypes = cx->new_(); if (allTypes && generateCompactTrackedOptimizationsMap(cx, code, allTypes)) { const uint8_t *optsRegionTableAddr = trackedOptimizationsMap_ + trackedOptimizationsRegionTableOffset_; diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 021a819191f9..5c5c12866c60 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -38,10 +38,6 @@ using mozilla::AssertedCast; using mozilla::DebugOnly; using mozilla::Maybe; -using JS::TrackedStrategy; -using JS::TrackedOutcome; -using JS::TrackedTypeSite; - class jit::BaselineFrameInspector { public: diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 8ef0d0658b28..12affe120c04 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -1116,13 +1116,13 @@ class IonBuilder // The track* methods below are called often. Do not combine them with the // unchecked variants, despite the unchecked variants having no other // callers. - void trackTypeInfo(JS::TrackedTypeSite site, MIRType mirType, + void trackTypeInfo(TrackedTypeSite site, MIRType mirType, types::TemporaryTypeSet *typeSet) { if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) trackTypeInfoUnchecked(site, mirType, typeSet); } - void trackTypeInfo(JS::TrackedTypeSite site, JSObject *obj) { + void trackTypeInfo(TrackedTypeSite site, JSObject *obj) { if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) trackTypeInfoUnchecked(site, obj); } @@ -1130,7 +1130,7 @@ class IonBuilder if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) trackTypeInfoUnchecked(callInfo); } - void trackOptimizationAttempt(JS::TrackedStrategy strategy) { + void trackOptimizationAttempt(TrackedStrategy strategy) { if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) trackOptimizationAttemptUnchecked(strategy); } @@ -1138,7 +1138,7 @@ class IonBuilder if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) amendOptimizationAttemptUnchecked(index); } - void trackOptimizationOutcome(JS::TrackedOutcome outcome) { + void trackOptimizationOutcome(TrackedOutcome outcome) { if (MOZ_UNLIKELY(current->trackedSite()->hasOptimizations())) trackOptimizationOutcomeUnchecked(outcome); } @@ -1153,13 +1153,13 @@ class IonBuilder // Out-of-line variants that don't check if optimization tracking is // enabled. - void trackTypeInfoUnchecked(JS::TrackedTypeSite site, MIRType mirType, + void trackTypeInfoUnchecked(TrackedTypeSite site, MIRType mirType, types::TemporaryTypeSet *typeSet); - void trackTypeInfoUnchecked(JS::TrackedTypeSite site, JSObject *obj); + void trackTypeInfoUnchecked(TrackedTypeSite site, JSObject *obj); void trackTypeInfoUnchecked(CallInfo &callInfo); - void trackOptimizationAttemptUnchecked(JS::TrackedStrategy strategy); + void trackOptimizationAttemptUnchecked(TrackedStrategy strategy); void amendOptimizationAttemptUnchecked(uint32_t index); - void trackOptimizationOutcomeUnchecked(JS::TrackedOutcome outcome); + void trackOptimizationOutcomeUnchecked(TrackedOutcome outcome); void trackOptimizationSuccessUnchecked(); void trackInlineSuccessUnchecked(InliningStatus status); }; diff --git a/js/src/jit/JitcodeMap.h b/js/src/jit/JitcodeMap.h index 96ebc3e62708..018e76f2dd12 100644 --- a/js/src/jit/JitcodeMap.h +++ b/js/src/jit/JitcodeMap.h @@ -115,14 +115,14 @@ class JitcodeGlobalEntry // attempts vectors. // // All pointers point into the same block of memory; the beginning of - // the block is optRegionTable_->payloadStart(). + // the block is optimizationRegionTable_->payloadStart(). const IonTrackedOptimizationsRegionTable *optsRegionTable_; const IonTrackedOptimizationsTypesTable *optsTypesTable_; const IonTrackedOptimizationsAttemptsTable *optsAttemptsTable_; // The types table above records type sets, which have been gathered // into one vector here. - IonTrackedTypeVector *optsAllTypes_; + types::TypeSet::TypeList *optsAllTypes_; struct ScriptNamePair { JSScript *script; @@ -163,7 +163,7 @@ class JitcodeGlobalEntry void initTrackedOptimizations(const IonTrackedOptimizationsRegionTable *regionTable, const IonTrackedOptimizationsTypesTable *typesTable, const IonTrackedOptimizationsAttemptsTable *attemptsTable, - IonTrackedTypeVector *allTypes) + types::TypeSet::TypeList *allTypes) { optsRegionTable_ = regionTable; optsTypesTable_ = typesTable; @@ -214,22 +214,7 @@ class JitcodeGlobalEntry return !!optsRegionTable_; } - IonTrackedOptimizationsAttempts trackedOptimizationAttempts(uint8_t index) { - MOZ_ASSERT(hasTrackedOptimizations()); - return optsAttemptsTable_->entry(index); - } - - IonTrackedOptimizationsTypeInfo trackedOptimizationTypeInfo(uint8_t index) { - MOZ_ASSERT(hasTrackedOptimizations()); - return optsTypesTable_->entry(index); - } - - const IonTrackedTypeVector *allTrackedTypes() { - MOZ_ASSERT(hasTrackedOptimizations()); - return optsAllTypes_; - } - - mozilla::Maybe trackedOptimizationIndexAtAddr(void *ptr); + bool optimizationAttemptsAtAddr(void *ptr, mozilla::Maybe &attempts); }; struct BaselineEntry : public BaseEntry @@ -560,46 +545,6 @@ class JitcodeGlobalEntry // Compute a profiling string for a given script. static char *createScriptString(JSContext *cx, JSScript *script, size_t *length=nullptr); - - bool hasTrackedOptimizations() const { - switch (kind()) { - case Ion: - return ionEntry().hasTrackedOptimizations(); - case Baseline: - case IonCache: - case Dummy: - break; - default: - MOZ_CRASH("Invalid JitcodeGlobalEntry kind."); - } - return false; - } - - mozilla::Maybe trackedOptimizationIndexAtAddr(void *addr) { - switch (kind()) { - case Ion: - return ionEntry().trackedOptimizationIndexAtAddr(addr); - case Baseline: - case IonCache: - case Dummy: - break; - default: - MOZ_CRASH("Invalid JitcodeGlobalEntry kind."); - } - return mozilla::Nothing(); - } - - IonTrackedOptimizationsAttempts trackedOptimizationAttempts(uint8_t index) { - return ionEntry().trackedOptimizationAttempts(index); - } - - IonTrackedOptimizationsTypeInfo trackedOptimizationTypeInfo(uint8_t index) { - return ionEntry().trackedOptimizationTypeInfo(index); - } - - const IonTrackedTypeVector *allTrackedTypes() { - return ionEntry().allTrackedTypes(); - } }; /* diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 8f44052c567c..19f57caa1b4e 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -24,10 +24,6 @@ using mozilla::ArrayLength; -using JS::TrackedStrategy; -using JS::TrackedOutcome; -using JS::TrackedTypeSite; - namespace js { namespace jit { diff --git a/js/src/jit/OptimizationTracking.cpp b/js/src/jit/OptimizationTracking.cpp index 7cfa5d551d9b..a416dabb0e66 100644 --- a/js/src/jit/OptimizationTracking.cpp +++ b/js/src/jit/OptimizationTracking.cpp @@ -10,7 +10,6 @@ #include "jit/IonBuilder.h" #include "jit/JitcodeMap.h" #include "jit/JitSpewer.h" -#include "js/TrackedOptimizationInfo.h" using namespace js; using namespace js::jit; @@ -19,14 +18,10 @@ using mozilla::Maybe; using mozilla::Some; using mozilla::Nothing; -using JS::TrackedStrategy; -using JS::TrackedOutcome; -using JS::TrackedTypeSite; -using JS::ForEachTrackedOptimizationAttemptOp; -using JS::ForEachTrackedOptimizationTypeInfoOp; +typedef CodeGeneratorShared::NativeToTrackedOptimizations NativeToTrackedOptimizations; bool -TrackedOptimizations::trackTypeInfo(OptimizationTypeInfo &&ty) +TrackedOptimizations::trackTypeInfo(TrackedTypeInfo &&ty) { return types_.append(mozilla::Move(ty)); } @@ -72,19 +67,20 @@ VectorContentsMatch(const Vec *xs, const Vec *ys) } bool -TrackedOptimizations::matchTypes(const TempOptimizationTypeInfoVector &other) const +TrackedOptimizations::matchTypes(const TempTrackedTypeInfoVector &other) const { return VectorContentsMatch(&types_, &other); } bool -TrackedOptimizations::matchAttempts(const TempOptimizationAttemptsVector &other) const +TrackedOptimizations::matchAttempts(const TempAttemptsVector &other) const { return VectorContentsMatch(&attempts_, &other); } -JS_PUBLIC_API(const char *) -JS::TrackedStrategyString(TrackedStrategy strategy) +#ifdef DEBUG +static const char * +StrategyString(TrackedStrategy strategy) { switch (strategy) { #define STRATEGY_CASE(name, msg) \ @@ -98,8 +94,8 @@ JS::TrackedStrategyString(TrackedStrategy strategy) } } -JS_PUBLIC_API(const char *) -JS::TrackedOutcomeString(TrackedOutcome outcome) +static const char * +OutcomeString(TrackedOutcome outcome) { switch (outcome) { #define OUTCOME_CASE(name, msg) \ @@ -113,10 +109,10 @@ JS::TrackedOutcomeString(TrackedOutcome outcome) } } -JS_PUBLIC_API(const char *) -JS::TrackedTypeSiteString(TrackedTypeSite site) +static const char * +TypeSiteString(TrackedTypeSite kind) { - switch (site) { + switch (kind) { #define TYPESITE_CASE(name, msg) \ case TrackedTypeSite::name: \ return msg; @@ -127,16 +123,15 @@ JS::TrackedTypeSiteString(TrackedTypeSite site) MOZ_CRASH("bad type site"); } } +#endif // DEBUG void -SpewTempOptimizationTypeInfoVector(const TempOptimizationTypeInfoVector *types, - const char *indent = nullptr) +SpewTempTrackedTypeInfoVector(const TempTrackedTypeInfoVector *types, const char *indent = nullptr) { #ifdef DEBUG - for (const OptimizationTypeInfo *t = types->begin(); t != types->end(); t++) { - JitSpewStart(JitSpew_OptimizationTracking, " %s%s of type %s, type set", - indent ? indent : "", - TrackedTypeSiteString(t->site()), StringFromMIRType(t->mirType())); + for (const TrackedTypeInfo *t = types->begin(); t != types->end(); t++) { + JitSpewStart(JitSpew_OptimizationTracking, " %s%s of type %s, type set", indent ? indent : "", + TypeSiteString(t->site()), StringFromMIRType(t->mirType())); for (uint32_t i = 0; i < t->types().length(); i++) JitSpewCont(JitSpew_OptimizationTracking, " %s", types::TypeString(t->types()[i])); JitSpewFin(JitSpew_OptimizationTracking); @@ -145,13 +140,12 @@ SpewTempOptimizationTypeInfoVector(const TempOptimizationTypeInfoVector *types, } void -SpewTempOptimizationAttemptsVector(const TempOptimizationAttemptsVector *attempts, - const char *indent = nullptr) +SpewTempAttemptsVector(const TempAttemptsVector *attempts, const char *indent = nullptr) { #ifdef DEBUG for (const OptimizationAttempt *a = attempts->begin(); a != attempts->end(); a++) { JitSpew(JitSpew_OptimizationTracking, " %s%s: %s", indent ? indent : "", - TrackedStrategyString(a->strategy()), TrackedOutcomeString(a->outcome())); + StrategyString(a->strategy()), OutcomeString(a->outcome())); } #endif } @@ -160,13 +154,13 @@ void TrackedOptimizations::spew() const { #ifdef DEBUG - SpewTempOptimizationTypeInfoVector(&types_); - SpewTempOptimizationAttemptsVector(&attempts_); + SpewTempTrackedTypeInfoVector(&types_); + SpewTempAttemptsVector(&attempts_); #endif } bool -OptimizationTypeInfo::trackTypeSet(types::TemporaryTypeSet *typeSet) +TrackedTypeInfo::trackTypeSet(types::TemporaryTypeSet *typeSet) { if (!typeSet) return true; @@ -174,20 +168,20 @@ OptimizationTypeInfo::trackTypeSet(types::TemporaryTypeSet *typeSet) } bool -OptimizationTypeInfo::trackType(types::Type type) +TrackedTypeInfo::trackType(types::Type type) { return types_.append(type); } bool -OptimizationTypeInfo::operator ==(const OptimizationTypeInfo &other) const +TrackedTypeInfo::operator ==(const TrackedTypeInfo &other) const { return site_ == other.site_ && mirType_ == other.mirType_ && VectorContentsMatch(&types_, &other.types_); } bool -OptimizationTypeInfo::operator !=(const OptimizationTypeInfo &other) const +TrackedTypeInfo::operator !=(const TrackedTypeInfo &other) const { return !(*this == other); } @@ -219,7 +213,7 @@ HashTypeList(const types::TypeSet::TypeList &types) } HashNumber -OptimizationTypeInfo::hash() const +TrackedTypeInfo::hash() const { return ((HashNumber(site_) << 24) + (HashNumber(mirType_) << 16)) ^ HashTypeList(types_); } @@ -440,54 +434,28 @@ IonTrackedOptimizationsRegion::RangeIterator::readNext(uint32_t *startOffset, ui MOZ_ASSERT(cur_ <= end_); } -Maybe -JitcodeGlobalEntry::IonEntry::trackedOptimizationIndexAtAddr(void *ptr) +bool +JitcodeGlobalEntry::IonEntry::optimizationAttemptsAtAddr(void *ptr, + Maybe &attempts) { - MOZ_ASSERT(hasTrackedOptimizations()); + MOZ_ASSERT(!attempts); MOZ_ASSERT(containsPointer(ptr)); uint32_t ptrOffset = ((uint8_t *) ptr) - ((uint8_t *) nativeStartAddr()); Maybe region = optsRegionTable_->findRegion(ptrOffset); if (region.isNothing()) - return Nothing(); - return region->findIndex(ptrOffset); -} - -void -IonTrackedOptimizationsAttempts::forEach(ForEachTrackedOptimizationAttemptOp &op) -{ - CompactBufferReader reader(start_, end_); - const uint8_t *cur = start_; - while (cur != end_) { - TrackedStrategy strategy = TrackedStrategy(reader.readUnsigned()); - TrackedOutcome outcome = TrackedOutcome(reader.readUnsigned()); - MOZ_ASSERT(strategy < TrackedStrategy::Count); - MOZ_ASSERT(outcome < TrackedOutcome::Count); - op(strategy, outcome); - cur = reader.currentPosition(); - MOZ_ASSERT(cur <= end_); - } -} - -void -IonTrackedOptimizationsTypeInfo::forEach(ForEachOp &op, const IonTrackedTypeVector *allTypes) -{ - CompactBufferReader reader(start_, end_); - const uint8_t *cur = start_; - while (cur != end_) { - TrackedTypeSite site = JS::TrackedTypeSite(reader.readUnsigned()); - MOZ_ASSERT(site < JS::TrackedTypeSite::Count); - MIRType mirType = MIRType(reader.readUnsigned()); - uint32_t length = reader.readUnsigned(); - for (uint32_t i = 0; i < length; i++) - op.readType((*allTypes)[reader.readByte()]); - op(site, mirType); - cur = reader.currentPosition(); - MOZ_ASSERT(cur <= end_); - } + return true; + Maybe attemptsIdx = region->findAttemptsIndex(ptrOffset); + if (attemptsIdx.isNothing()) + return true; + IonTrackedOptimizationsAttempts attemptsEntry = optsAttemptsTable_->entry(*attemptsIdx); + attempts.emplace(); + if (!attemptsEntry.readVector(attempts.ptr())) + return false; + return true; } Maybe -IonTrackedOptimizationsRegion::findIndex(uint32_t offset) const +IonTrackedOptimizationsRegion::findAttemptsIndex(uint32_t offset) const { if (offset < startOffset_ || offset >= endOffset_) return Nothing(); @@ -587,7 +555,7 @@ OptimizationAttempt::writeCompact(CompactBufferWriter &writer) const } bool -OptimizationTypeInfo::writeCompact(CompactBufferWriter &writer, +TrackedTypeInfo::writeCompact(CompactBufferWriter &writer, UniqueTrackedTypes &uniqueTypes) const { writer.writeUnsigned((uint32_t) site_); @@ -779,6 +747,32 @@ IonTrackedOptimizationsRegion::WriteRun(CompactBufferWriter &writer, return true; } +TrackedTypeInfo::TrackedTypeInfo(CompactBufferReader &reader) + : site_(TrackedTypeSite(reader.readUnsigned())), + mirType_(MIRType(reader.readUnsigned())) +{ + MOZ_ASSERT(site_ < TrackedTypeSite::Count); +} + +bool +TrackedTypeInfo::readTypes(CompactBufferReader &reader, const types::TypeSet::TypeList *allTypes) +{ + uint32_t length = reader.readUnsigned(); + for (uint32_t i = 0; i < length; i++) { + if (!types_.append((*allTypes)[reader.readByte()])) + return false; + } + return true; +} + +OptimizationAttempt::OptimizationAttempt(CompactBufferReader &reader) + : strategy_(TrackedStrategy(reader.readUnsigned())), + outcome_(TrackedOutcome(reader.readUnsigned())) +{ + MOZ_ASSERT(strategy_ < TrackedStrategy::Count); + MOZ_ASSERT(outcome_ < TrackedOutcome::Count); +} + static bool WriteOffsetsTable(CompactBufferWriter &writer, const Vector &offsets, uint32_t *tableOffsetp) @@ -813,50 +807,6 @@ WriteOffsetsTable(CompactBufferWriter &writer, const Vector &offse return true; } -static JSFunction * -MaybeConstructorFromType(types::Type ty) -{ - if (ty.isUnknown() || ty.isAnyObject() || !ty.isGroup()) - return nullptr; - types::ObjectGroup *obj = ty.group(); - types::TypeNewScript *newScript = obj->newScript(); - if (!newScript && obj->maybeUnboxedLayout()) - newScript = obj->unboxedLayout().newScript(); - return newScript ? newScript->function() : nullptr; -} - -static void -SpewConstructor(types::Type ty, JSFunction *constructor) -{ -#ifdef DEBUG - char buf[512]; - PutEscapedString(buf, 512, constructor->displayAtom(), 0); - - const char *filename; - uint32_t lineno; - if (constructor->hasScript()) { - filename = constructor->nonLazyScript()->filename(); - lineno = constructor->nonLazyScript()->lineno(); - } else { - filename = constructor->lazyScript()->filename(); - lineno = constructor->lazyScript()->lineno(); - } - - JitSpew(JitSpew_OptimizationTracking, " Unique type %s has constructor %s (%s:%u)", - types::TypeString(ty), buf, filename, lineno); -#endif -} - -static void -SpewAllocationSite(types::Type ty, JSScript *script, uint32_t offset) -{ -#ifdef DEBUG - JitSpew(JitSpew_OptimizationTracking, " Unique type %s has alloc site %s:%u", - types::TypeString(ty), script->filename(), - PCToLineNumber(script, script->offsetToPC(offset))); -#endif -} - bool jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &writer, const NativeToTrackedOptimizations *start, @@ -866,7 +816,7 @@ jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &write uint32_t *regionTableOffsetp, uint32_t *typesTableOffsetp, uint32_t *optimizationTableOffsetp, - IonTrackedTypeVector *allTypes) + types::TypeSet::TypeList *allTypes) { MOZ_ASSERT(unique.sorted()); @@ -923,47 +873,23 @@ jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &write return false; for (const UniqueTrackedOptimizations::SortEntry *p = vec.begin(); p != vec.end(); p++) { - const TempOptimizationTypeInfoVector *v = p->types; + const TempTrackedTypeInfoVector *v = p->types; JitSpew(JitSpew_OptimizationTracking, " Type info entry %u of length %u, offset %u", p - vec.begin(), v->length(), writer.length()); - SpewTempOptimizationTypeInfoVector(v, " "); + SpewTempTrackedTypeInfoVector(v, " "); if (!offsets.append(writer.length())) return false; - for (const OptimizationTypeInfo *t = v->begin(); t != v->end(); t++) { + for (const TrackedTypeInfo *t = v->begin(); t != v->end(); t++) { if (!t->writeCompact(writer, uniqueTypes)) return false; } } - // Enumerate the unique types, and pull out any 'new' script constructor - // functions and allocation site information. We do this during linking - // instead of during profiling to avoid touching compartment tables during - // profiling. Additionally, TypeNewScript is subject to GC in the - // meantime. - types::TypeSet::TypeList uniqueTypeList; - if (!uniqueTypes.enumerate(&uniqueTypeList)) + // Copy the unique type list into the outparam TypeList. + if (!uniqueTypes.enumerate(allTypes)) return false; - for (uint32_t i = 0; i < uniqueTypeList.length(); i++) { - types::Type ty = uniqueTypeList[i]; - if (JSFunction *constructor = MaybeConstructorFromType(ty)) { - if (!allTypes->append(IonTrackedTypeWithAddendum(ty, constructor))) - return false; - SpewConstructor(ty, constructor); - } else { - JSScript *script; - uint32_t offset; - if (cx->findAllocationSiteForType(ty, &script, &offset)) { - if (!allTypes->append(IonTrackedTypeWithAddendum(ty, script, offset))) - return false; - SpewAllocationSite(ty, script, offset); - } else { - if (!allTypes->append(IonTrackedTypeWithAddendum(ty))) - return false; - } - } - } if (!WriteOffsetsTable(writer, offsets, typesTableOffsetp)) return false; @@ -971,10 +897,10 @@ jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &write // Write out attempts payloads. for (const UniqueTrackedOptimizations::SortEntry *p = vec.begin(); p != vec.end(); p++) { - const TempOptimizationAttemptsVector *v = p->attempts; + const TempAttemptsVector *v = p->attempts; JitSpew(JitSpew_OptimizationTracking, " Attempts entry %u of length %u, offset %u", p - vec.begin(), v->length(), writer.length()); - SpewTempOptimizationAttemptsVector(v, " "); + SpewTempAttemptsVector(v, " "); if (!offsets.append(writer.length())) return false; @@ -1036,7 +962,7 @@ IonBuilder::trackTypeInfoUnchecked(TrackedTypeSite kind, MIRType mirType, { BytecodeSite *site = current->trackedSite(); // OOMs are handled as if optimization tracking were turned off. - OptimizationTypeInfo typeInfo(kind, mirType); + TrackedTypeInfo typeInfo(kind, mirType); if (!typeInfo.trackTypeSet(typeSet)) { site->setOptimizations(nullptr); return; @@ -1050,7 +976,7 @@ IonBuilder::trackTypeInfoUnchecked(TrackedTypeSite kind, JSObject *obj) { BytecodeSite *site = current->trackedSite(); // OOMs are handled as if optimization tracking were turned off. - OptimizationTypeInfo typeInfo(kind, MIRType_Object); + TrackedTypeInfo typeInfo(kind, MIRType_Object); if (!typeInfo.trackType(types::Type::ObjectType(obj))) return; if (!site->optimizations()->trackTypeInfo(mozilla::Move(typeInfo))) @@ -1109,104 +1035,3 @@ IonBuilder::trackInlineSuccessUnchecked(InliningStatus status) if (status == InliningStatus_Inlined) trackOptimizationOutcome(TrackedOutcome::Inlined); } - -JS_PUBLIC_API(void) -JS::ForEachTrackedOptimizationAttempt(JSRuntime *rt, void *addr, uint8_t index, - ForEachTrackedOptimizationAttemptOp &op) -{ - JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable(); - JitcodeGlobalEntry entry; - table->lookupInfallible(addr, &entry, rt); - entry.trackedOptimizationAttempts(index).forEach(op); -} - -static void -InterpretedFunctionFilenameAndLineNumber(JSFunction *fun, const char **filename, unsigned *lineno) -{ - ScriptSource *source; - if (fun->hasScript()) { - source = fun->nonLazyScript()->maybeForwardedScriptSource(); - *lineno = fun->nonLazyScript()->lineno(); - } else { - source = fun->lazyScript()->maybeForwardedScriptSource(); - *lineno = fun->lazyScript()->lineno(); - } - *filename = source->introducerFilename(); -} - -static JSFunction * -InterpretedFunctionFromTrackedType(const IonTrackedTypeWithAddendum &tracked) -{ - if (tracked.hasConstructor()) - return tracked.constructor; - - types::Type ty = tracked.type; - - if (ty.isSingleton()) { - JSObject *obj = ty.singleton(); - return obj->is() ? &obj->as() : nullptr; - } - - return ty.group()->maybeInterpretedFunction(); -} - -// This adapter is needed as the internal API can deal with engine-internal -// data structures directly, while the public API cannot. -class ForEachTypeInfoAdapter : public IonTrackedOptimizationsTypeInfo::ForEachOp -{ - ForEachTrackedOptimizationTypeInfoOp &op_; - - public: - explicit ForEachTypeInfoAdapter(ForEachTrackedOptimizationTypeInfoOp &op) - : op_(op) - { } - - void readType(const IonTrackedTypeWithAddendum &tracked) MOZ_OVERRIDE { - types::Type ty = tracked.type; - - if (ty.isPrimitive() || ty.isUnknown() || ty.isAnyObject()) { - op_.readType("primitive", types::NonObjectTypeString(ty), nullptr, 0); - return; - } - - char buf[512]; - const uint32_t bufsize = mozilla::ArrayLength(buf); - - if (JSFunction *fun = InterpretedFunctionFromTrackedType(tracked)) { - PutEscapedString(buf, bufsize, fun->displayAtom(), 0); - const char *filename; - unsigned lineno; - InterpretedFunctionFilenameAndLineNumber(fun, &filename, &lineno); - op_.readType(tracked.constructor ? "constructor" : "function", buf, filename, lineno); - return; - } - - const char *className = ty.objectKey()->clasp()->name; - JS_snprintf(buf, bufsize, "[object %s]", className); - - if (tracked.hasAllocationSite()) { - JSScript *script = tracked.script; - op_.readType("alloc site", buf, - script->maybeForwardedScriptSource()->introducerFilename(), - PCToLineNumber(script, script->offsetToPC(tracked.offset))); - return; - } - - op_.readType("prototype", buf, nullptr, 0); - } - - void operator()(JS::TrackedTypeSite site, MIRType mirType) MOZ_OVERRIDE { - op_(site, StringFromMIRType(mirType)); - } -}; - -JS_PUBLIC_API(void) -JS::ForEachTrackedOptimizationTypeInfo(JSRuntime *rt, void *addr, uint8_t index, - ForEachTrackedOptimizationTypeInfoOp &op) -{ - JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable(); - JitcodeGlobalEntry entry; - table->lookupInfallible(addr, &entry, rt); - ForEachTypeInfoAdapter adapter(op); - entry.trackedOptimizationTypeInfo(index).forEach(adapter, entry.allTrackedTypes()); -} diff --git a/js/src/jit/OptimizationTracking.h b/js/src/jit/OptimizationTracking.h index 2876dfa1a3ec..0a31f55b54eb 100644 --- a/js/src/jit/OptimizationTracking.h +++ b/js/src/jit/OptimizationTracking.h @@ -13,30 +13,280 @@ #include "jit/CompactBuffer.h" #include "jit/CompileInfo.h" #include "jit/JitAllocPolicy.h" -#include "js/TrackedOptimizationInfo.h" +#include "jit/shared/CodeGenerator-shared.h" namespace js { namespace jit { -struct NativeToTrackedOptimizations; +#define TRACKED_STRATEGY_LIST(_) \ + _(GetProp_ArgumentsLength, \ + "getprop arguments.length") \ + _(GetProp_ArgumentsCallee, \ + "getprop arguments.callee") \ + _(GetProp_InferredConstant, \ + "getprop inferred constant") \ + _(GetProp_Constant, \ + "getprop constant") \ + _(GetProp_TypedObject, \ + "getprop TypedObject") \ + _(GetProp_DefiniteSlot, \ + "getprop definite slot") \ + _(GetProp_Unboxed, \ + "getprop unboxed object") \ + _(GetProp_CommonGetter, \ + "getprop common getter") \ + _(GetProp_InlineAccess, \ + "getprop inline access") \ + _(GetProp_Innerize, \ + "getprop innerize (access on global window)") \ + _(GetProp_InlineCache, \ + "getprop IC") \ + \ + _(SetProp_CommonSetter, \ + "setprop common setter") \ + _(SetProp_TypedObject, \ + "setprop TypedObject") \ + _(SetProp_DefiniteSlot, \ + "setprop definite slot") \ + _(SetProp_Unboxed, \ + "setprop unboxed object") \ + _(SetProp_InlineAccess, \ + "setprop inline access") \ + \ + _(GetElem_TypedObject, \ + "getprop TypedObject") \ + _(GetElem_Dense, \ + "getelem dense") \ + _(GetElem_TypedStatic, \ + "getelem TypedArray static") \ + _(GetElem_TypedArray, \ + "getelem TypedArray") \ + _(GetElem_String, \ + "getelem string") \ + _(GetElem_Arguments, \ + "getelem arguments") \ + _(GetElem_ArgumentsInlined, \ + "getelem arguments inlined") \ + _(GetElem_InlineCache, \ + "getelem IC") \ + \ + _(SetElem_TypedObject, \ + "setelem TypedObject") \ + _(SetElem_TypedStatic, \ + "setelem TypedArray static") \ + _(SetElem_TypedArray, \ + "setelem TypedArray") \ + _(SetElem_Dense, \ + "setelem dense") \ + _(SetElem_Arguments, \ + "setelem arguments") \ + _(SetElem_InlineCache, \ + "setelem IC") \ + \ + _(Call_Inline, \ + "call inline") + + +// Ordering is important below. All outcomes before GenericSuccess will be +// considered failures, and all outcomes after GenericSuccess will be +// considered successes. +#define TRACKED_OUTCOME_LIST(_) \ + _(GenericFailure, \ + "failure") \ + _(Disabled, \ + "disabled") \ + _(NoTypeInfo, \ + "no type info") \ + _(NoAnalysisInfo, \ + "no newscript analysis") \ + _(NoShapeInfo, \ + "cannot determine shape") \ + _(UnknownObject, \ + "unknown object") \ + _(UnknownProperties, \ + "unknown properties") \ + _(Singleton, \ + "is singleton") \ + _(NotSingleton, \ + "is not singleton") \ + _(NotFixedSlot, \ + "property not in fixed slot") \ + _(InconsistentFixedSlot, \ + "property not in a consistent fixed slot") \ + _(NotObject, \ + "not definitely an object") \ + _(NotStruct, \ + "not definitely a TypedObject struct") \ + _(NotUnboxed, \ + "not definitely an unboxed object") \ + _(StructNoField, \ + "struct doesn't definitely have field") \ + _(InconsistentFieldType, \ + "unboxed property does not consistent type") \ + _(InconsistentFieldOffset, \ + "unboxed property does not consistent offset") \ + _(NeedsTypeBarrier, \ + "needs type barrier") \ + _(InDictionaryMode, \ + "object in dictionary mode") \ + _(NoProtoFound, \ + "no proto found") \ + _(MultiProtoPaths, \ + "not all paths to property go through same proto") \ + _(NonWritableProperty, \ + "non-writable property") \ + _(ProtoIndexedProps, \ + "prototype has indexed properties") \ + _(ArrayBadFlags, \ + "array observed to be sparse, overflowed .length, or has been iterated") \ + _(ArrayDoubleConversion, \ + "array has ambiguous double conversion") \ + _(ArrayRange, \ + "array range issue (.length problems)") \ + _(ArraySeenNegativeIndex, \ + "has seen array access with negative index") \ + _(TypedObjectNeutered, \ + "TypedObject might have been neutered") \ + _(TypedObjectArrayRange, \ + "TypedObject array of unknown length") \ + _(AccessNotDense, \ + "access not on dense native (check receiver, index, and result types)") \ + _(AccessNotTypedObject, \ + "access not on typed array (check receiver and index types)") \ + _(AccessNotTypedArray, \ + "access not on typed array (check receiver, index, and result types)") \ + _(AccessNotString, \ + "getelem not on string (check receiver and index types)") \ + _(StaticTypedArrayUint32, \ + "static uint32 arrays currently cannot be optimized") \ + _(StaticTypedArrayCantComputeMask, \ + "can't compute mask for static typed array access (index isn't constant or not int32)") \ + _(OutOfBounds, \ + "observed out of bounds access") \ + _(GetElemStringNotCached, \ + "getelem on strings is not inline cached") \ + _(NonNativeReceiver, \ + "observed non-native receiver") \ + _(IndexType, \ + "index type must be int32, string, or symbol") \ + _(SetElemNonDenseNonTANotCached, \ + "setelem on non-dense non-TAs are not inline cached") \ + \ + _(CantInlineGeneric, \ + "can't inline") \ + _(CantInlineNoTarget, \ + "can't inline: no target") \ + _(CantInlineNotInterpreted, \ + "can't inline: not interpreted") \ + _(CantInlineNoBaseline, \ + "can't inline: no baseline code") \ + _(CantInlineLazy, \ + "can't inline: lazy script") \ + _(CantInlineNotConstructor, \ + "can't inline: calling non-constructor with 'new'") \ + _(CantInlineDisabledIon, \ + "can't inline: ion disabled for callee") \ + _(CantInlineTooManyArgs, \ + "can't inline: too many arguments") \ + _(CantInlineRecursive, \ + "can't inline: recursive") \ + _(CantInlineHeavyweight, \ + "can't inline: heavyweight") \ + _(CantInlineNeedsArgsObj, \ + "can't inline: needs arguments object") \ + _(CantInlineDebuggee, \ + "can't inline: debuggee") \ + _(CantInlineUnknownProps, \ + "can't inline: type has unknown properties") \ + _(CantInlineExceededDepth, \ + "can't inline: exceeded inlining depth") \ + _(CantInlineBigLoop, \ + "can't inline: big function with a loop") \ + _(CantInlineBigCaller, \ + "can't inline: big caller") \ + _(CantInlineBigCallee, \ + "can't inline: big callee") \ + _(CantInlineNotHot, \ + "can't inline: not hot enough") \ + _(CantInlineNotInDispatch, \ + "can't inline: not in dispatch table") \ + _(CantInlineNativeBadForm, \ + "can't inline native: bad form (arity mismatch/constructing)") \ + _(CantInlineNativeBadType, \ + "can't inline native: bad argument or return type observed") \ + _(CantInlineNativeNoTemplateObj, \ + "can't inline native: no template object") \ + _(CantInlineBound, \ + "can't inline bound function invocation") \ + \ + _(GenericSuccess, \ + "success") \ + _(Inlined, \ + "inlined") \ + _(DOM, \ + "DOM") \ + _(Monomorphic, \ + "monomorphic") \ + _(Polymorphic, \ + "polymorphic") + +#define TRACKED_TYPESITE_LIST(_) \ + _(Receiver, \ + "receiver object") \ + _(Index, \ + "index") \ + _(Value, \ + "value") \ + _(Call_Target, \ + "call target") \ + _(Call_This, \ + "call 'this'") \ + _(Call_Arg, \ + "call argument") \ + _(Call_Return, \ + "call return") + +enum class TrackedStrategy : uint32_t { +#define STRATEGY_OP(name, msg) name, + TRACKED_STRATEGY_LIST(STRATEGY_OP) +#undef STRATEGY_OPT + + Count +}; + +enum class TrackedOutcome : uint32_t { +#define OUTCOME_OP(name, msg) name, + TRACKED_OUTCOME_LIST(OUTCOME_OP) +#undef OUTCOME_OP + + Count +}; + +enum class TrackedTypeSite : uint32_t { +#define TYPESITE_OP(name, msg) name, + TRACKED_TYPESITE_LIST(TYPESITE_OP) +#undef TYPESITE_OP + + Count +}; class OptimizationAttempt { - JS::TrackedStrategy strategy_; - JS::TrackedOutcome outcome_; + TrackedStrategy strategy_; + TrackedOutcome outcome_; public: - OptimizationAttempt(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome) + OptimizationAttempt(TrackedStrategy strategy, TrackedOutcome outcome) : strategy_(strategy), outcome_(outcome) { } - void setOutcome(JS::TrackedOutcome outcome) { outcome_ = outcome; } - bool succeeded() const { return outcome_ >= JS::TrackedOutcome::GenericSuccess; } - bool failed() const { return outcome_ < JS::TrackedOutcome::GenericSuccess; } - JS::TrackedStrategy strategy() const { return strategy_; } - JS::TrackedOutcome outcome() const { return outcome_; } + void setOutcome(TrackedOutcome outcome) { outcome_ = outcome; } + bool succeeded() const { return outcome_ >= TrackedOutcome::GenericSuccess; } + bool failed() const { return outcome_ < TrackedOutcome::GenericSuccess; } + TrackedStrategy strategy() const { return strategy_; } + TrackedOutcome outcome() const { return outcome_; } bool operator ==(const OptimizationAttempt &other) const { return strategy_ == other.strategy_ && outcome_ == other.outcome_; @@ -48,27 +298,29 @@ class OptimizationAttempt return (HashNumber(strategy_) << 8) + HashNumber(outcome_); } + explicit OptimizationAttempt(CompactBufferReader &reader); void writeCompact(CompactBufferWriter &writer) const; }; -typedef Vector TempOptimizationAttemptsVector; +typedef Vector TempAttemptsVector; +typedef Vector AttemptsVector; class UniqueTrackedTypes; -class OptimizationTypeInfo +class TrackedTypeInfo { - JS::TrackedTypeSite site_; + TrackedTypeSite site_; MIRType mirType_; types::TypeSet::TypeList types_; public: - OptimizationTypeInfo(OptimizationTypeInfo &&other) + TrackedTypeInfo(TrackedTypeInfo &&other) : site_(other.site_), mirType_(other.mirType_), types_(mozilla::Move(other.types_)) { } - OptimizationTypeInfo(JS::TrackedTypeSite site, MIRType mirType) + TrackedTypeInfo(TrackedTypeSite site, MIRType mirType) : site_(site), mirType_(mirType) { } @@ -76,26 +328,32 @@ class OptimizationTypeInfo bool trackTypeSet(types::TemporaryTypeSet *typeSet); bool trackType(types::Type type); - JS::TrackedTypeSite site() const { return site_; } + TrackedTypeSite site() const { return site_; } MIRType mirType() const { return mirType_; } const types::TypeSet::TypeList &types() const { return types_; } - bool operator ==(const OptimizationTypeInfo &other) const; - bool operator !=(const OptimizationTypeInfo &other) const; + bool operator ==(const TrackedTypeInfo &other) const; + bool operator !=(const TrackedTypeInfo &other) const; HashNumber hash() const; + // This constructor is designed to be used in conjunction with readTypes + // below it. The same reader must be passed to readTypes after + // instantiating the TrackedTypeInfo. + explicit TrackedTypeInfo(CompactBufferReader &reader); + bool readTypes(CompactBufferReader &reader, const types::TypeSet::TypeList *allTypes); bool writeCompact(CompactBufferWriter &writer, UniqueTrackedTypes &uniqueTypes) const; }; -typedef Vector TempOptimizationTypeInfoVector; +typedef Vector TempTrackedTypeInfoVector; +typedef Vector TrackedTypeInfoVector; // Tracks the optimization attempts made at a bytecode location. class TrackedOptimizations : public TempObject { friend class UniqueTrackedOptimizations; - TempOptimizationTypeInfoVector types_; - TempOptimizationAttemptsVector attempts_; + TempTrackedTypeInfoVector types_; + TempAttemptsVector attempts_; uint32_t currentAttempt_; public: @@ -105,15 +363,15 @@ class TrackedOptimizations : public TempObject currentAttempt_(UINT32_MAX) { } - bool trackTypeInfo(OptimizationTypeInfo &&ty); + bool trackTypeInfo(TrackedTypeInfo &&ty); - bool trackAttempt(JS::TrackedStrategy strategy); + bool trackAttempt(TrackedStrategy strategy); void amendAttempt(uint32_t index); - void trackOutcome(JS::TrackedOutcome outcome); + void trackOutcome(TrackedOutcome outcome); void trackSuccess(); - bool matchTypes(const TempOptimizationTypeInfoVector &other) const; - bool matchAttempts(const TempOptimizationAttemptsVector &other) const; + bool matchTypes(const TempTrackedTypeInfoVector &other) const; + bool matchAttempts(const TempAttemptsVector &other) const; void spew() const; }; @@ -125,8 +383,8 @@ class UniqueTrackedOptimizations public: struct SortEntry { - const TempOptimizationTypeInfoVector *types; - const TempOptimizationAttemptsVector *attempts; + const TempTrackedTypeInfoVector *types; + const TempAttemptsVector *attempts; uint32_t frequency; }; typedef Vector SortedVector; @@ -134,8 +392,8 @@ class UniqueTrackedOptimizations private: struct Key { - const TempOptimizationTypeInfoVector *types; - const TempOptimizationAttemptsVector *attempts; + const TempTrackedTypeInfoVector *types; + const TempAttemptsVector *attempts; typedef Key Lookup; static HashNumber hash(const Lookup &lookup); @@ -151,12 +409,12 @@ class UniqueTrackedOptimizations uint32_t frequency; }; - // Map of unique (TempOptimizationTypeInfoVector, - // TempOptimizationAttemptsVector) pairs to indices. + // Map of unique (TempTrackedTypeInfoVector, TempAttemptsVector) pairs to + // indices. typedef HashMap AttemptsMap; AttemptsMap map_; - // TempOptimizationAttemptsVectors sorted by frequency. + // TempAttemptsVectors sorted by frequency. SortedVector sorted_; public: @@ -199,7 +457,7 @@ class UniqueTrackedOptimizations // | Optimization type info 1 | | // |------------------------------------------------| | // | Optimization type info 2 | |-- PayloadT of list of -// |------------------------------------------------| | OptimizationTypeInfo in +// |------------------------------------------------| | IonTrackedOptimizationTypeInfo in // | ... | | order of decreasing frequency // |------------------------------------------------| | // | Optimization type info N | | @@ -217,7 +475,7 @@ class UniqueTrackedOptimizations // | Optimization attempts 1 | | // |------------------------------------------------| | // | Optimization attempts 2 | |-- PayloadA of list of -// |------------------------------------------------| | OptimizationAttempts in +// |------------------------------------------------| | IonTrackedOptimizationAttempts in // | ... | | order of decreasing frequency // |------------------------------------------------| | // | Optimization attempts N | | @@ -311,9 +569,7 @@ class IonTrackedOptimizationsRegion RangeIterator ranges() const { return RangeIterator(rangesStart_, end_, startOffset_); } - // Find the index of tracked optimization info (e.g., type info and - // attempts) at a native code offset. - mozilla::Maybe findIndex(uint32_t offset) const; + mozilla::Maybe findAttemptsIndex(uint32_t offset) const; // For the variants below, S stands for startDelta, L for length, and I // for index. These were automatically generated from training on the @@ -390,6 +646,7 @@ class IonTrackedOptimizationsRegion static const uint32_t MAX_RUN_LENGTH = 100; + typedef CodeGeneratorShared::NativeToTrackedOptimizations NativeToTrackedOptimizations; static uint32_t ExpectedRunLength(const NativeToTrackedOptimizations *start, const NativeToTrackedOptimizations *end); @@ -416,55 +673,20 @@ class IonTrackedOptimizationsAttempts MOZ_ASSERT(start < end); } - void forEach(JS::ForEachTrackedOptimizationAttemptOp &op); + template + bool readVector(T *attempts) { + CompactBufferReader reader(start_, end_); + const uint8_t *cur = start_; + while (cur != end_) { + if (!attempts->append(OptimizationAttempt(reader))) + return false; + cur = reader.currentPosition(); + MOZ_ASSERT(cur <= end_); + } + return true; + } }; -struct IonTrackedTypeWithAddendum -{ - types::Type type; - - enum HasAddendum { - HasNothing, - HasAllocationSite, - HasConstructor - }; - HasAddendum hasAddendum; - - // If type is a type object and is tied to a site, the script and pc are - // resolved early and stored below. This is done to avoid accessing the - // compartment during profiling time. - union { - struct { - JSScript *script; - uint32_t offset; - }; - JSFunction *constructor; - }; - - explicit IonTrackedTypeWithAddendum(types::Type type) - : type(type), - hasAddendum(HasNothing) - { } - - IonTrackedTypeWithAddendum(types::Type type, JSScript *script, uint32_t offset) - : type(type), - hasAddendum(HasAllocationSite), - script(script), - offset(offset) - { } - - IonTrackedTypeWithAddendum(types::Type type, JSFunction *constructor) - : type(type), - hasAddendum(HasConstructor), - constructor(constructor) - { } - - bool hasAllocationSite() const { return hasAddendum == HasAllocationSite; } - bool hasConstructor() const { return hasAddendum == HasConstructor; } -}; - -typedef Vector IonTrackedTypeVector; - class IonTrackedOptimizationsTypeInfo { const uint8_t *start_; @@ -479,17 +701,21 @@ class IonTrackedOptimizationsTypeInfo bool empty() const { return start_ == end_; } - // Unlike IonTrackedOptimizationAttempts, - // JS::ForEachTrackedOptimizaitonTypeInfoOp cannot be used directly. The - // internal API needs to deal with engine-internal data structures (e.g., - // types::Type) directly. - struct ForEachOp - { - virtual void readType(const IonTrackedTypeWithAddendum &tracked) = 0; - virtual void operator()(JS::TrackedTypeSite site, MIRType mirType) = 0; - }; - - void forEach(ForEachOp &op, const IonTrackedTypeVector *allTypes); + template + bool readVector(T *types, const types::TypeSet::TypeList *allTypes) { + CompactBufferReader reader(start_, end_); + const uint8_t *cur = start_; + while (cur != end_) { + TrackedTypeInfo ty(reader); + if (!ty.readTypes(reader, allTypes)) + return false; + if (!types->append(mozilla::Move(ty))) + return false; + cur = reader.currentPosition(); + MOZ_ASSERT(cur <= end_); + } + return true; + } }; template @@ -537,12 +763,12 @@ typedef IonTrackedOptimizationsOffsetsTable bool WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &writer, - const NativeToTrackedOptimizations *start, - const NativeToTrackedOptimizations *end, + const CodeGeneratorShared::NativeToTrackedOptimizations *start, + const CodeGeneratorShared::NativeToTrackedOptimizations *end, const UniqueTrackedOptimizations &unique, uint32_t *numRegions, uint32_t *regionTableOffsetp, uint32_t *typesTableOffsetp, uint32_t *attemptsTableOffsetp, - IonTrackedTypeVector *allTypes); + types::TypeSet::TypeList *allTypes); } // namespace jit } // namespace js diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 4a19409e54c6..b917e164ad58 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -777,7 +777,7 @@ CodeGeneratorShared::verifyCompactNativeToBytecodeMap(JitCode *code) bool CodeGeneratorShared::generateCompactTrackedOptimizationsMap(JSContext *cx, JitCode *code, - IonTrackedTypeVector *allTypes) + types::TypeSet::TypeList *allTypes) { MOZ_ASSERT(trackedOptimizationsMap_ == nullptr); MOZ_ASSERT(trackedOptimizationsMapSize_ == 0); @@ -848,57 +848,15 @@ CodeGeneratorShared::generateCompactTrackedOptimizationsMap(JSContext *cx, JitCo data, data + trackedOptimizationsMapSize_, trackedOptimizationsMapSize_); JitSpew(JitSpew_OptimizationTracking, " with type list of length %u, size %u", - allTypes->length(), allTypes->length() * sizeof(IonTrackedTypeWithAddendum)); + allTypes->length(), allTypes->length() * sizeof(types::Type)); return true; } -#ifdef DEBUG -// Since this is a DEBUG-only verification, crash on OOM in the forEach ops -// below. - -class ReadTempAttemptsVectorOp : public JS::ForEachTrackedOptimizationAttemptOp -{ - TempOptimizationAttemptsVector *attempts_; - - public: - explicit ReadTempAttemptsVectorOp(TempOptimizationAttemptsVector *attempts) - : attempts_(attempts) - { } - - void operator()(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome) MOZ_OVERRIDE { - MOZ_ALWAYS_TRUE(attempts_->append(OptimizationAttempt(strategy, outcome))); - } -}; - -struct ReadTempTypeInfoVectorOp : public IonTrackedOptimizationsTypeInfo::ForEachOp -{ - TempOptimizationTypeInfoVector *types_; - types::TypeSet::TypeList accTypes_; - - public: - explicit ReadTempTypeInfoVectorOp(TempOptimizationTypeInfoVector *types) - : types_(types) - { } - - void readType(const IonTrackedTypeWithAddendum &tracked) MOZ_OVERRIDE { - MOZ_ALWAYS_TRUE(accTypes_.append(tracked.type)); - } - - void operator()(JS::TrackedTypeSite site, MIRType mirType) MOZ_OVERRIDE { - OptimizationTypeInfo ty(site, mirType); - for (uint32_t i = 0; i < accTypes_.length(); i++) - MOZ_ALWAYS_TRUE(ty.trackType(accTypes_[i])); - MOZ_ALWAYS_TRUE(types_->append(mozilla::Move(ty))); - accTypes_.clear(); - } -}; -#endif // DEBUG - void CodeGeneratorShared::verifyCompactTrackedOptimizationsMap(JitCode *code, uint32_t numRegions, const UniqueTrackedOptimizations &unique, - const IonTrackedTypeVector *allTypes) + const types::TypeSet::TypeList *allTypes) { #ifdef DEBUG MOZ_ASSERT(trackedOptimizationsMap_ != nullptr); @@ -954,18 +912,16 @@ CodeGeneratorShared::verifyCompactTrackedOptimizationsMap(JitCode *code, uint32_ MOZ_ASSERT(endOffset == entry.endOffset.offset()); MOZ_ASSERT(index == unique.indexOf(entry.optimizations)); - // Assert that the type info and attempts vectors are correctly - // decoded. + // Assert that the type info and attempts vector are correctly + // decoded. Since this is a DEBUG-only verification, crash on OOM. IonTrackedOptimizationsTypeInfo typeInfo = typesTable->entry(index); - TempOptimizationTypeInfoVector tvec(alloc()); - ReadTempTypeInfoVectorOp top(&tvec); - typeInfo.forEach(top, allTypes); + TempTrackedTypeInfoVector tvec(alloc()); + MOZ_ALWAYS_TRUE(typeInfo.readVector(&tvec, allTypes)); MOZ_ASSERT(entry.optimizations->matchTypes(tvec)); IonTrackedOptimizationsAttempts attempts = attemptsTable->entry(index); - TempOptimizationAttemptsVector avec(alloc()); - ReadTempAttemptsVectorOp aop(&avec); - attempts.forEach(aop); + TempAttemptsVector avec(alloc()); + MOZ_ALWAYS_TRUE(attempts.readVector(&avec)); MOZ_ASSERT(entry.optimizations->matchAttempts(avec)); } } diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 604642bae38b..12d2354de561 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -14,7 +14,6 @@ #include "jit/MacroAssembler.h" #include "jit/MIRGenerator.h" #include "jit/MIRGraph.h" -#include "jit/OptimizationTracking.h" #include "jit/Safepoints.h" #include "jit/Snapshots.h" #include "jit/VMFunctions.h" @@ -26,6 +25,7 @@ class OutOfLineCode; class CodeGenerator; class MacroAssembler; class IonCache; +class UniqueTrackedOptimizations; template class OutOfLineCallVM; @@ -48,17 +48,6 @@ struct ReciprocalMulConstants { int32_t shiftAmount; }; -// This should be nested in CodeGeneratorShared, but it is used in -// optimization tracking implementation and nested classes cannot be -// forward-declared. -struct NativeToTrackedOptimizations -{ - // [startOffset, endOffset] - CodeOffsetLabel startOffset; - CodeOffsetLabel endOffset; - const TrackedOptimizations *optimizations; -}; - class CodeGeneratorShared : public LElementVisitor { js::Vector outOfLineCode_; @@ -126,6 +115,15 @@ class CodeGeneratorShared : public LElementVisitor return gen->isProfilerInstrumentationEnabled(); } + public: + struct NativeToTrackedOptimizations { + // [startOffset, endOffset) + CodeOffsetLabel startOffset; + CodeOffsetLabel endOffset; + const TrackedOptimizations *optimizations; + }; + + protected: js::Vector trackedOptimizations_; uint8_t *trackedOptimizationsMap_; uint32_t trackedOptimizationsMapSize_; @@ -340,10 +338,10 @@ class CodeGeneratorShared : public LElementVisitor void verifyCompactNativeToBytecodeMap(JitCode *code); bool generateCompactTrackedOptimizationsMap(JSContext *cx, JitCode *code, - IonTrackedTypeVector *allTypes); + types::TypeSet::TypeList *allTypes); void verifyCompactTrackedOptimizationsMap(JitCode *code, uint32_t numRegions, const UniqueTrackedOptimizations &unique, - const IonTrackedTypeVector *allTypes); + const types::TypeSet::TypeList *allTypes); // Mark the safepoint on |ins| as corresponding to the current assembler location. // The location should be just after a call. diff --git a/js/src/jsapi-tests/testIntTypesABI.cpp b/js/src/jsapi-tests/testIntTypesABI.cpp index 066e7ad1b829..b868fb5d3551 100644 --- a/js/src/jsapi-tests/testIntTypesABI.cpp +++ b/js/src/jsapi-tests/testIntTypesABI.cpp @@ -31,7 +31,6 @@ #include "js/SliceBudget.h" #include "js/StructuredClone.h" #include "js/TracingAPI.h" -#include "js/TrackedOptimizationInfo.h" #include "js/TypeDecls.h" #include "js/UbiNode.h" #include "js/Utility.h" diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 46b9bc70c841..6a7110915957 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -304,10 +304,6 @@ class ExclusiveContext : public ContextFriendFields, types::ObjectGroup *getNewGroup(const Class *clasp, TaggedProto proto, JSObject *associated = nullptr); types::ObjectGroup *getLazySingletonGroup(const Class *clasp, TaggedProto proto); - - // Returns false if not found. - bool findAllocationSiteForType(types::Type ty, JSScript **script, uint32_t *offset) const; - inline js::LifoAlloc &typeLifoAlloc(); // Current global. This is only safe to use within the scope of the diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index bf61065b1956..8c89765f0b8a 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -97,38 +97,6 @@ types::TypeIdStringImpl(jsid id) // Logging ///////////////////////////////////////////////////////////////////// -const char * -types::NonObjectTypeString(Type type) -{ - if (type.isPrimitive()) { - switch (type.primitive()) { - case JSVAL_TYPE_UNDEFINED: - return "void"; - case JSVAL_TYPE_NULL: - return "null"; - case JSVAL_TYPE_BOOLEAN: - return "bool"; - case JSVAL_TYPE_INT32: - return "int"; - case JSVAL_TYPE_DOUBLE: - return "float"; - case JSVAL_TYPE_STRING: - return "string"; - case JSVAL_TYPE_SYMBOL: - return "symbol"; - case JSVAL_TYPE_MAGIC: - return "lazyargs"; - default: - MOZ_CRASH("Bad type"); - } - } - if (type.isUnknown()) - return "unknown"; - - MOZ_ASSERT(type.isAnyObject()); - return "object"; -} - #ifdef DEBUG static bool InferSpewActive(SpewChannel channel) @@ -204,8 +172,32 @@ types::InferSpewColor(TypeSet *types) const char * types::TypeString(Type type) { - if (type.isPrimitive() || type.isUnknown() || type.isAnyObject()) - return NonObjectTypeString(type); + if (type.isPrimitive()) { + switch (type.primitive()) { + case JSVAL_TYPE_UNDEFINED: + return "void"; + case JSVAL_TYPE_NULL: + return "null"; + case JSVAL_TYPE_BOOLEAN: + return "bool"; + case JSVAL_TYPE_INT32: + return "int"; + case JSVAL_TYPE_DOUBLE: + return "float"; + case JSVAL_TYPE_STRING: + return "string"; + case JSVAL_TYPE_SYMBOL: + return "symbol"; + case JSVAL_TYPE_MAGIC: + return "lazyargs"; + default: + MOZ_CRASH("Bad type"); + } + } + if (type.isUnknown()) + return "unknown"; + if (type.isAnyObject()) + return " object"; static char bufs[4][40]; static unsigned which = 0; @@ -4718,30 +4710,6 @@ ExclusiveContext::getLazySingletonGroup(const Class *clasp, TaggedProto proto) return group; } -bool -ExclusiveContext::findAllocationSiteForType(Type type, JSScript **script, uint32_t *offset) const -{ - *script = nullptr; - *offset = 0; - - if (type.isUnknown() || type.isAnyObject() || !type.isGroup()) - return false; - ObjectGroup *obj = type.group(); - - const AllocationSiteTable *table = compartment()->types.allocationSiteTable; - if (!table) - return false; - - for (AllocationSiteTable::Range r = table->all(); !r.empty(); r.popFront()) { - if (obj == r.front().value()) { - *script = r.front().key().script; - *offset = r.front().key().offset; - return true; - } - } - return false; -} - ///////////////////////////////////////////////////////////////////// // Tracing ///////////////////////////////////////////////////////////////////// diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 406e12a3a21c..efe240c1ca00 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -1790,8 +1790,6 @@ enum SpewChannel { SPEW_COUNT }; -const char *NonObjectTypeString(Type type); - #ifdef DEBUG const char * InferSpewColorReset(); diff --git a/js/src/moz.build b/js/src/moz.build index 239c858519b9..5a988b668a5d 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -84,7 +84,6 @@ EXPORTS.js += [ '../public/SliceBudget.h', '../public/StructuredClone.h', '../public/TracingAPI.h', - '../public/TrackedOptimizationInfo.h', '../public/TypeDecls.h', '../public/UbiNode.h', '../public/UbiNodeTraverse.h',