mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Backed out 3 changesets (bug 1128653, bug 1127156
) for static analysis bustage
CLOSED TREE Backed out changeset f1d372961125 (bug1127156
) Backed out changeset 66c90dec344b (bug1127156
) Backed out changeset 9fcc56bc052b (bug 1128653)
This commit is contained in:
parent
0381e3b0cc
commit
0eddfa1016
@ -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;
|
||||
|
||||
|
@ -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
|
@ -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_<IonTrackedTypeVector>();
|
||||
types::TypeSet::TypeList *allTypes = cx->new_<types::TypeSet::TypeList>();
|
||||
if (allTypes && generateCompactTrackedOptimizationsMap(cx, code, allTypes)) {
|
||||
const uint8_t *optsRegionTableAddr = trackedOptimizationsMap_ +
|
||||
trackedOptimizationsRegionTableOffset_;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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<uint8_t> trackedOptimizationIndexAtAddr(void *ptr);
|
||||
bool optimizationAttemptsAtAddr(void *ptr, mozilla::Maybe<AttemptsVector> &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<uint8_t> 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();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -24,10 +24,6 @@
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
|
||||
using JS::TrackedStrategy;
|
||||
using JS::TrackedOutcome;
|
||||
using JS::TrackedTypeSite;
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
|
@ -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<uint8_t>
|
||||
JitcodeGlobalEntry::IonEntry::trackedOptimizationIndexAtAddr(void *ptr)
|
||||
bool
|
||||
JitcodeGlobalEntry::IonEntry::optimizationAttemptsAtAddr(void *ptr,
|
||||
Maybe<AttemptsVector> &attempts)
|
||||
{
|
||||
MOZ_ASSERT(hasTrackedOptimizations());
|
||||
MOZ_ASSERT(!attempts);
|
||||
MOZ_ASSERT(containsPointer(ptr));
|
||||
uint32_t ptrOffset = ((uint8_t *) ptr) - ((uint8_t *) nativeStartAddr());
|
||||
Maybe<IonTrackedOptimizationsRegion> 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<uint8_t> 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<uint8_t>
|
||||
IonTrackedOptimizationsRegion::findIndex(uint32_t offset) const
|
||||
IonTrackedOptimizationsRegion::findAttemptsIndex(uint32_t offset) const
|
||||
{
|
||||
if (offset < startOffset_ || offset >= endOffset_)
|
||||
return Nothing();
|
||||
@ -507,12 +475,6 @@ IonTrackedOptimizationsRegion::findIndex(uint32_t offset) const
|
||||
Maybe<IonTrackedOptimizationsRegion>
|
||||
IonTrackedOptimizationsRegionTable::findRegion(uint32_t offset) const
|
||||
{
|
||||
// For two contiguous regions, e.g., [i, j] and [j, k], an offset exactly
|
||||
// at j will be associated with [i, j] instead of [j, k]. An offset
|
||||
// exactly at j is often a return address from a younger frame, which case
|
||||
// the next region, despite starting at j, has not yet logically started
|
||||
// execution.
|
||||
|
||||
static const uint32_t LINEAR_SEARCH_THRESHOLD = 8;
|
||||
uint32_t regions = numEntries();
|
||||
MOZ_ASSERT(regions > 0);
|
||||
@ -521,7 +483,7 @@ IonTrackedOptimizationsRegionTable::findRegion(uint32_t offset) const
|
||||
if (regions <= LINEAR_SEARCH_THRESHOLD) {
|
||||
for (uint32_t i = 0; i < regions; i++) {
|
||||
IonTrackedOptimizationsRegion region = entry(i);
|
||||
if (region.startOffset() <= offset && offset <= region.endOffset()) {
|
||||
if (region.startOffset() <= offset && offset < region.endOffset()) {
|
||||
return Some(entry(i));
|
||||
}
|
||||
}
|
||||
@ -538,7 +500,7 @@ IonTrackedOptimizationsRegionTable::findRegion(uint32_t offset) const
|
||||
if (offset < region.startOffset()) {
|
||||
// Entry is below mid.
|
||||
regions = step;
|
||||
} else if (offset > region.endOffset()) {
|
||||
} else if (offset >= region.endOffset()) {
|
||||
// Entry is above mid.
|
||||
i = mid;
|
||||
regions -= step;
|
||||
@ -587,7 +549,7 @@ OptimizationAttempt::writeCompact(CompactBufferWriter &writer) const
|
||||
}
|
||||
|
||||
bool
|
||||
OptimizationTypeInfo::writeCompact(CompactBufferWriter &writer,
|
||||
TrackedTypeInfo::writeCompact(CompactBufferWriter &writer,
|
||||
UniqueTrackedTypes &uniqueTypes) const
|
||||
{
|
||||
writer.writeUnsigned((uint32_t) site_);
|
||||
@ -741,14 +703,14 @@ IonTrackedOptimizationsRegion::WriteRun(CompactBufferWriter &writer,
|
||||
const UniqueTrackedOptimizations &unique)
|
||||
{
|
||||
// Write the header, which is the range that this whole run encompasses.
|
||||
JitSpew(JitSpew_OptimizationTracking, " Header: [%u, %u]",
|
||||
JitSpew(JitSpew_OptimizationTracking, " Header: [%u, %u)",
|
||||
start->startOffset.offset(), (end - 1)->endOffset.offset());
|
||||
writer.writeUnsigned(start->startOffset.offset());
|
||||
writer.writeUnsigned((end - 1)->endOffset.offset());
|
||||
|
||||
// Write the first entry of the run, which is not delta-encoded.
|
||||
JitSpew(JitSpew_OptimizationTracking,
|
||||
" [%6u, %6u] vector %3u, offset %4u",
|
||||
" [%6u, %6u) vector %3u, offset %4u",
|
||||
start->startOffset.offset(), start->endOffset.offset(),
|
||||
unique.indexOf(start->optimizations), writer.length());
|
||||
uint32_t prevEndOffset = start->endOffset.offset();
|
||||
@ -765,7 +727,7 @@ IonTrackedOptimizationsRegion::WriteRun(CompactBufferWriter &writer,
|
||||
uint8_t index = unique.indexOf(entry->optimizations);
|
||||
|
||||
JitSpew(JitSpew_OptimizationTracking,
|
||||
" [%6u, %6u] delta [+%5u, +%5u] vector %3u, offset %4u",
|
||||
" [%6u, %6u) delta [+%5u, +%5u) vector %3u, offset %4u",
|
||||
startOffset, endOffset, startDelta, length, index, writer.length());
|
||||
|
||||
WriteDelta(writer, startDelta, length, index);
|
||||
@ -779,6 +741,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<uint32_t, 16> &offsets,
|
||||
uint32_t *tableOffsetp)
|
||||
@ -813,50 +801,6 @@ WriteOffsetsTable(CompactBufferWriter &writer, const Vector<uint32_t, 16> &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 +810,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 +867,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 +891,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 +956,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 +970,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 +1029,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<JSFunction>() ? &obj->as<JSFunction>() : 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());
|
||||
}
|
||||
|
@ -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<OptimizationAttempt, 4, JitAllocPolicy> TempOptimizationAttemptsVector;
|
||||
typedef Vector<OptimizationAttempt, 4, JitAllocPolicy> TempAttemptsVector;
|
||||
typedef Vector<OptimizationAttempt, 4, SystemAllocPolicy> 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<OptimizationTypeInfo, 1, JitAllocPolicy> TempOptimizationTypeInfoVector;
|
||||
typedef Vector<TrackedTypeInfo, 1, JitAllocPolicy> TempTrackedTypeInfoVector;
|
||||
typedef Vector<TrackedTypeInfo, 1, SystemAllocPolicy> 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<SortEntry, 4> 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<Key, Entry, Key> 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<uint8_t> findIndex(uint32_t offset) const;
|
||||
mozilla::Maybe<uint8_t> 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 <class T>
|
||||
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;
|
||||
};
|
||||
|
||||
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<IonTrackedTypeWithAddendum, 1, SystemAllocPolicy> 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 <class T>
|
||||
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 <class Entry>
|
||||
@ -537,12 +763,12 @@ typedef IonTrackedOptimizationsOffsetsTable<IonTrackedOptimizationsTypeInfo>
|
||||
|
||||
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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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 ArgSeq, class StoreOutputTo>
|
||||
class OutOfLineCallVM;
|
||||
@ -48,16 +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 *, 0, SystemAllocPolicy> outOfLineCode_;
|
||||
@ -125,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<NativeToTrackedOptimizations, 0, SystemAllocPolicy> trackedOptimizations_;
|
||||
uint8_t *trackedOptimizationsMap_;
|
||||
uint32_t trackedOptimizationsMapSize_;
|
||||
@ -339,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.
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -1790,8 +1790,6 @@ enum SpewChannel {
|
||||
SPEW_COUNT
|
||||
};
|
||||
|
||||
const char *NonObjectTypeString(Type type);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
const char * InferSpewColorReset();
|
||||
|
@ -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',
|
||||
|
@ -1875,7 +1875,8 @@ JS::ProfilingFrameIterator::extractStack(Frame *frames, uint32_t offset, uint32_
|
||||
// Look up an entry for the return address.
|
||||
jit::JitcodeGlobalTable *table = rt_->jitRuntime()->getJitcodeGlobalTable();
|
||||
jit::JitcodeGlobalEntry entry;
|
||||
table->lookupInfallible(returnAddr, &entry, rt_);
|
||||
mozilla::DebugOnly<bool> result = table->lookup(returnAddr, &entry, rt_);
|
||||
MOZ_ASSERT(result);
|
||||
|
||||
MOZ_ASSERT(entry.isIon() || entry.isIonCache() || entry.isBaseline() || entry.isDummy());
|
||||
|
||||
@ -1897,25 +1898,7 @@ JS::ProfilingFrameIterator::extractStack(Frame *frames, uint32_t offset, uint32_
|
||||
frames[offset + i].returnAddress = returnAddr;
|
||||
frames[offset + i].activation = activation_;
|
||||
frames[offset + i].label = labels[i];
|
||||
frames[offset + i].hasTrackedOptimizations = false;
|
||||
frames[offset + i].trackedOptimizationIndex = 0;
|
||||
}
|
||||
|
||||
// Extract the index into the side table of optimization information and
|
||||
// store it on the youngest frame. All inlined frames will have the same
|
||||
// optimization information by virtue of sharing the JitcodeGlobalEntry,
|
||||
// but such information is only interpretable on the youngest frame.
|
||||
//
|
||||
// FIXMEshu: disabled until we can ensure the optimization info is live
|
||||
// when we write out the JSON stream of the profile.
|
||||
if (false && entry.hasTrackedOptimizations()) {
|
||||
mozilla::Maybe<uint8_t> index = entry.trackedOptimizationIndexAtAddr(returnAddr);
|
||||
if (index.isSome()) {
|
||||
frames[offset].hasTrackedOptimizations = true;
|
||||
frames[offset].trackedOptimizationIndex = index.value();
|
||||
}
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
|
@ -150,20 +150,6 @@ JSStreamWriter::Value(int aValue)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSStreamWriter::Value(unsigned aValue)
|
||||
{
|
||||
MOZ_ASSERT(!mNeedsName);
|
||||
if (mNeedsComma && mStack.Peek() == ARRAY) {
|
||||
mStream << ",";
|
||||
}
|
||||
mStream << aValue;
|
||||
mNeedsComma = true;
|
||||
if (mStack.Peek() == OBJECT) {
|
||||
mNeedsName = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JSStreamWriter::Value(double aValue)
|
||||
{
|
||||
|
@ -22,7 +22,6 @@ public:
|
||||
void EndArray();
|
||||
void Name(const char *name);
|
||||
void Value(int value);
|
||||
void Value(unsigned value);
|
||||
void Value(double value);
|
||||
void Value(const char *value, size_t valueLength);
|
||||
void Value(const char *value);
|
||||
|
@ -8,10 +8,7 @@
|
||||
#include "platform.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
// JS
|
||||
#include "jsapi.h"
|
||||
#include "js/TrackedOptimizationInfo.h"
|
||||
|
||||
// JSON
|
||||
#include "JSStreamWriter.h"
|
||||
@ -96,9 +93,8 @@ void ProfileEntry::log()
|
||||
// by looking through all the use points of TableTicker.cpp.
|
||||
// mTagMarker (ProfilerMarker*) m
|
||||
// mTagData (const char*) c,s
|
||||
// mTagPtr (void*) d,l,L,B (immediate backtrace), S(start-of-stack),
|
||||
// J (JIT code addr)
|
||||
// mTagInt (int) n,f,y,o (JIT optimization info index), T (thread id)
|
||||
// mTagPtr (void*) d,l,L,B (immediate backtrace), S(start-of-stack)
|
||||
// mTagInt (int) n,f,y,T (thread id)
|
||||
// mTagChar (char) h
|
||||
// mTagFloat (double) r,t,p,R (resident memory), U (unshared memory)
|
||||
switch (mTagName) {
|
||||
@ -106,9 +102,9 @@ void ProfileEntry::log()
|
||||
LOGF("%c \"%s\"", mTagName, mTagMarker->GetMarkerName()); break;
|
||||
case 'c': case 's':
|
||||
LOGF("%c \"%s\"", mTagName, mTagData); break;
|
||||
case 'd': case 'l': case 'L': case 'J': case 'B': case 'S':
|
||||
case 'd': case 'l': case 'L': case 'B': case 'S':
|
||||
LOGF("%c %p", mTagName, mTagPtr); break;
|
||||
case 'n': case 'f': case 'y': case 'o': case 'T':
|
||||
case 'n': case 'f': case 'y': case 'T':
|
||||
LOGF("%c %d", mTagName, mTagInt); break;
|
||||
case 'h':
|
||||
LOGF("%c \'%c\'", mTagName, mTagChar); break;
|
||||
@ -249,72 +245,7 @@ void ProfileBuffer::IterateTagsForThread(IterateTagsCallback aCallback, int aThr
|
||||
}
|
||||
}
|
||||
|
||||
class StreamOptimizationTypeInfoOp : public JS::ForEachTrackedOptimizationTypeInfoOp
|
||||
{
|
||||
JSStreamWriter& mWriter;
|
||||
bool mStartedTypeList;
|
||||
|
||||
public:
|
||||
explicit StreamOptimizationTypeInfoOp(JSStreamWriter& b)
|
||||
: mWriter(b)
|
||||
, mStartedTypeList(false)
|
||||
{ }
|
||||
|
||||
void readType(const char *keyedBy, const char *name,
|
||||
const char *location, unsigned lineno) MOZ_OVERRIDE {
|
||||
if (!mStartedTypeList) {
|
||||
mStartedTypeList = true;
|
||||
mWriter.BeginObject();
|
||||
mWriter.Name("types");
|
||||
mWriter.BeginArray();
|
||||
}
|
||||
|
||||
mWriter.BeginObject();
|
||||
mWriter.NameValue("keyedBy", keyedBy);
|
||||
mWriter.NameValue("name", name);
|
||||
if (location) {
|
||||
mWriter.NameValue("location", location);
|
||||
mWriter.NameValue("line", lineno);
|
||||
}
|
||||
mWriter.EndObject();
|
||||
}
|
||||
|
||||
void operator()(JS::TrackedTypeSite site, const char *mirType) MOZ_OVERRIDE {
|
||||
if (mStartedTypeList) {
|
||||
mWriter.EndArray();
|
||||
mStartedTypeList = false;
|
||||
} else {
|
||||
mWriter.BeginObject();
|
||||
}
|
||||
|
||||
mWriter.NameValue("site", JS::TrackedTypeSiteString(site));
|
||||
mWriter.NameValue("mirType", mirType);
|
||||
mWriter.EndObject();
|
||||
}
|
||||
};
|
||||
|
||||
class StreamOptimizationAttemptsOp : public JS::ForEachTrackedOptimizationAttemptOp
|
||||
{
|
||||
JSStreamWriter& mWriter;
|
||||
|
||||
public:
|
||||
explicit StreamOptimizationAttemptsOp(JSStreamWriter& b)
|
||||
: mWriter(b)
|
||||
{ }
|
||||
|
||||
void operator()(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome) MOZ_OVERRIDE {
|
||||
mWriter.BeginObject();
|
||||
{
|
||||
// Stringify the reasons for now; could stream enum values in the future
|
||||
// to save space.
|
||||
mWriter.NameValue("strategy", JS::TrackedStrategyString(strategy));
|
||||
mWriter.NameValue("outcome", JS::TrackedOutcomeString(outcome));
|
||||
}
|
||||
mWriter.EndObject();
|
||||
}
|
||||
};
|
||||
|
||||
void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JSRuntime* rt)
|
||||
void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId)
|
||||
{
|
||||
b.BeginArray();
|
||||
|
||||
@ -437,28 +368,6 @@ void ProfileBuffer::StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JS
|
||||
b.NameValue("category", mEntries[readAheadPos].mTagInt);
|
||||
incBy++;
|
||||
}
|
||||
readAheadPos = (framePos + incBy) % mEntrySize;
|
||||
if (readAheadPos != mWritePos &&
|
||||
mEntries[readAheadPos].mTagName == 'J') {
|
||||
void* pc = mEntries[readAheadPos].mTagPtr;
|
||||
incBy++;
|
||||
readAheadPos = (framePos + incBy) % mEntrySize;
|
||||
MOZ_ASSERT(readAheadPos != mWritePos &&
|
||||
mEntries[readAheadPos].mTagName == 'o');
|
||||
uint32_t index = mEntries[readAheadPos].mTagInt;
|
||||
|
||||
// TODOshu: cannot stream tracked optimization info if
|
||||
// the JS engine has already shut down when streaming.
|
||||
if (rt) {
|
||||
b.Name("opts");
|
||||
b.BeginArray();
|
||||
StreamOptimizationTypeInfoOp typeInfoOp(b);
|
||||
JS::ForEachTrackedOptimizationTypeInfo(rt, pc, index, typeInfoOp);
|
||||
StreamOptimizationAttemptsOp attemptOp(b);
|
||||
JS::ForEachTrackedOptimizationAttempt(rt, pc, index, attemptOp);
|
||||
b.EndArray();
|
||||
}
|
||||
}
|
||||
b.EndObject();
|
||||
}
|
||||
framePos = (framePos + incBy) % mEntrySize;
|
||||
@ -633,7 +542,7 @@ void ThreadProfile::StreamJSObject(JSStreamWriter& b)
|
||||
b.NameValue("tid", static_cast<int>(mThreadId));
|
||||
|
||||
b.Name("samples");
|
||||
mBuffer->StreamSamplesToJSObject(b, mThreadId, mPseudoStack->mRuntime);
|
||||
mBuffer->StreamSamplesToJSObject(b, mThreadId);
|
||||
|
||||
b.Name("markers");
|
||||
mBuffer->StreamMarkersToJSObject(b, mThreadId);
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
|
||||
void addTag(const ProfileEntry& aTag);
|
||||
void IterateTagsForThread(IterateTagsCallback aCallback, int aThreadId);
|
||||
void StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId, JSRuntime* rt);
|
||||
void StreamSamplesToJSObject(JSStreamWriter& b, int aThreadId);
|
||||
void StreamMarkersToJSObject(JSStreamWriter& b, int aThreadId);
|
||||
void DuplicateLastSample(int aThreadId);
|
||||
|
||||
@ -184,8 +184,6 @@ public:
|
||||
int64_t mRssMemory;
|
||||
int64_t mUssMemory;
|
||||
#endif
|
||||
|
||||
void StreamTrackedOptimizations(JSStreamWriter& b, void* addr, uint8_t index);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const ThreadProfile& profile);
|
||||
|
@ -582,16 +582,6 @@ void mergeStacksIntoProfile(ThreadProfile& aProfile, TickSample* aSample, Native
|
||||
if (jsStackAddr > nativeStackAddr) {
|
||||
MOZ_ASSERT(jsIndex >= 0);
|
||||
addDynamicTag(aProfile, 'c', jsFrames[jsIndex].label);
|
||||
|
||||
// Stringifying optimization information is delayed until streaming
|
||||
// time. To re-lookup the entry in the JitcodeGlobalTable, we need to
|
||||
// store both the the JIT code address ('J') and the tracked
|
||||
// optimization index ('o') in the circular buffer.
|
||||
if (jsFrames[jsIndex].hasTrackedOptimizations) {
|
||||
aProfile.addTag(ProfileEntry('J', jsFrames[jsIndex].returnAddress));
|
||||
aProfile.addTag(ProfileEntry('o', jsFrames[jsIndex].trackedOptimizationIndex));
|
||||
}
|
||||
|
||||
jsIndex--;
|
||||
continue;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user