bool TryFindConstructor(string typeName, out ObjectConstructorDelegate ctor)
 {
     return(ProgramDatabase.TryGetDelegateForSymbol(
                $"??0{typeName}@@QEAA@UMemLabelId@@W4ObjectCreationMode@@@Z",
                out ctor
                ));
 }
    public ProduceAbstractScope(Rtti *type)
        : this()
    {
        if (type == null)
        {
            throw new ArgumentNullException(nameof(type));
        }

        if (!type->IsAbstract)
        {
            throw new ArgumentException("Type must be abstract.", nameof(type));
        }

        // In order to generate type trees for abstract types, we need to hook
        // VirtualRedirectTransfer to call the appropriate Transfer method on the type.
        for (var iter = type; iter != null; iter = iter->BaseClass)
        {
            if (TryHookTransfer(iter->Name, out transferHook))
            {
                break;
            }
        }

        if (transferHook == null)
        {
            throw new ArgumentException("Couldn't locate a ::Transfer method for type.", nameof(type));
        }

        // We also need to locate a constructor that we can call, as not all of the
        // abstract types actually have one defined.
        ObjectConstructorDelegate ctor = null;

        for (var iter = type; iter != null; iter = iter->BaseClass)
        {
            if (TryFindConstructor(iter->Name, out ctor))
            {
                break;
            }
        }

        if (ctor == null)
        {
            throw new ArgumentException("Couldn't locate a constructor for type.", nameof(type));
        }

        constructorHandle = GCHandle.Alloc(ctor, GCHandleType.Pinned);

        // We need to override the 'produce helper' so that attempting to produce
        // the type will no longer result in an error. Additionally, we override the
        // GetTypeVirtualInternal method to avoid errors on types without their own
        // constructors.
        var getType = CreateGetTypeDelegate(type->RuntimeTypeIndex);

        getTypeHandle = GCHandle.Alloc(getType, GCHandleType.Pinned);
        var produce = CreateProduceHelper(
            type->ByteSize,
            type->RuntimeTypeIndex,
            Marshal.GetFunctionPointerForDelegate(getType),
            ctor
            );

        // Pin the produce method to avoid GC and assign it to the type.
        // Also set IsAbstract to false to allow the type to be produced.
        produceHandle    = GCHandle.Alloc(produce, GCHandleType.Pinned);
        originalProduce  = type->Producer.Pointer;
        type->Producer   = produce;
        type->IsAbstract = false;
    }
    ObjectProducerDelegate CreateProduceHelper(int objectSize, uint typeIndex, IntPtr getType, ObjectConstructorDelegate ctor)
    {
        return((label, mode) =>
        {
            var vtable = (NativeObject.VirtualMethodTable *)UnsafeUtility.Malloc(sizeof(NativeObject.VirtualMethodTable), 8, Allocator.Persistent);
            var alloc = (NativeObject *)UnsafeUtility.Malloc(objectSize, 8, Allocator.Persistent);

            // Call the C++ constructor
            ctor.Invoke(alloc, label, mode);

            // Copy the original virtual method table and override GetTypeVirtualInternal
            // to call a custom method that returns the correct runtime type.
            *vtable = *alloc->MethodTable;
            vtable->GetTypeVirtualInternal = getType;

            // Assign the new method table and type index to the object.
            alloc->MethodTable = vtable;
            alloc->CachedTypeIndex = typeIndex;
            return alloc;
        });
    }