blob: d1bc6b31bb81a689c60b329aad327a24e2820fba [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "Backend.h"
#if ENABLE_NATIVE_CODEGEN
namespace Js
{
FunctionCodeGenJitTimeData::FunctionCodeGenJitTimeData(FunctionInfo *const functionInfo, EntryPointInfo *const entryPoint, Var globalThis, uint16 profiledIterations, bool isInlined) :
functionInfo(functionInfo), entryPointInfo(entryPoint), globalObjTypeSpecFldInfoCount(0), globalObjTypeSpecFldInfoArray(nullptr),
weakFuncRef(nullptr), inlinees(nullptr), inlineeCount(0), ldFldInlineeCount(0), isInlined(isInlined), isAggressiveInliningEnabled(false),
#ifdef FIELD_ACCESS_STATS
inlineCacheStats(nullptr),
#endif
next(nullptr),
ldFldInlinees(nullptr),
callbackInlinees(nullptr),
callApplyTargetInlinees(nullptr),
globalThisObject(globalThis),
profiledIterations(profiledIterations),
sharedPropertyGuards(nullptr),
sharedPropertyGuardCount(0)
{
}
FunctionCodeGenJitTimeData* FunctionCodeGenJitTimeData::New(Recycler* recycler, FunctionInfo *const functionInfo, EntryPointInfo *const entryPoint, bool isInlined)
{
Var globalThis = nullptr;
uint16 profiledIterations = 0;
FunctionProxy *proxy = functionInfo->GetFunctionProxy();
if (proxy && proxy->IsFunctionBody())
{
FunctionBody* functionBody = proxy->GetFunctionBody();
if (functionBody)
{
if (functionBody->GetByteCode())
{
globalThis = functionBody->GetScriptContext()->GetLibrary()->GetGlobalObject()->ToThis();
profiledIterations = functionBody->GetProfiledIterations();
}
DebugOnly(functionBody->LockDownCounters());
}
}
return RecyclerNew(recycler, FunctionCodeGenJitTimeData, functionInfo, entryPoint, globalThis, profiledIterations, isInlined);
}
uint16 FunctionCodeGenJitTimeData::GetProfiledIterations() const
{
return profiledIterations;
}
FunctionInfo *FunctionCodeGenJitTimeData::GetFunctionInfo() const
{
return this->functionInfo;
}
FunctionBody *FunctionCodeGenJitTimeData::GetFunctionBody() const
{
FunctionProxy *proxy = this->functionInfo->GetFunctionProxy();
return proxy && proxy->IsFunctionBody() ? proxy->GetFunctionBody() : nullptr;
}
Var FunctionCodeGenJitTimeData::GetGlobalThisObject() const
{
return this->globalThisObject;
}
bool FunctionCodeGenJitTimeData::IsPolymorphicCallSite(const ProfileId profiledCallSiteId) const
{
Assert(GetFunctionBody());
Assert(profiledCallSiteId < GetFunctionBody()->GetProfiledCallSiteCount());
return inlinees ? inlinees[profiledCallSiteId]->next != nullptr : false;
}
const FunctionCodeGenJitTimeData *FunctionCodeGenJitTimeData::GetInlinee(const ProfileId profiledCallSiteId) const
{
Assert(GetFunctionBody());
Assert(profiledCallSiteId < GetFunctionBody()->GetProfiledCallSiteCount());
return inlinees ? inlinees[profiledCallSiteId] : nullptr;
}
const FunctionCodeGenJitTimeData *FunctionCodeGenJitTimeData::GetJitTimeDataFromFunctionInfo(FunctionInfo *polyFunctionInfo) const
{
const FunctionCodeGenJitTimeData *next = this;
while (next && next->functionInfo != polyFunctionInfo)
{
next = next->next;
}
return next;
}
const FunctionCodeGenJitTimeData *FunctionCodeGenJitTimeData::GetLdFldInlinee(const InlineCacheIndex inlineCacheIndex) const
{
Assert(GetFunctionBody());
Assert(inlineCacheIndex < GetFunctionBody()->GetInlineCacheCount());
return ldFldInlinees ? ldFldInlinees[inlineCacheIndex] : nullptr;
}
const FunctionCodeGenJitTimeData * FunctionCodeGenJitTimeData::GetCallbackInlinee(const ProfileId profiledCallSiteId) const
{
Assert(GetFunctionBody());
Assert(profiledCallSiteId < GetFunctionBody()->GetProfiledCallSiteCount());
return callbackInlinees ? callbackInlinees[profiledCallSiteId] : nullptr;
}
const FunctionCodeGenJitTimeData * FunctionCodeGenJitTimeData::GetCallApplyTargetInlinee(const ProfileId callApplyCallSiteId) const
{
Assert(GetFunctionBody());
Assert(callApplyCallSiteId < GetFunctionBody()->GetProfiledCallApplyCallSiteCount());
return callApplyTargetInlinees ? callApplyTargetInlinees[callApplyCallSiteId] : nullptr;
}
FunctionCodeGenJitTimeData *FunctionCodeGenJitTimeData::AddInlinee(
Recycler *const recycler,
const ProfileId profiledCallSiteId,
FunctionInfo *const inlinee,
bool isInlined)
{
Assert(recycler);
const auto functionBody = GetFunctionBody();
Assert(functionBody);
Assert(profiledCallSiteId < functionBody->GetProfiledCallSiteCount());
Assert(inlinee);
if (!inlinees)
{
inlinees = RecyclerNewArrayZ(recycler, Field(FunctionCodeGenJitTimeData *), functionBody->GetProfiledCallSiteCount());
}
FunctionCodeGenJitTimeData *inlineeData = nullptr;
if (!inlinees[profiledCallSiteId])
{
inlineeData = FunctionCodeGenJitTimeData::New(recycler, inlinee, nullptr /* entryPoint */, isInlined);
inlinees[profiledCallSiteId] = inlineeData;
if (++inlineeCount == 0)
{
Js::Throw::OutOfMemory();
}
}
else
{
inlineeData = FunctionCodeGenJitTimeData::New(recycler, inlinee, nullptr /* entryPoint */, isInlined);
// This is polymorphic, chain the data.
inlineeData->next = inlinees[profiledCallSiteId];
inlinees[profiledCallSiteId] = inlineeData;
}
return inlineeData;
}
FunctionCodeGenJitTimeData *FunctionCodeGenJitTimeData::AddLdFldInlinee(
Recycler *const recycler,
const InlineCacheIndex inlineCacheIndex,
FunctionInfo *const inlinee)
{
Assert(recycler);
const auto functionBody = GetFunctionBody();
Assert(functionBody);
Assert(inlineCacheIndex < GetFunctionBody()->GetInlineCacheCount());
Assert(inlinee);
if (!ldFldInlinees)
{
ldFldInlinees = RecyclerNewArrayZ(recycler, Field(FunctionCodeGenJitTimeData*), GetFunctionBody()->GetInlineCacheCount());
}
const auto inlineeData = FunctionCodeGenJitTimeData::New(recycler, inlinee, nullptr);
Assert(!ldFldInlinees[inlineCacheIndex]);
ldFldInlinees[inlineCacheIndex] = inlineeData;
if (++ldFldInlineeCount == 0)
{
Js::Throw::OutOfMemory();
}
return inlineeData;
}
FunctionCodeGenJitTimeData * FunctionCodeGenJitTimeData::AddCallbackInlinee(
Recycler *const recycler,
const ProfileId profiledCallSiteId,
FunctionInfo *const inlinee)
{
Assert(recycler != nullptr);
FunctionBody * functionBody = GetFunctionBody();
Assert(functionBody != nullptr);
Assert(profiledCallSiteId < functionBody->GetProfiledCallSiteCount());
Assert(inlinee != nullptr);
if (!callbackInlinees)
{
callbackInlinees = RecyclerNewArrayZ(recycler, Field(FunctionCodeGenJitTimeData *), functionBody->GetProfiledCallSiteCount());
}
// Polymorphic arguments are not inlined.
Assert(callbackInlinees[profiledCallSiteId] == nullptr);
FunctionCodeGenJitTimeData * inlineeData = FunctionCodeGenJitTimeData::New(recycler, inlinee, nullptr /* entryPoint */, true /*isInlined*/);
callbackInlinees[profiledCallSiteId] = inlineeData;
return inlineeData;
}
FunctionCodeGenJitTimeData * FunctionCodeGenJitTimeData::AddCallApplyTargetInlinee(
Recycler *const recycler,
const ProfileId profiledCallSiteId,
const ProfileId callApplyCallSiteId,
FunctionInfo *const inlinee)
{
Assert(recycler != nullptr);
FunctionBody * functionBody = GetFunctionBody();
Assert(functionBody != nullptr);
Assert(profiledCallSiteId < functionBody->GetProfiledCallSiteCount());
Assert(callApplyCallSiteId < functionBody->GetProfiledCallApplyCallSiteCount());
Assert(inlinee != nullptr);
if (!callApplyTargetInlinees)
{
callApplyTargetInlinees = RecyclerNewArrayZ(recycler, Field(FunctionCodeGenJitTimeData *), functionBody->GetProfiledCallApplyCallSiteCount());
}
// Polymorphic call/apply targets are not inlined.
Assert(callApplyTargetInlinees[callApplyCallSiteId] == nullptr);
FunctionCodeGenJitTimeData * inlineeData = FunctionCodeGenJitTimeData::New(recycler, inlinee, nullptr /* entryPoint */, true /*isInlined*/);
callApplyTargetInlinees[callApplyCallSiteId] = inlineeData;
return inlineeData;
}
uint FunctionCodeGenJitTimeData::InlineeCount() const
{
return inlineeCount;
}
uint FunctionCodeGenJitTimeData::LdFldInlineeCount() const
{
return ldFldInlineeCount;
}
#ifdef FIELD_ACCESS_STATS
void FunctionCodeGenJitTimeData::EnsureInlineCacheStats(Recycler* recycler)
{
this->inlineCacheStats = RecyclerNew(recycler, FieldAccessStats);
}
void FunctionCodeGenJitTimeData::AddInlineeInlineCacheStats(FunctionCodeGenJitTimeData* inlineeJitTimeData)
{
Assert(this->inlineCacheStats != nullptr);
Assert(inlineeJitTimeData != nullptr && inlineeJitTimeData->inlineCacheStats != nullptr);
this->inlineCacheStats->Add(inlineeJitTimeData->inlineCacheStats);
}
#endif
}
#endif