255 lines
10 KiB
C++
255 lines
10 KiB
C++
#include "il2cpp-config.h"
|
|
#include "metadata/GenericMetadata.h"
|
|
#include "os/Atomic.h"
|
|
#include "os/Mutex.h"
|
|
#include "utils/Memory.h"
|
|
#include "vm/Class.h"
|
|
#include "vm/GenericClass.h"
|
|
#include "vm/Exception.h"
|
|
#include "vm/MetadataAlloc.h"
|
|
#include "vm/MetadataCache.h"
|
|
#include "vm/MetadataLock.h"
|
|
#include "il2cpp-class-internals.h"
|
|
#include "il2cpp-runtime-metadata.h"
|
|
#include "il2cpp-runtime-stats.h"
|
|
|
|
namespace il2cpp
|
|
{
|
|
namespace vm
|
|
{
|
|
void GenericClass::SetupMethods(Il2CppClass* genericInstanceType)
|
|
{
|
|
Il2CppClass* genericTypeDefinition = GenericClass::GetTypeDefinition(genericInstanceType->generic_class);
|
|
uint16_t methodCount = genericTypeDefinition->method_count;
|
|
IL2CPP_ASSERT(genericTypeDefinition->method_count == genericInstanceType->method_count);
|
|
|
|
if (methodCount == 0)
|
|
{
|
|
genericInstanceType->methods = NULL;
|
|
return;
|
|
}
|
|
|
|
const MethodInfo** methods = (const MethodInfo**)MetadataCalloc(methodCount, sizeof(MethodInfo*));
|
|
|
|
for (uint16_t methodIndex = 0; methodIndex < methodCount; ++methodIndex)
|
|
{
|
|
const MethodInfo* methodDefinition = genericTypeDefinition->methods[methodIndex];
|
|
methods[methodIndex] = metadata::GenericMetadata::Inflate(methodDefinition, GenericClass::GetContext(genericInstanceType->generic_class));
|
|
}
|
|
|
|
genericInstanceType->methods = methods;
|
|
|
|
il2cpp_runtime_stats.method_count += methodCount;
|
|
}
|
|
|
|
static void InflatePropertyDefinition(const PropertyInfo* propertyDefinition, PropertyInfo* newProperty, Il2CppClass* declaringClass, Il2CppGenericContext* context)
|
|
{
|
|
newProperty->attrs = propertyDefinition->attrs;
|
|
newProperty->parent = declaringClass;
|
|
newProperty->name = propertyDefinition->name;
|
|
newProperty->token = propertyDefinition->token;
|
|
|
|
if (propertyDefinition->get)
|
|
newProperty->get = metadata::GenericMetadata::Inflate(propertyDefinition->get, context);
|
|
if (propertyDefinition->set)
|
|
newProperty->set = metadata::GenericMetadata::Inflate(propertyDefinition->set, context);
|
|
}
|
|
|
|
void GenericClass::SetupProperties(Il2CppClass* genericInstanceType)
|
|
{
|
|
Il2CppClass* genericTypeDefinition = GenericClass::GetTypeDefinition(genericInstanceType->generic_class);
|
|
uint16_t propertyCount = genericTypeDefinition->property_count;
|
|
IL2CPP_ASSERT(genericTypeDefinition->property_count == genericInstanceType->property_count);
|
|
|
|
if (propertyCount == 0)
|
|
{
|
|
genericInstanceType->properties = NULL;
|
|
return;
|
|
}
|
|
|
|
PropertyInfo* properties = (PropertyInfo*)MetadataCalloc(propertyCount, sizeof(PropertyInfo));
|
|
PropertyInfo* property = properties;
|
|
|
|
for (uint16_t propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)
|
|
{
|
|
InflatePropertyDefinition(genericTypeDefinition->properties + propertyIndex, property, genericInstanceType, GenericClass::GetContext(genericInstanceType->generic_class));
|
|
property++;
|
|
}
|
|
|
|
genericInstanceType->properties = properties;
|
|
}
|
|
|
|
static void InflateEventDefinition(const EventInfo* eventDefinition, EventInfo* newEvent, Il2CppClass* declaringClass, Il2CppGenericContext* context)
|
|
{
|
|
newEvent->eventType = metadata::GenericMetadata::InflateIfNeeded(eventDefinition->eventType, context, false);
|
|
newEvent->name = eventDefinition->name;
|
|
newEvent->parent = declaringClass;
|
|
newEvent->token = eventDefinition->token;
|
|
|
|
if (eventDefinition->add)
|
|
newEvent->add = metadata::GenericMetadata::Inflate(eventDefinition->add, context);
|
|
if (eventDefinition->raise)
|
|
newEvent->raise = metadata::GenericMetadata::Inflate(eventDefinition->raise, context);
|
|
if (eventDefinition->remove)
|
|
newEvent->remove = metadata::GenericMetadata::Inflate(eventDefinition->remove, context);
|
|
}
|
|
|
|
void GenericClass::SetupEvents(Il2CppClass* genericInstanceType)
|
|
{
|
|
Il2CppClass* genericTypeDefinition = GenericClass::GetTypeDefinition(genericInstanceType->generic_class);
|
|
uint16_t eventCount = genericTypeDefinition->event_count;
|
|
IL2CPP_ASSERT(genericTypeDefinition->event_count == genericInstanceType->event_count);
|
|
|
|
if (eventCount == 0)
|
|
{
|
|
genericInstanceType->events = NULL;
|
|
return;
|
|
}
|
|
|
|
EventInfo* events = (EventInfo*)MetadataCalloc(eventCount, sizeof(EventInfo));
|
|
EventInfo* event = events;
|
|
|
|
for (uint16_t eventIndex = 0; eventIndex < eventCount; ++eventIndex)
|
|
{
|
|
InflateEventDefinition(genericTypeDefinition->events + eventIndex, event, genericInstanceType, GenericClass::GetContext(genericInstanceType->generic_class));
|
|
event++;
|
|
}
|
|
|
|
genericInstanceType->events = events;
|
|
}
|
|
|
|
static FieldInfo* InflateFieldDefinition(const FieldInfo* fieldDefinition, FieldInfo* newField, Il2CppClass* declaringClass, Il2CppGenericContext* context)
|
|
{
|
|
newField->type = metadata::GenericMetadata::InflateIfNeeded(fieldDefinition->type, context, false);
|
|
newField->name = fieldDefinition->name;
|
|
newField->parent = declaringClass;
|
|
newField->offset = fieldDefinition->offset;
|
|
newField->token = fieldDefinition->token;
|
|
|
|
return newField;
|
|
}
|
|
|
|
void GenericClass::SetupFields(Il2CppClass* genericInstanceType)
|
|
{
|
|
Il2CppClass* genericTypeDefinition = GenericClass::GetTypeDefinition(genericInstanceType->generic_class);
|
|
uint16_t fieldCount = genericTypeDefinition->field_count;
|
|
IL2CPP_ASSERT(genericTypeDefinition->field_count == genericInstanceType->field_count);
|
|
|
|
if (fieldCount == 0)
|
|
{
|
|
genericInstanceType->fields = NULL;
|
|
return;
|
|
}
|
|
|
|
FieldInfo* fields = (FieldInfo*)MetadataCalloc(fieldCount, sizeof(FieldInfo));
|
|
FieldInfo* field = fields;
|
|
|
|
for (uint16_t fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex)
|
|
{
|
|
InflateFieldDefinition(genericTypeDefinition->fields + fieldIndex, field, genericInstanceType, GenericClass::GetContext(genericInstanceType->generic_class));
|
|
field++;
|
|
}
|
|
|
|
genericInstanceType->fields = fields;
|
|
}
|
|
|
|
Il2CppClass* GenericClass::GetClass(Il2CppGenericClass* gclass, bool throwOnError)
|
|
{
|
|
Il2CppClass* cachedClass = os::Atomic::LoadPointerRelaxed(&gclass->cached_class);
|
|
if (cachedClass)
|
|
return cachedClass;
|
|
return CreateClass(gclass, throwOnError);
|
|
}
|
|
|
|
Il2CppClass* GenericClass::CreateClass(Il2CppGenericClass *gclass, bool throwOnError)
|
|
{
|
|
Il2CppClass* definition = GetTypeDefinition(gclass);
|
|
if (definition == NULL)
|
|
{
|
|
if (throwOnError)
|
|
vm::Exception::Raise(vm::Exception::GetMaximumNestedGenericsException());
|
|
return NULL;
|
|
}
|
|
|
|
os::FastAutoLock lock(&g_MetadataLock);
|
|
|
|
if (!gclass->cached_class)
|
|
{
|
|
Il2CppClass* klass = (Il2CppClass*)MetadataCalloc(1, sizeof(Il2CppClass) + (sizeof(VirtualInvokeData) * definition->vtable_count));
|
|
klass->klass = klass;
|
|
|
|
klass->name = definition->name;
|
|
klass->namespaze = definition->namespaze;
|
|
|
|
klass->image = definition->image;
|
|
klass->flags = definition->flags;
|
|
//klass->type_token = definition->type_token;
|
|
klass->generic_class = gclass;
|
|
|
|
Il2CppClass* genericTypeDefinition = GenericClass::GetTypeDefinition(klass->generic_class);
|
|
Il2CppGenericContext* context = &klass->generic_class->context;
|
|
|
|
if (genericTypeDefinition->parent)
|
|
klass->parent = Class::FromIl2CppType(metadata::GenericMetadata::InflateIfNeeded(&genericTypeDefinition->parent->byval_arg, context, false));
|
|
|
|
if (genericTypeDefinition->declaringType)
|
|
klass->declaringType = Class::FromIl2CppType(metadata::GenericMetadata::InflateIfNeeded(&genericTypeDefinition->declaringType->byval_arg, context, false));
|
|
|
|
klass->this_arg.type = klass->byval_arg.type = IL2CPP_TYPE_GENERICINST;
|
|
klass->this_arg.data.generic_class = klass->byval_arg.data.generic_class = gclass;
|
|
klass->this_arg.byref = true;
|
|
klass->byval_arg.valuetype = genericTypeDefinition->byval_arg.valuetype;
|
|
|
|
klass->event_count = definition->event_count;
|
|
klass->field_count = definition->field_count;
|
|
klass->interfaces_count = definition->interfaces_count;
|
|
klass->method_count = definition->method_count;
|
|
klass->property_count = definition->property_count;
|
|
|
|
klass->enumtype = definition->enumtype;
|
|
klass->element_class = klass->castClass = klass;
|
|
|
|
klass->has_cctor = definition->has_cctor;
|
|
klass->cctor_finished_or_no_cctor = !definition->has_cctor;
|
|
|
|
klass->has_finalize = definition->has_finalize;
|
|
klass->native_size = klass->thread_static_fields_offset = -1;
|
|
klass->token = definition->token;
|
|
klass->interopData = MetadataCache::GetInteropDataForType(&klass->byval_arg);
|
|
|
|
if (GenericClass::GetTypeDefinition(klass->generic_class) == il2cpp_defaults.generic_nullable_class)
|
|
{
|
|
klass->element_class = klass->castClass = Class::FromIl2CppType(klass->generic_class->context.class_inst->type_argv[0]);
|
|
klass->nullabletype = true;
|
|
}
|
|
|
|
if (klass->enumtype)
|
|
klass->element_class = klass->castClass = definition->element_class;
|
|
|
|
klass->is_import_or_windows_runtime = definition->is_import_or_windows_runtime;
|
|
|
|
// Do not update gclass->cached_class until `klass` is fully initialized
|
|
// And do so with an atomic barrier so no threads observer the writes out of order
|
|
il2cpp::os::Atomic::ExchangePointer(&gclass->cached_class, klass);
|
|
}
|
|
|
|
return gclass->cached_class;
|
|
}
|
|
|
|
Il2CppGenericContext* GenericClass::GetContext(Il2CppGenericClass *gclass)
|
|
{
|
|
return &gclass->context;
|
|
}
|
|
|
|
Il2CppClass* GenericClass::GetTypeDefinition(Il2CppGenericClass *gclass)
|
|
{
|
|
return MetadataCache::GetTypeInfoFromType(gclass->type);
|
|
}
|
|
|
|
bool GenericClass::IsEnum(Il2CppGenericClass *gclass)
|
|
{
|
|
return IsValueType(gclass) && GetTypeDefinition(gclass)->enumtype;
|
|
}
|
|
} /* namespace vm */
|
|
} /* namespace il2cpp */
|