Backed out 3 changesets (bug 1128653, bug 1127156) for static analysis bustage

CLOSED TREE

Backed out changeset f1d372961125 (bug 1127156)
Backed out changeset 66c90dec344b (bug 1127156)
Backed out changeset 9fcc56bc052b (bug 1128653)
This commit is contained in:
Phil Ringnalda 2015-02-03 19:45:54 -08:00
parent 0381e3b0cc
commit 0eddfa1016
22 changed files with 476 additions and 1032 deletions

View File

@ -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;

View File

@ -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

View File

@ -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_;

View File

@ -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:

View File

@ -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);
};

View File

@ -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();
}
};
/*

View File

@ -24,10 +24,6 @@
using mozilla::ArrayLength;
using JS::TrackedStrategy;
using JS::TrackedOutcome;
using JS::TrackedTypeSite;
namespace js {
namespace jit {

View File

@ -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());
}

View File

@ -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

View File

@ -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));
}
}

View File

@ -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.

View File

@ -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"

View File

@ -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

View File

@ -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
/////////////////////////////////////////////////////////////////////

View File

@ -1790,8 +1790,6 @@ enum SpewChannel {
SPEW_COUNT
};
const char *NonObjectTypeString(Type type);
#ifdef DEBUG
const char * InferSpewColorReset();

View File

@ -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',

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}