#include "config.h"
#include "TypeProfiler.h"
#include "InspectorProtocolObjects.h"
#include "TypeLocation.h"
#include <wtf/text/StringBuilder.h>
namespace JSC {
namespace TypeProfilerInternal {
static const bool verbose = false;
}
TypeProfiler::TypeProfiler()
: m_nextUniqueVariableID(1)
{
}
void TypeProfiler::logTypesForTypeLocation(TypeLocation* location, VM& vm)
{
TypeProfilerSearchDescriptor descriptor = location->m_globalVariableID == TypeProfilerReturnStatement ? TypeProfilerSearchDescriptorFunctionReturn : TypeProfilerSearchDescriptorNormal;
dataLogF("[Start, End]::[%u, %u]\n", location->m_divotStart, location->m_divotEnd);
if (findLocation(location->m_divotStart, location->m_sourceID, descriptor, vm))
dataLog("\t\t[Entry IS in System]\n");
else
dataLog("\t\t[Entry IS NOT in system]\n");
dataLog("\t\t", location->m_globalVariableID == TypeProfilerReturnStatement ? "[Return Statement]" : "[Normal Statement]", "\n");
dataLog("\t\t#Local#\n\t\t", location->m_instructionTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n");
if (location->m_globalTypeSet)
dataLog("\t\t#Global#\n\t\t", location->m_globalTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n");
}
void TypeProfiler::insertNewLocation(TypeLocation* location)
{
if (TypeProfilerInternal::verbose)
dataLogF("Registering location:: divotStart:%u, divotEnd:%u\n", location->m_divotStart, location->m_divotEnd);
if (!m_bucketMap.contains(location->m_sourceID)) {
Vector<TypeLocation*> bucket;
m_bucketMap.set(location->m_sourceID, bucket);
}
Vector<TypeLocation*>& bucket = m_bucketMap.find(location->m_sourceID)->value;
bucket.append(location);
}
String TypeProfiler::typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptor descriptor, unsigned offset, intptr_t sourceID, VM& vm)
{
TypeLocation* location = findLocation(offset, sourceID, descriptor, vm);
ASSERT(location);
StringBuilder json;
json.append('{');
json.appendLiteral("\"globalTypeSet\":");
if (location->m_globalTypeSet && location->m_globalVariableID != TypeProfilerNoGlobalIDExists)
json.append(location->m_globalTypeSet->toJSONString());
else
json.appendLiteral("null");
json.append(',');
json.appendLiteral("\"instructionTypeSet\":");
json.append(location->m_instructionTypeSet->toJSONString());
json.append(',');
json.appendLiteral("\"isOverflown\":");
if (location->m_instructionTypeSet->isOverflown() || (location->m_globalTypeSet && location->m_globalTypeSet->isOverflown()))
json.appendLiteral("true");
else
json.appendLiteral("false");
json.append('}');
return json.toString();
}
TypeLocation* TypeProfiler::findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor descriptor, VM& vm)
{
QueryKey queryKey(sourceID, divot, descriptor);
auto iter = m_queryCache.find(queryKey);
if (iter != m_queryCache.end())
return iter->value;
if (!vm.functionHasExecutedCache()->hasExecutedAtOffset(sourceID, divot))
return nullptr;
if (!m_bucketMap.contains(sourceID))
return nullptr;
Vector<TypeLocation*>& bucket = m_bucketMap.find(sourceID)->value;
TypeLocation* bestMatch = nullptr;
unsigned distance = UINT_MAX; for (auto* location : bucket) {
if (descriptor == TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID == TypeProfilerReturnStatement && location->m_divotForFunctionOffsetIfReturnStatement == divot)
return location;
if (descriptor != TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID != TypeProfilerReturnStatement && location->m_divotStart <= divot && divot <= location->m_divotEnd && location->m_divotEnd - location->m_divotStart <= distance) {
distance = location->m_divotEnd - location->m_divotStart;
bestMatch = location;
}
}
if (bestMatch)
m_queryCache.set(queryKey, bestMatch);
return bestMatch;
}
TypeLocation* TypeProfiler::nextTypeLocation()
{
return m_typeLocationInfo.add();
}
void TypeProfiler::invalidateTypeSetCache()
{
for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
TypeLocation* location = *iter;
location->m_instructionTypeSet->invalidateCache();
if (location->m_globalTypeSet)
location->m_globalTypeSet->invalidateCache();
}
}
void TypeProfiler::dumpTypeProfilerData(VM& vm)
{
for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
TypeLocation* location = *iter;
logTypesForTypeLocation(location, vm);
}
}
}