Bug 1030389 - Instrumentation: Track IonBuilder::jsop_getprop optimization. (r=djvj)

This commit is contained in:
Shu-yu Guo 2015-01-28 19:01:02 -08:00
Родитель 04979e9c13
Коммит cce7d4e2aa
2 изменённых файлов: 232 добавлений и 74 удалений

Просмотреть файл

@ -359,16 +359,20 @@ IonBuilder::DontInline(JSScript *targetScript, const char *reason)
IonBuilder::InliningDecision
IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo)
{
if (!optimizationInfo().inlineInterpreted())
if (!optimizationInfo().inlineInterpreted()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
return InliningDecision_DontInline;
}
if (TraceLogTextIdEnabled(TraceLogger_InlinedScripts)) {
return DontInline(nullptr, "Tracelogging of inlined scripts is enabled"
"but Tracelogger cannot do that yet.");
}
if (!target->isInterpreted())
if (!target->isInterpreted()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNotInterpreted);
return DontInline(nullptr, "Non-interpreted target");
}
// Allow constructing lazy scripts when performing the definite properties
// analysis, as baseline has not been used to warm the caller up yet.
@ -381,58 +385,84 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo)
MethodStatus status = BaselineCompile(analysisContext, script);
if (status == Method_Error)
return InliningDecision_Error;
if (status != Method_Compiled)
if (status != Method_Compiled) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNoBaseline);
return InliningDecision_DontInline;
}
}
}
if (!target->hasScript())
if (!target->hasScript()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineLazy);
return DontInline(nullptr, "Lazy script");
}
JSScript *inlineScript = target->nonLazyScript();
if (callInfo.constructing() && !target->isInterpretedConstructor())
if (callInfo.constructing() && !target->isInterpretedConstructor()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNotConstructor);
return DontInline(inlineScript, "Callee is not a constructor");
}
AnalysisMode analysisMode = info().analysisMode();
if (!CanIonCompile(inlineScript, analysisMode))
if (!CanIonCompile(inlineScript, analysisMode)) {
trackOptimizationOutcome(TrackedOutcome::CantInlineDisabledIon);
return DontInline(inlineScript, "Disabled Ion compilation");
}
// Don't inline functions which don't have baseline scripts.
if (!inlineScript->hasBaselineScript())
if (!inlineScript->hasBaselineScript()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNoBaseline);
return DontInline(inlineScript, "No baseline jitcode");
}
if (TooManyFormalArguments(target->nargs()))
if (TooManyFormalArguments(target->nargs())) {
trackOptimizationOutcome(TrackedOutcome::CantInlineTooManyArgs);
return DontInline(inlineScript, "Too many args");
}
// We check the number of actual arguments against the maximum number of
// formal arguments as we do not want to encode all actual arguments in the
// callerResumePoint.
if (TooManyFormalArguments(callInfo.argc()))
if (TooManyFormalArguments(callInfo.argc())) {
trackOptimizationOutcome(TrackedOutcome::CantInlineTooManyArgs);
return DontInline(inlineScript, "Too many actual args");
}
// Allow inlining of recursive calls, but only one level deep.
IonBuilder *builder = callerBuilder_;
while (builder) {
if (builder->script() == inlineScript)
if (builder->script() == inlineScript) {
trackOptimizationOutcome(TrackedOutcome::CantInlineRecursive);
return DontInline(inlineScript, "Recursive call");
}
builder = builder->callerBuilder_;
}
if (target->isHeavyweight())
if (target->isHeavyweight()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineHeavyweight);
return DontInline(inlineScript, "Heavyweight function");
}
if (inlineScript->uninlineable())
if (inlineScript->uninlineable()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
return DontInline(inlineScript, "Uninlineable script");
}
if (inlineScript->needsArgsObj())
if (inlineScript->needsArgsObj()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNeedsArgsObj);
return DontInline(inlineScript, "Script that needs an arguments object");
}
if (inlineScript->isDebuggee())
if (inlineScript->isDebuggee()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineDebuggee);
return DontInline(inlineScript, "Script is debuggee");
}
types::TypeObjectKey *targetType = types::TypeObjectKey::get(target);
if (targetType->unknownProperties())
if (targetType->unknownProperties()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineUnknownProps);
return DontInline(inlineScript, "Target type has unknown properties");
}
return InliningDecision_Inline;
}
@ -4575,8 +4605,10 @@ IonBuilder::InliningDecision
IonBuilder::makeInliningDecision(JSObject *targetArg, CallInfo &callInfo)
{
// When there is no target, inlining is impossible.
if (targetArg == nullptr)
if (targetArg == nullptr) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNoTarget);
return InliningDecision_DontInline;
}
// Inlining non-function targets is handled by inlineNonFunctionCall().
if (!targetArg->is<JSFunction>())
@ -4604,11 +4636,15 @@ IonBuilder::makeInliningDecision(JSObject *targetArg, CallInfo &callInfo)
if (!targetScript->shouldInline()) {
// Cap the inlining depth.
if (js_JitOptions.isSmallFunction(targetScript)) {
if (inliningDepth_ >= optimizationInfo().smallFunctionMaxInlineDepth())
if (inliningDepth_ >= optimizationInfo().smallFunctionMaxInlineDepth()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
return DontInline(targetScript, "Vetoed: exceeding allowed inline depth");
}
} else {
if (inliningDepth_ >= optimizationInfo().maxInlineDepth())
if (inliningDepth_ >= optimizationInfo().maxInlineDepth()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
return DontInline(targetScript, "Vetoed: exceeding allowed inline depth");
}
if (targetScript->hasLoops()) {
// Currently, we are not inlining function which have loops because
@ -4635,19 +4671,25 @@ IonBuilder::makeInliningDecision(JSObject *targetArg, CallInfo &callInfo)
hasOpportunities = arg->isLambda() || arg->isConstantValue();
}
if (!hasOpportunities)
if (!hasOpportunities) {
trackOptimizationOutcome(TrackedOutcome::CantInlineBigLoop);
return DontInline(targetScript, "Vetoed: big function that contains a loop");
}
}
// Caller must not be excessively large.
if (script()->length() >= optimizationInfo().inliningMaxCallerBytecodeLength())
if (script()->length() >= optimizationInfo().inliningMaxCallerBytecodeLength()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineBigCaller);
return DontInline(targetScript, "Vetoed: caller excessively large");
}
}
// Callee must not be excessively large.
// This heuristic also applies to the callsite as a whole.
if (targetScript->length() > optimizationInfo().inlineMaxTotalBytecodeLength())
if (targetScript->length() > optimizationInfo().inlineMaxTotalBytecodeLength()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineBigCallee);
return DontInline(targetScript, "Vetoed: callee excessively large");
}
// Callee must have been called a few times to have somewhat stable
// type information, except for definite properties analysis,
@ -4656,6 +4698,7 @@ IonBuilder::makeInliningDecision(JSObject *targetArg, CallInfo &callInfo)
!targetScript->baselineScript()->ionCompiledOrInlined() &&
info().analysisMode() != Analysis_DefiniteProperties)
{
trackOptimizationOutcome(TrackedOutcome::CantInlineNotHot);
JitSpew(JitSpew_Inlining, "Cannot inline %s:%u: callee is insufficiently hot.",
targetScript->filename(), targetScript->lineno());
return InliningDecision_WarmUpCountTooLow;
@ -7715,6 +7758,7 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
return false;
}
trackOptimizationSuccess();
*emitted = true;
return true;
}
@ -8963,8 +9007,10 @@ IonBuilder::jsop_rest()
uint32_t
IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name)
{
if (!types || types->unknownObject())
if (!types || types->unknownObject()) {
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
return UINT32_MAX;
}
// Watch for types which the new script properties analysis has not been
// performed on yet. Normally this is done after a small number of the
@ -8985,6 +9031,7 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name)
if (types::TypeObject *typeObject = type->maybeType()) {
if (typeObject->newScript() && !typeObject->newScript()->analyzed()) {
addAbortedNewScriptPropertiesType(typeObject);
trackOptimizationOutcome(TrackedOutcome::NoAnalysisInfo);
return UINT32_MAX;
}
}
@ -8997,22 +9044,32 @@ IonBuilder::getDefiniteSlot(types::TemporaryTypeSet *types, PropertyName *name)
if (!type)
continue;
if (type->unknownProperties() || type->singleton())
if (type->unknownProperties()) {
trackOptimizationOutcome(TrackedOutcome::UnknownProperties);
return UINT32_MAX;
}
if (type->singleton()) {
trackOptimizationOutcome(TrackedOutcome::Singleton);
return UINT32_MAX;
}
types::HeapTypeSetKey property = type->property(NameToId(name));
if (!property.maybeTypes() ||
!property.maybeTypes()->definiteProperty() ||
property.nonData(constraints()))
{
trackOptimizationOutcome(TrackedOutcome::NotFixedSlot);
return UINT32_MAX;
}
uint32_t propertySlot = property.maybeTypes()->definiteSlot();
if (slot == UINT32_MAX)
if (slot == UINT32_MAX) {
slot = propertySlot;
else if (slot != propertySlot)
} else if (slot != propertySlot) {
trackOptimizationOutcome(TrackedOutcome::NotFixedSlot);
return UINT32_MAX;
}
}
return slot;
@ -9369,19 +9426,23 @@ bool
IonBuilder::jsop_getprop(PropertyName *name)
{
bool emitted = false;
startTrackingOptimizations();
MDefinition *obj = current->pop();
types::TemporaryTypeSet *types = bytecodeTypes(pc);
trackTypeInfo(TrackedTypeSite::Receiver, obj->type(), obj->resultTypeSet());
if (!info().isAnalysis()) {
// The calls below can abort compilation, so we only try this if we're
// not analyzing.
// Try to optimize arguments.length.
trackOptimizationAttempt(TrackedStrategy::GetProp_ArgumentsLength);
if (!getPropTryArgumentsLength(&emitted, obj) || emitted)
return emitted;
// Try to optimize arguments.callee.
trackOptimizationAttempt(TrackedStrategy::GetProp_ArgumentsCallee);
if (!getPropTryArgumentsCallee(&emitted, obj, name) || emitted)
return emitted;
}
@ -9390,9 +9451,12 @@ IonBuilder::jsop_getprop(PropertyName *name)
obj, name, types);
// Try to optimize to a specific constant.
trackOptimizationAttempt(TrackedStrategy::GetProp_InferredConstant);
if (barrier == BarrierKind::NoBarrier) {
if (!getPropTryInferredConstant(&emitted, obj, name, types) || emitted)
return emitted;
} else {
trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier);
}
// Always use a call if we are performing analysis and
@ -9400,6 +9464,14 @@ IonBuilder::jsop_getprop(PropertyName *name)
// analysis if there are no known types for this operation, as it will
// always invalidate when executing.
if (info().isAnalysis() || types->empty()) {
if (types->empty()) {
// Since no further optimizations will be tried, use the IC
// strategy, which would have been the last one to be tried, as a
// sentinel value for why everything failed.
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineCache);
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
}
MCallGetProperty *call = MCallGetProperty::New(alloc(), obj, name, *pc == JSOP_CALLPROP);
current->add(call);
@ -9417,30 +9489,37 @@ IonBuilder::jsop_getprop(PropertyName *name)
}
// Try to hardcode known constants.
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
if (!getPropTryConstant(&emitted, obj, name, types) || emitted)
return emitted;
// Try to emit loads from known binary data blocks
trackOptimizationAttempt(TrackedStrategy::GetProp_TypedObject);
if (!getPropTryTypedObject(&emitted, obj, name) || emitted)
return emitted;
// Try to emit loads from definite slots.
trackOptimizationAttempt(TrackedStrategy::GetProp_DefiniteSlot);
if (!getPropTryDefiniteSlot(&emitted, obj, name, barrier, types) || emitted)
return emitted;
// Try to inline a common property getter, or make a call.
trackOptimizationAttempt(TrackedStrategy::GetProp_CommonGetter);
if (!getPropTryCommonGetter(&emitted, obj, name, types) || emitted)
return emitted;
// Try to emit a monomorphic/polymorphic access based on baseline caches.
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineAccess);
if (!getPropTryInlineAccess(&emitted, obj, name, barrier, types) || emitted)
return emitted;
// Try to optimize accesses on outer window proxies, for example window.foo.
trackOptimizationAttempt(TrackedStrategy::GetProp_Innerize);
if (!getPropTryInnerize(&emitted, obj, name, types) || emitted)
return emitted;
// Try to emit a polymorphic cache.
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineCache);
if (!getPropTryCache(&emitted, obj, name, barrier, types) || emitted)
return emitted;
@ -9480,16 +9559,22 @@ IonBuilder::getPropTryInferredConstant(bool *emitted, MDefinition *obj, Property
// Need a result typeset to optimize.
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
if (!objTypes)
if (!objTypes) {
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
return true;
}
JSObject *singleton = objTypes->getSingleton();
if (!singleton)
if (!singleton) {
trackOptimizationOutcome(TrackedOutcome::NotSingleton);
return true;
}
types::TypeObjectKey *type = types::TypeObjectKey::get(singleton);
if (type->unknownProperties())
if (type->unknownProperties()) {
trackOptimizationOutcome(TrackedOutcome::UnknownProperties);
return true;
}
types::HeapTypeSetKey property = type->property(NameToId(name));
@ -9500,6 +9585,7 @@ IonBuilder::getPropTryInferredConstant(bool *emitted, MDefinition *obj, Property
if (!pushConstant(constantValue))
return false;
types->addType(types::GetValueType(constantValue), alloc_->lifoAlloc());
trackOptimizationSuccess();
*emitted = true;
}
@ -9520,6 +9606,7 @@ IonBuilder::getPropTryArgumentsLength(bool *emitted, MDefinition *obj)
if (JSOp(*pc) != JSOP_LENGTH)
return true;
trackOptimizationSuccess();
*emitted = true;
obj->setImplicitlyUsedUnchecked();
@ -9555,6 +9642,7 @@ IonBuilder::getPropTryArgumentsCallee(bool *emitted, MDefinition *obj, PropertyN
obj->setImplicitlyUsedUnchecked();
current->push(getCallee());
trackOptimizationSuccess();
*emitted = true;
return true;
}
@ -9564,9 +9652,12 @@ IonBuilder::getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *na
types::TemporaryTypeSet *types)
{
MOZ_ASSERT(*emitted == false);
JSObject *singleton = types ? types->getSingleton() : nullptr;
if (!singleton)
if (!singleton) {
trackOptimizationOutcome(TrackedOutcome::NotSingleton);
return true;
}
bool testObject, testString;
if (!testSingletonPropertyTypes(obj, singleton, name, &testObject, &testString))
@ -9583,6 +9674,7 @@ IonBuilder::getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *na
pushConstant(ObjectValue(*singleton));
trackOptimizationSuccess();
*emitted = true;
return true;
}
@ -9641,6 +9733,7 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedO
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
return true;
trackOptimizationSuccess();
*emitted = true;
LinearSum byteOffset(alloc());
@ -9662,6 +9755,7 @@ IonBuilder::getPropTryReferencePropOfTypedObject(bool *emitted, MDefinition *typ
if (globalType->hasFlags(constraints(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED))
return true;
trackOptimizationSuccess();
*emitted = true;
LinearSum byteOffset(alloc());
@ -9702,6 +9796,7 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, MDefinition *obj, PropertyName
BarrierKind barrier, types::TemporaryTypeSet *types)
{
MOZ_ASSERT(*emitted == false);
uint32_t slot = getDefiniteSlot(obj->resultTypeSet(), name);
if (slot == UINT32_MAX)
return true;
@ -9731,6 +9826,7 @@ IonBuilder::getPropTryDefiniteSlot(bool *emitted, MDefinition *obj, PropertyName
if (!pushTypeBarrier(load, types, barrier))
return false;
trackOptimizationSuccess();
*emitted = true;
return true;
}
@ -9792,6 +9888,7 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
if (!pushDOMTypeBarrier(get, types, commonGetter))
return false;
trackOptimizationOutcome(TrackedOutcome::DOM);
*emitted = true;
return true;
}
@ -9825,13 +9922,13 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
case InliningStatus_NotInlined:
break;
case InliningStatus_Inlined:
trackOptimizationOutcome(TrackedOutcome::Inlined);
*emitted = true;
return true;
}
}
// Inline if we can, otherwise, forget it and just generate a call.
bool inlineable = false;
if (commonGetter->isInterpreted()) {
InliningDecision decision = makeInliningDecision(commonGetter, callInfo);
switch (decision) {
@ -9841,18 +9938,22 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, MDefinition *obj, PropertyName
case InliningDecision_WarmUpCountTooLow:
break;
case InliningDecision_Inline:
inlineable = true;
break;
if (!inlineScriptedCall(callInfo, commonGetter))
return false;
trackOptimizationOutcome(TrackedOutcome::Inlined);
*emitted = true;
return true;
}
}
if (inlineable) {
if (!inlineScriptedCall(callInfo, commonGetter))
return false;
} else {
if (!makeCall(commonGetter, callInfo, false))
return false;
}
if (!makeCall(commonGetter, callInfo, false))
return false;
// If the getter could have been inlined, don't track success. The call to
// makeInliningDecision above would have tracked a specific reason why we
// couldn't inline.
if (!commonGetter->isInterpreted())
trackOptimizationSuccess();
*emitted = true;
return true;
@ -9907,15 +10008,25 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
BarrierKind barrier, types::TemporaryTypeSet *types)
{
MOZ_ASSERT(*emitted == false);
if (obj->type() != MIRType_Object)
if (obj->type() != MIRType_Object) {
trackOptimizationOutcome(TrackedOutcome::NotObject);
return true;
}
BaselineInspector::ShapeVector shapes(alloc());
if (!inspector->maybeShapesForPropertyOp(pc, shapes))
return false;
if (shapes.empty() || !CanInlinePropertyOpShapes(shapes))
if (shapes.empty()) {
trackOptimizationOutcome(TrackedOutcome::NoShapeInfo);
return true;
}
if (!CanInlinePropertyOpShapes(shapes)) {
trackOptimizationOutcome(TrackedOutcome::InDictionaryMode);
return true;
}
MIRType rvalType = types->getKnownMIRType();
if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType))
@ -9935,6 +10046,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
if (!loadSlot(obj, shape, rvalType, barrier, types))
return false;
trackOptimizationOutcome(TrackedOutcome::Monomorphic);
*emitted = true;
return true;
}
@ -9963,6 +10075,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
if (!loadSlot(obj, propShapes[0], rvalType, barrier, types))
return false;
trackOptimizationOutcome(TrackedOutcome::Polymorphic);
*emitted = true;
return true;
}
@ -9983,6 +10096,7 @@ IonBuilder::getPropTryInlineAccess(bool *emitted, MDefinition *obj, PropertyName
if (!pushTypeBarrier(load, types, barrier))
return false;
trackOptimizationOutcome(TrackedOutcome::Polymorphic);
*emitted = true;
return true;
}
@ -9997,8 +10111,10 @@ IonBuilder::getPropTryCache(bool *emitted, MDefinition *obj, PropertyName *name,
// that it can be safely unboxed to an object.
if (obj->type() != MIRType_Object) {
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types || !types->objectOrSentinel())
if (!types || !types->objectOrSentinel()) {
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
return true;
}
}
// Since getters have no guaranteed return values, we must barrier in order to be
@ -10058,6 +10174,7 @@ IonBuilder::getPropTryCache(bool *emitted, MDefinition *obj, PropertyName *name,
if (!pushTypeBarrier(load, types, barrier))
return false;
trackOptimizationSuccess();
*emitted = true;
return true;
}

Просмотреть файл

@ -44,37 +44,78 @@ namespace jit {
// 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") \
_(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") \
_(NotObject, \
"not definitely an object") \
_(NeedsTypeBarrier, \
"needs type barrier") \
_(InDictionaryMode, \
"object in dictionary mode") \
\
_(GenericSuccess, \
"success") \
_(Monomorphic, \
"monomorphic") \
_(Polymorphic, \
#define TRACKED_OUTCOME_LIST(_) \
_(GenericFailure, \
"failure") \
_(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") \
_(NotObject, \
"not definitely an object") \
_(NeedsTypeBarrier, \
"needs type barrier") \
_(InDictionaryMode, \
"object in dictionary mode") \
\
_(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") \
\
_(GenericSuccess, \
"success") \
_(Inlined, \
"inlined") \
_(DOM, \
"DOM") \
_(Monomorphic, \
"monomorphic") \
_(Polymorphic, \
"polymorphic")
#define TRACKED_TYPESITE_LIST(_) \