Backed out changeset cde091bad9e8 (bug 1127156)

This commit is contained in:
Carsten "Tomcat" Book 2015-02-04 12:35:20 +01:00
parent 4e4e5bd4a6
commit f73cce7b91
16 changed files with 462 additions and 878 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();
@ -587,7 +555,7 @@ OptimizationAttempt::writeCompact(CompactBufferWriter &writer) const
}
bool
OptimizationTypeInfo::writeCompact(CompactBufferWriter &writer,
TrackedTypeInfo::writeCompact(CompactBufferWriter &writer,
UniqueTrackedTypes &uniqueTypes) const
{
writer.writeUnsigned((uint32_t) site_);
@ -779,6 +747,32 @@ IonTrackedOptimizationsRegion::WriteRun(CompactBufferWriter &writer,
return true;
}
TrackedTypeInfo::TrackedTypeInfo(CompactBufferReader &reader)
: site_(TrackedTypeSite(reader.readUnsigned())),
mirType_(MIRType(reader.readUnsigned()))
{
MOZ_ASSERT(site_ < TrackedTypeSite::Count);
}
bool
TrackedTypeInfo::readTypes(CompactBufferReader &reader, const types::TypeSet::TypeList *allTypes)
{
uint32_t length = reader.readUnsigned();
for (uint32_t i = 0; i < length; i++) {
if (!types_.append((*allTypes)[reader.readByte()]))
return false;
}
return true;
}
OptimizationAttempt::OptimizationAttempt(CompactBufferReader &reader)
: strategy_(TrackedStrategy(reader.readUnsigned())),
outcome_(TrackedOutcome(reader.readUnsigned()))
{
MOZ_ASSERT(strategy_ < TrackedStrategy::Count);
MOZ_ASSERT(outcome_ < TrackedOutcome::Count);
}
static bool
WriteOffsetsTable(CompactBufferWriter &writer, const Vector<uint32_t, 16> &offsets,
uint32_t *tableOffsetp)
@ -813,50 +807,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 +816,7 @@ jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &write
uint32_t *regionTableOffsetp,
uint32_t *typesTableOffsetp,
uint32_t *optimizationTableOffsetp,
IonTrackedTypeVector *allTypes)
types::TypeSet::TypeList *allTypes)
{
MOZ_ASSERT(unique.sorted());
@ -923,47 +873,23 @@ jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &write
return false;
for (const UniqueTrackedOptimizations::SortEntry *p = vec.begin(); p != vec.end(); p++) {
const TempOptimizationTypeInfoVector *v = p->types;
const TempTrackedTypeInfoVector *v = p->types;
JitSpew(JitSpew_OptimizationTracking, " Type info entry %u of length %u, offset %u",
p - vec.begin(), v->length(), writer.length());
SpewTempOptimizationTypeInfoVector(v, " ");
SpewTempTrackedTypeInfoVector(v, " ");
if (!offsets.append(writer.length()))
return false;
for (const OptimizationTypeInfo *t = v->begin(); t != v->end(); t++) {
for (const TrackedTypeInfo *t = v->begin(); t != v->end(); t++) {
if (!t->writeCompact(writer, uniqueTypes))
return false;
}
}
// Enumerate the unique types, and pull out any 'new' script constructor
// functions and allocation site information. We do this during linking
// instead of during profiling to avoid touching compartment tables during
// profiling. Additionally, TypeNewScript is subject to GC in the
// meantime.
types::TypeSet::TypeList uniqueTypeList;
if (!uniqueTypes.enumerate(&uniqueTypeList))
// Copy the unique type list into the outparam TypeList.
if (!uniqueTypes.enumerate(allTypes))
return false;
for (uint32_t i = 0; i < uniqueTypeList.length(); i++) {
types::Type ty = uniqueTypeList[i];
if (JSFunction *constructor = MaybeConstructorFromType(ty)) {
if (!allTypes->append(IonTrackedTypeWithAddendum(ty, constructor)))
return false;
SpewConstructor(ty, constructor);
} else {
JSScript *script;
uint32_t offset;
if (cx->findAllocationSiteForType(ty, &script, &offset)) {
if (!allTypes->append(IonTrackedTypeWithAddendum(ty, script, offset)))
return false;
SpewAllocationSite(ty, script, offset);
} else {
if (!allTypes->append(IonTrackedTypeWithAddendum(ty)))
return false;
}
}
}
if (!WriteOffsetsTable(writer, offsets, typesTableOffsetp))
return false;
@ -971,10 +897,10 @@ jit::WriteIonTrackedOptimizationsTable(JSContext *cx, CompactBufferWriter &write
// Write out attempts payloads.
for (const UniqueTrackedOptimizations::SortEntry *p = vec.begin(); p != vec.end(); p++) {
const TempOptimizationAttemptsVector *v = p->attempts;
const TempAttemptsVector *v = p->attempts;
JitSpew(JitSpew_OptimizationTracking, " Attempts entry %u of length %u, offset %u",
p - vec.begin(), v->length(), writer.length());
SpewTempOptimizationAttemptsVector(v, " ");
SpewTempAttemptsVector(v, " ");
if (!offsets.append(writer.length()))
return false;
@ -1036,7 +962,7 @@ IonBuilder::trackTypeInfoUnchecked(TrackedTypeSite kind, MIRType mirType,
{
BytecodeSite *site = current->trackedSite();
// OOMs are handled as if optimization tracking were turned off.
OptimizationTypeInfo typeInfo(kind, mirType);
TrackedTypeInfo typeInfo(kind, mirType);
if (!typeInfo.trackTypeSet(typeSet)) {
site->setOptimizations(nullptr);
return;
@ -1050,7 +976,7 @@ IonBuilder::trackTypeInfoUnchecked(TrackedTypeSite kind, JSObject *obj)
{
BytecodeSite *site = current->trackedSite();
// OOMs are handled as if optimization tracking were turned off.
OptimizationTypeInfo typeInfo(kind, MIRType_Object);
TrackedTypeInfo typeInfo(kind, MIRType_Object);
if (!typeInfo.trackType(types::Type::ObjectType(obj)))
return;
if (!site->optimizations()->trackTypeInfo(mozilla::Move(typeInfo)))
@ -1109,104 +1035,3 @@ IonBuilder::trackInlineSuccessUnchecked(InliningStatus status)
if (status == InliningStatus_Inlined)
trackOptimizationOutcome(TrackedOutcome::Inlined);
}
JS_PUBLIC_API(void)
JS::ForEachTrackedOptimizationAttempt(JSRuntime *rt, void *addr, uint8_t index,
ForEachTrackedOptimizationAttemptOp &op)
{
JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable();
JitcodeGlobalEntry entry;
table->lookupInfallible(addr, &entry, rt);
entry.trackedOptimizationAttempts(index).forEach(op);
}
static void
InterpretedFunctionFilenameAndLineNumber(JSFunction *fun, const char **filename, unsigned *lineno)
{
ScriptSource *source;
if (fun->hasScript()) {
source = fun->nonLazyScript()->maybeForwardedScriptSource();
*lineno = fun->nonLazyScript()->lineno();
} else {
source = fun->lazyScript()->maybeForwardedScriptSource();
*lineno = fun->lazyScript()->lineno();
}
*filename = source->introducerFilename();
}
static JSFunction *
InterpretedFunctionFromTrackedType(const IonTrackedTypeWithAddendum &tracked)
{
if (tracked.hasConstructor())
return tracked.constructor;
types::Type ty = tracked.type;
if (ty.isSingleton()) {
JSObject *obj = ty.singleton();
return obj->is<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;
};
explicit IonTrackedTypeWithAddendum(types::Type type)
: type(type),
hasAddendum(HasNothing)
{ }
IonTrackedTypeWithAddendum(types::Type type, JSScript *script, uint32_t offset)
: type(type),
hasAddendum(HasAllocationSite),
script(script),
offset(offset)
{ }
IonTrackedTypeWithAddendum(types::Type type, JSFunction *constructor)
: type(type),
hasAddendum(HasConstructor),
constructor(constructor)
{ }
bool hasAllocationSite() const { return hasAddendum == HasAllocationSite; }
bool hasConstructor() const { return hasAddendum == HasConstructor; }
};
typedef Vector<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,17 +48,6 @@ struct ReciprocalMulConstants {
int32_t shiftAmount;
};
// This should be nested in CodeGeneratorShared, but it is used in
// optimization tracking implementation and nested classes cannot be
// forward-declared.
struct NativeToTrackedOptimizations
{
// [startOffset, endOffset]
CodeOffsetLabel startOffset;
CodeOffsetLabel endOffset;
const TrackedOptimizations *optimizations;
};
class CodeGeneratorShared : public LElementVisitor
{
js::Vector<OutOfLineCode *, 0, SystemAllocPolicy> outOfLineCode_;
@ -126,6 +115,15 @@ class CodeGeneratorShared : public LElementVisitor
return gen->isProfilerInstrumentationEnabled();
}
public:
struct NativeToTrackedOptimizations {
// [startOffset, endOffset)
CodeOffsetLabel startOffset;
CodeOffsetLabel endOffset;
const TrackedOptimizations *optimizations;
};
protected:
js::Vector<NativeToTrackedOptimizations, 0, SystemAllocPolicy> trackedOptimizations_;
uint8_t *trackedOptimizationsMap_;
uint32_t trackedOptimizationsMapSize_;
@ -340,10 +338,10 @@ class CodeGeneratorShared : public LElementVisitor
void verifyCompactNativeToBytecodeMap(JitCode *code);
bool generateCompactTrackedOptimizationsMap(JSContext *cx, JitCode *code,
IonTrackedTypeVector *allTypes);
types::TypeSet::TypeList *allTypes);
void verifyCompactTrackedOptimizationsMap(JitCode *code, uint32_t numRegions,
const UniqueTrackedOptimizations &unique,
const IonTrackedTypeVector *allTypes);
const types::TypeSet::TypeList *allTypes);
// Mark the safepoint on |ins| as corresponding to the current assembler location.
// The location should be just after a call.

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