164 lines
6.6 KiB
C++
164 lines
6.6 KiB
C++
/*
|
|
* Copyright (C) 2014-2019 Apple Inc. All Rights Reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "TypeProfiler.h"
|
|
|
|
#include "TypeLocation.h"
|
|
#include <wtf/text/StringBuilder.h>
|
|
|
|
namespace JSC {
|
|
|
|
namespace TypeProfilerInternal {
|
|
static constexpr 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)
|
|
{
|
|
// This returns a JSON string representing an Object with the following properties:
|
|
// globalTypeSet: 'JSON<TypeSet> | null'
|
|
// instructionTypeSet: 'JSON<TypeSet>'
|
|
|
|
TypeLocation* location = findLocation(offset, sourceID, descriptor, vm);
|
|
ASSERT(location);
|
|
|
|
StringBuilder json;
|
|
|
|
json.append('{');
|
|
|
|
json.append("\"globalTypeSet\":");
|
|
if (location->m_globalTypeSet && location->m_globalVariableID != TypeProfilerNoGlobalIDExists)
|
|
json.append(location->m_globalTypeSet->toJSONString());
|
|
else
|
|
json.append("null");
|
|
json.append(',');
|
|
|
|
json.append("\"instructionTypeSet\":", location->m_instructionTypeSet->toJSONString(), ',');
|
|
|
|
bool isOverflown = location->m_instructionTypeSet->isOverflown() || (location->m_globalTypeSet && location->m_globalTypeSet->isOverflown());
|
|
json.append("\"isOverflown\":", isOverflown ? "true" : "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; // Because assignments may be nested, make sure we find the closest enclosing assignment to this character offset.
|
|
for (auto* location : bucket) {
|
|
// We found the type location that correlates to the convergence of all return statements in a function.
|
|
// This text offset is the offset of the opening brace in a function declaration.
|
|
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);
|
|
// FIXME: BestMatch should never be null past this point. This doesn't hold currently because we ignore var assignments when code contains eval/With (VarInjection).
|
|
// https://bugs.webkit.org/show_bug.cgi?id=135184
|
|
return bestMatch;
|
|
}
|
|
|
|
TypeLocation* TypeProfiler::nextTypeLocation()
|
|
{
|
|
return m_typeLocationInfo.add();
|
|
}
|
|
|
|
void TypeProfiler::invalidateTypeSetCache(VM& vm)
|
|
{
|
|
for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
|
|
TypeLocation* location = *iter;
|
|
location->m_instructionTypeSet->invalidateCache(vm);
|
|
if (location->m_globalTypeSet)
|
|
location->m_globalTypeSet->invalidateCache(vm);
|
|
}
|
|
}
|
|
|
|
void TypeProfiler::dumpTypeProfilerData(VM& vm)
|
|
{
|
|
for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
|
|
TypeLocation* location = *iter;
|
|
logTypesForTypeLocation(location, vm);
|
|
}
|
|
}
|
|
|
|
} // namespace JSC
|