446 lines
15 KiB
C++
446 lines
15 KiB
C++
#include "il2cpp-config.h"
|
|
#include <vector>
|
|
#include <map>
|
|
#include <limits>
|
|
#include "os/Mutex.h"
|
|
#include "utils/StringUtils.h"
|
|
#include "vm/Array.h"
|
|
#include "vm/Class.h"
|
|
#include "vm/Image.h"
|
|
#include "vm/MetadataCache.h"
|
|
#include "vm/Reflection.h"
|
|
#include "vm/StackTrace.h"
|
|
#include "vm/Type.h"
|
|
#include "utils/HashUtils.h"
|
|
#include "utils/Il2CppHashMap.h"
|
|
#include "utils/MemoryMappedFile.h"
|
|
#include "utils/StringUtils.h"
|
|
#include "vm-utils/VmStringUtils.h"
|
|
|
|
#include "Baselib.h"
|
|
#include "Cpp/ReentrantLock.h"
|
|
|
|
struct NamespaceAndNamePairHash
|
|
{
|
|
size_t operator()(const std::pair<const char*, const char*>& pair) const
|
|
{
|
|
return il2cpp::utils::HashUtils::Combine(il2cpp::utils::StringUtils::Hash(pair.first), il2cpp::utils::StringUtils::Hash(pair.second));
|
|
}
|
|
};
|
|
|
|
struct NamespaceAndNamePairEquals
|
|
{
|
|
bool operator()(const std::pair<const char*, const char*>& p1, const std::pair<const char*, const char*>& p2) const
|
|
{
|
|
return !strcmp(p1.first, p2.first) && !strcmp(p1.second, p2.second);
|
|
}
|
|
};
|
|
|
|
struct NamespaceAndNamePairLess
|
|
{
|
|
bool operator()(const std::pair<const char*, const char*>& p1, const std::pair<const char*, const char*>& p2) const
|
|
{
|
|
int namespaceCompare = strcmp(p1.first, p2.first);
|
|
|
|
if (namespaceCompare < 0)
|
|
return true;
|
|
|
|
if (namespaceCompare > 0)
|
|
return false;
|
|
|
|
return strcmp(p1.second, p2.second) < 0;
|
|
}
|
|
};
|
|
|
|
struct Il2CppNameToTypeHandleHashTable : public Il2CppHashMap<std::pair<const char*, const char*>, Il2CppMetadataTypeHandle, NamespaceAndNamePairHash, NamespaceAndNamePairEquals>
|
|
{
|
|
typedef Il2CppHashMap<std::pair<const char*, const char*>, Il2CppMetadataTypeHandle, NamespaceAndNamePairHash, NamespaceAndNamePairEquals> Base;
|
|
Il2CppNameToTypeHandleHashTable() : Base()
|
|
{
|
|
}
|
|
};
|
|
|
|
namespace il2cpp
|
|
{
|
|
namespace vm
|
|
{
|
|
const Il2CppAssembly* Image::GetAssembly(const Il2CppImage* image)
|
|
{
|
|
return image->assembly;
|
|
}
|
|
|
|
typedef il2cpp::vm::StackFrames::const_reverse_iterator StackReverseIterator;
|
|
|
|
static bool IsSystemType(Il2CppClass* klass)
|
|
{
|
|
return strcmp(klass->namespaze, "System") == 0 && strcmp(klass->name, "Type") == 0;
|
|
}
|
|
|
|
static bool IsSystemReflectionAssembly(Il2CppClass* klass)
|
|
{
|
|
return strcmp(klass->namespaze, "System.Reflection") == 0 && strcmp(klass->name, "Assembly") == 0;
|
|
}
|
|
|
|
static StackReverseIterator GetNextImageFromStack(StackReverseIterator first, StackReverseIterator last)
|
|
{
|
|
for (StackReverseIterator it = first; it != last; it++)
|
|
{
|
|
Il2CppClass* klass = it->method->klass;
|
|
if (klass->image != NULL && !IsSystemType(klass) && !IsSystemReflectionAssembly(klass))
|
|
{
|
|
return it;
|
|
}
|
|
}
|
|
|
|
return last;
|
|
}
|
|
|
|
const Il2CppImage* Image::GetExecutingImage()
|
|
{
|
|
const il2cpp::vm::StackFrames& stack = *StackTrace::GetStackFrames();
|
|
StackReverseIterator imageIt = GetNextImageFromStack(stack.rbegin(), stack.rend());
|
|
|
|
if (imageIt != stack.rend())
|
|
{
|
|
return imageIt->method->klass->image;
|
|
}
|
|
|
|
// Fallback to corlib if no image is found
|
|
return const_cast<Il2CppImage*>(Image::GetCorlib());
|
|
}
|
|
|
|
const Il2CppImage* Image::GetCallingImage()
|
|
{
|
|
const il2cpp::vm::StackFrames& stack = *StackTrace::GetStackFrames();
|
|
StackReverseIterator imageIt = GetNextImageFromStack(stack.rbegin(), stack.rend());
|
|
|
|
if (imageIt != stack.rend())
|
|
{
|
|
imageIt = GetNextImageFromStack(++imageIt, stack.rend());
|
|
|
|
if (imageIt != stack.rend())
|
|
{
|
|
return imageIt->method->klass->image;
|
|
}
|
|
}
|
|
|
|
// Fallback to corlib if no image is found
|
|
return const_cast<Il2CppImage*>(Image::GetCorlib());
|
|
}
|
|
|
|
const char * Image::GetName(const Il2CppImage* image)
|
|
{
|
|
return image->name;
|
|
}
|
|
|
|
const char * Image::GetFileName(const Il2CppImage* image)
|
|
{
|
|
return image->name;
|
|
}
|
|
|
|
const MethodInfo* Image::GetEntryPoint(const Il2CppImage* image)
|
|
{
|
|
return MetadataCache::GetAssemblyEntryPoint(image);
|
|
}
|
|
|
|
Il2CppImage* Image::GetCorlib()
|
|
{
|
|
return il2cpp_defaults.corlib;
|
|
}
|
|
|
|
static baselib::ReentrantLock s_ClassFromNameMutex;
|
|
|
|
static void AddNestedTypesToNametoClassHashTable(Il2CppNameToTypeHandleHashTable* hashTable, const char *namespaze, const std::string& parentName, Il2CppMetadataTypeHandle handle)
|
|
{
|
|
std::pair<const char*, const char*> namespaceAndName = MetadataCache::GetTypeNamespaceAndName(handle);
|
|
|
|
std::string name = parentName + "/" + namespaceAndName.second;
|
|
char *pName = (char*)IL2CPP_CALLOC(name.size() + 1, sizeof(char));
|
|
strcpy(pName, name.c_str());
|
|
|
|
hashTable->insert(std::make_pair(std::make_pair(namespaze, (const char*)pName), handle));
|
|
|
|
void *iter = NULL;
|
|
while (Il2CppMetadataTypeHandle nestedClass = MetadataCache::GetNestedTypes(handle, &iter))
|
|
AddNestedTypesToNametoClassHashTable(hashTable, namespaze, name, nestedClass);
|
|
}
|
|
|
|
static void AddNestedTypesToNametoClassHashTable(const Il2CppImage* image, Il2CppMetadataTypeHandle handle)
|
|
{
|
|
std::pair<const char*, const char*> namespaceAndName = MetadataCache::GetTypeNamespaceAndName(handle);
|
|
|
|
void *iter = NULL;
|
|
while (Il2CppMetadataTypeHandle nestedClass = MetadataCache::GetNestedTypes(handle, &iter))
|
|
{
|
|
AddNestedTypesToNametoClassHashTable(image->nameToClassHashTable, namespaceAndName.first, namespaceAndName.second, nestedClass);
|
|
}
|
|
}
|
|
|
|
// This must be called when the s_ClassFromNameMutex is held.
|
|
static void AddTypeToNametoClassHashTable(const Il2CppImage* image, Il2CppMetadataTypeHandle typeHandle)
|
|
{
|
|
if (typeHandle == NULL)
|
|
return;
|
|
|
|
// don't add nested types
|
|
if (MetadataCache::TypeIsNested(typeHandle))
|
|
return;
|
|
|
|
if (image != il2cpp_defaults.corlib)
|
|
AddNestedTypesToNametoClassHashTable(image, typeHandle);
|
|
|
|
image->nameToClassHashTable->insert(std::make_pair(MetadataCache::GetTypeNamespaceAndName(typeHandle), typeHandle));
|
|
}
|
|
|
|
void Image::InitNestedTypes(const Il2CppImage *image)
|
|
{
|
|
for (uint32_t index = 0; index < image->typeCount; index++)
|
|
{
|
|
Il2CppMetadataTypeHandle handle = MetadataCache::GetAssemblyTypeHandle(image, index);
|
|
|
|
// don't add nested types
|
|
if (MetadataCache::TypeIsNested(handle))
|
|
return;
|
|
|
|
AddNestedTypesToNametoClassHashTable(image, handle);
|
|
}
|
|
|
|
for (uint32_t index = 0; index < image->exportedTypeCount; index++)
|
|
{
|
|
Il2CppMetadataTypeHandle handle = MetadataCache::GetAssemblyExportedTypeHandle(image, index);
|
|
|
|
// don't add nested types
|
|
if (MetadataCache::TypeIsNested(handle))
|
|
return;
|
|
|
|
AddNestedTypesToNametoClassHashTable(image, handle);
|
|
}
|
|
}
|
|
|
|
Il2CppClass* Image::ClassFromName(const Il2CppImage* image, const char* namespaze, const char *name)
|
|
{
|
|
if (!image->nameToClassHashTable)
|
|
{
|
|
os::FastAutoLock lock(&s_ClassFromNameMutex);
|
|
if (!image->nameToClassHashTable)
|
|
{
|
|
image->nameToClassHashTable = new Il2CppNameToTypeHandleHashTable();
|
|
for (uint32_t index = 0; index < image->typeCount; index++)
|
|
{
|
|
AddTypeToNametoClassHashTable(image, MetadataCache::GetAssemblyTypeHandle(image, index));
|
|
}
|
|
|
|
for (uint32_t index = 0; index < image->exportedTypeCount; index++)
|
|
{
|
|
AddTypeToNametoClassHashTable(image, MetadataCache::GetAssemblyExportedTypeHandle(image, index));
|
|
}
|
|
}
|
|
}
|
|
|
|
Il2CppNameToTypeHandleHashTable::const_iterator iter = image->nameToClassHashTable->find(std::make_pair(namespaze, name));
|
|
if (iter != image->nameToClassHashTable->end())
|
|
return MetadataCache::GetTypeInfoFromHandle(iter->second);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool IsExported(const Il2CppClass* type)
|
|
{
|
|
if ((type->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_PUBLIC)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ((type->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_NESTED_PUBLIC)
|
|
{
|
|
IL2CPP_ASSERT(type->declaringType);
|
|
return IsExported(type->declaringType);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Image::GetTypes(const Il2CppImage* image, bool exportedOnly, TypeVector* target)
|
|
{
|
|
uint32_t typeCount = Image::GetNumTypes(image);
|
|
target->reserve(typeCount);
|
|
|
|
for (uint32_t sourceIndex = 0; sourceIndex < typeCount; sourceIndex++)
|
|
{
|
|
const Il2CppClass* type = Image::GetType(image, sourceIndex);
|
|
if (strcmp(type->name, "<Module>") == 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (exportedOnly && !IsExported(type))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
target->push_back(type);
|
|
}
|
|
}
|
|
|
|
Il2CppArray* Image::GetTypes(const Il2CppImage* image, bool exportedOnly)
|
|
{
|
|
TypeVector types;
|
|
GetTypes(image, exportedOnly, &types);
|
|
Il2CppArray* result = Array::New(il2cpp_defaults.monotype_class, (il2cpp_array_size_t)types.size());
|
|
size_t index = 0;
|
|
for (vm::TypeVector::const_iterator type = types.begin(); type != types.end(); ++type)
|
|
{
|
|
Il2CppReflectionType* reflectionType = Reflection::GetTypeObject(&(*type)->byval_arg);
|
|
il2cpp_array_setref(result, index, reflectionType);
|
|
index++;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
uint32_t Image::GetNumTypes(const Il2CppImage* image)
|
|
{
|
|
return image->typeCount;
|
|
}
|
|
|
|
const Il2CppClass* Image::GetType(const Il2CppImage* image, AssemblyTypeIndex index)
|
|
{
|
|
IL2CPP_ASSERT(index <= std::numeric_limits<AssemblyTypeIndex>::max());
|
|
return MetadataCache::GetTypeInfoFromHandle(MetadataCache::GetAssemblyTypeHandle(image, index));
|
|
}
|
|
|
|
static bool StringsMatch(const char* left, const char* right, bool ignoreCase)
|
|
{
|
|
if (!ignoreCase)
|
|
{
|
|
return strcmp(left, right) == 0;
|
|
}
|
|
else
|
|
{
|
|
utils::VmStringUtils::CaseInsensitiveComparer comparer;
|
|
return comparer(left, right);
|
|
}
|
|
}
|
|
|
|
static bool ClassMatches(Il2CppMetadataTypeHandle typeHandle, const char* namespaze, bool ignoreCase, const char* name)
|
|
{
|
|
if (MetadataCache::TypeIsNested(typeHandle))
|
|
return false;
|
|
|
|
std::pair<const char*, const char*> namespaceAndName = MetadataCache::GetTypeNamespaceAndName(typeHandle);
|
|
return StringsMatch(name, namespaceAndName.second, ignoreCase) && StringsMatch(namespaze, namespaceAndName.first, ignoreCase);
|
|
}
|
|
|
|
static Il2CppClass* FindClassMatching(const Il2CppImage* image, const char* namespaze, const char *name, bool ignoreCase)
|
|
{
|
|
for (uint32_t i = 0; i < image->typeCount; i++)
|
|
{
|
|
Il2CppMetadataTypeHandle typeHandle = MetadataCache::GetAssemblyTypeHandle(image, i);
|
|
if (ClassMatches(typeHandle, namespaze, ignoreCase, name))
|
|
return MetadataCache::GetTypeInfoFromHandle(typeHandle);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static Il2CppClass* FindExportedClassMatching(const Il2CppImage* image, const char* namespaze, const char *name, bool ignoreCase)
|
|
{
|
|
for (uint32_t i = 0; i < image->exportedTypeCount; i++)
|
|
{
|
|
Il2CppMetadataTypeHandle typeHandle = MetadataCache::GetAssemblyExportedTypeHandle(image, i);
|
|
if (ClassMatches(typeHandle, namespaze, ignoreCase, name))
|
|
return MetadataCache::GetTypeInfoFromHandle(typeHandle);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static Il2CppClass* FindNestedType(Il2CppClass* klass, const char* name, bool ignoreCase)
|
|
{
|
|
void* iter = NULL;
|
|
while (Il2CppClass* nestedType = Class::GetNestedTypes(klass, &iter))
|
|
{
|
|
if (StringsMatch(name, nestedType->name, ignoreCase))
|
|
return nestedType;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Il2CppClass* Image::FromTypeNameParseInfo(const Il2CppImage* image, const TypeNameParseInfo &info, bool ignoreCase)
|
|
{
|
|
const char* ns = info.ns().c_str();
|
|
const char* name = info.name().c_str();
|
|
Il2CppClass *parent_class = FindClassMatching(image, ns, name, ignoreCase);
|
|
|
|
if (parent_class == NULL)
|
|
{
|
|
parent_class = FindExportedClassMatching(image, ns, name, ignoreCase);
|
|
if (parent_class == NULL)
|
|
return NULL;
|
|
}
|
|
|
|
std::vector<std::string>::const_iterator it = info.nested().begin();
|
|
|
|
while (it != info.nested().end())
|
|
{
|
|
parent_class = FindNestedType(parent_class, (*it).c_str(), ignoreCase);
|
|
|
|
if (parent_class == NULL)
|
|
return NULL;
|
|
|
|
++it;
|
|
}
|
|
|
|
return parent_class;
|
|
}
|
|
|
|
static baselib::ReentrantLock s_Mutex;
|
|
static std::vector<Image::EmbeddedResourceData> s_CachedResourceData;
|
|
static std::map<Il2CppReflectionAssembly*, void*> s_CachedMemoryMappedResourceFiles;
|
|
|
|
void Image::CacheMemoryMappedResourceFile(Il2CppReflectionAssembly* assembly, void* memoryMappedFile)
|
|
{
|
|
os::FastAutoLock lock(&s_Mutex);
|
|
s_CachedMemoryMappedResourceFiles[assembly] = memoryMappedFile;
|
|
}
|
|
|
|
void* Image::GetCachedMemoryMappedResourceFile(Il2CppReflectionAssembly* assembly)
|
|
{
|
|
os::FastAutoLock lock(&s_Mutex);
|
|
std::map<Il2CppReflectionAssembly*, void*>::iterator entry = s_CachedMemoryMappedResourceFiles.find(assembly);
|
|
if (entry != s_CachedMemoryMappedResourceFiles.end())
|
|
return entry->second;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void Image::CacheResourceData(EmbeddedResourceRecord record, void* data)
|
|
{
|
|
os::FastAutoLock lock(&s_Mutex);
|
|
s_CachedResourceData.push_back(EmbeddedResourceData(record, data));
|
|
}
|
|
|
|
void* Image::GetCachedResourceData(const Il2CppImage* image, const std::string& name)
|
|
{
|
|
os::FastAutoLock lock(&s_Mutex);
|
|
for (std::vector<EmbeddedResourceData>::iterator it = s_CachedResourceData.begin(); it != s_CachedResourceData.end(); ++it)
|
|
{
|
|
if (it->record.image == image && it->record.name == name)
|
|
return it->data;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void Image::ClearCachedResourceData()
|
|
{
|
|
os::FastAutoLock lock(&s_Mutex);
|
|
for (std::map<Il2CppReflectionAssembly*, void*>::iterator i = s_CachedMemoryMappedResourceFiles.begin(); i != s_CachedMemoryMappedResourceFiles.end(); ++i)
|
|
utils::MemoryMappedFile::Unmap(i->second);
|
|
|
|
s_CachedMemoryMappedResourceFiles.clear();
|
|
s_CachedResourceData.clear();
|
|
}
|
|
} /* namespace vm */
|
|
} /* namespace il2cpp */
|