Add support for basic classes to Scripting Type (without scripting object as a base)
This commit is contained in:
@@ -60,16 +60,16 @@ ScriptingType::ScriptingType()
|
||||
, Module(nullptr)
|
||||
, InitRuntime(nullptr)
|
||||
, Fullname(nullptr, 0)
|
||||
, Type(ScriptingTypes::Class)
|
||||
, Type(ScriptingTypes::Script)
|
||||
, BaseTypePtr(nullptr)
|
||||
{
|
||||
Class.Spawn = nullptr;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = nullptr;
|
||||
Class.SetupScriptObjectVTable = nullptr;
|
||||
Class.DefaultInstance = nullptr;
|
||||
Script.Spawn = nullptr;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = nullptr;
|
||||
Script.SetupScriptObjectVTable = nullptr;
|
||||
Script.DefaultInstance = nullptr;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, SpawnHandler spawn, const ScriptingTypeHandle& baseType, SetupScriptVTableHandler setupScriptVTable, SetupScriptObjectVTableHandler setupScriptObjectVTable)
|
||||
@@ -77,21 +77,39 @@ ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* modul
|
||||
, Module(module)
|
||||
, InitRuntime(initRuntime)
|
||||
, Fullname(fullname)
|
||||
, Type(ScriptingTypes::Class)
|
||||
, Type(ScriptingTypes::Script)
|
||||
, BaseTypeHandle(baseType)
|
||||
, BaseTypePtr(nullptr)
|
||||
, Size(size)
|
||||
{
|
||||
Class.Spawn = spawn;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = setupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Class.DefaultInstance = nullptr;
|
||||
Script.Spawn = spawn;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = setupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Script.DefaultInstance = nullptr;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, SpawnHandler spawn, ScriptingTypeInitializer* baseType, SetupScriptVTableHandler setupScriptVTable, SetupScriptObjectVTableHandler setupScriptObjectVTable)
|
||||
: ManagedClass(nullptr)
|
||||
, Module(module)
|
||||
, InitRuntime(initRuntime)
|
||||
, Fullname(fullname)
|
||||
, Type(ScriptingTypes::Script)
|
||||
, BaseTypePtr(baseType)
|
||||
, Size(size)
|
||||
{
|
||||
Script.Spawn = spawn;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = setupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Script.DefaultInstance = nullptr;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, ScriptingTypeInitializer* baseType)
|
||||
: ManagedClass(nullptr)
|
||||
, Module(module)
|
||||
, InitRuntime(initRuntime)
|
||||
@@ -100,13 +118,8 @@ ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* modul
|
||||
, BaseTypePtr(baseType)
|
||||
, Size(size)
|
||||
{
|
||||
Class.Spawn = spawn;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = setupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = setupScriptObjectVTable;
|
||||
Class.DefaultInstance = nullptr;
|
||||
Class.Ctor = ctor;
|
||||
Class.Dtor = dtor;
|
||||
}
|
||||
|
||||
ScriptingType::ScriptingType(const StringAnsiView& fullname, BinaryModule* module, int32 size, InitRuntimeHandler initRuntime, Ctor ctor, Dtor dtor, Copy copy, Box box, Unbox unbox, GetField getField, SetField setField, ScriptingTypeInitializer* baseType)
|
||||
@@ -139,14 +152,14 @@ ScriptingType::ScriptingType(const ScriptingType& other)
|
||||
{
|
||||
switch (other.Type)
|
||||
{
|
||||
case ScriptingTypes::Class:
|
||||
Class.Spawn = other.Class.Spawn;
|
||||
Class.VTable = nullptr;
|
||||
Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = other.Class.SetupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = other.Class.SetupScriptObjectVTable;
|
||||
Class.DefaultInstance = nullptr;
|
||||
case ScriptingTypes::Script:
|
||||
Script.Spawn = other.Script.Spawn;
|
||||
Script.VTable = nullptr;
|
||||
Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = other.Script.SetupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = other.Script.SetupScriptObjectVTable;
|
||||
Script.DefaultInstance = nullptr;
|
||||
break;
|
||||
case ScriptingTypes::Structure:
|
||||
Struct.Ctor = other.Struct.Ctor;
|
||||
@@ -175,18 +188,18 @@ ScriptingType::ScriptingType(ScriptingType&& other)
|
||||
{
|
||||
switch (other.Type)
|
||||
{
|
||||
case ScriptingTypes::Class:
|
||||
Class.Spawn = other.Class.Spawn;
|
||||
Class.VTable = other.Class.VTable;
|
||||
other.Class.VTable = nullptr;
|
||||
Class.ScriptVTable = other.Class.ScriptVTable;
|
||||
other.Class.ScriptVTable = nullptr;
|
||||
Class.ScriptVTableBase = other.Class.ScriptVTableBase;
|
||||
other.Class.ScriptVTableBase = nullptr;
|
||||
Class.SetupScriptVTable = other.Class.SetupScriptVTable;
|
||||
Class.SetupScriptObjectVTable = other.Class.SetupScriptObjectVTable;
|
||||
Class.DefaultInstance = other.Class.DefaultInstance;
|
||||
other.Class.DefaultInstance = nullptr;
|
||||
case ScriptingTypes::Script:
|
||||
Script.Spawn = other.Script.Spawn;
|
||||
Script.VTable = other.Script.VTable;
|
||||
other.Script.VTable = nullptr;
|
||||
Script.ScriptVTable = other.Script.ScriptVTable;
|
||||
other.Script.ScriptVTable = nullptr;
|
||||
Script.ScriptVTableBase = other.Script.ScriptVTableBase;
|
||||
other.Script.ScriptVTableBase = nullptr;
|
||||
Script.SetupScriptVTable = other.Script.SetupScriptVTable;
|
||||
Script.SetupScriptObjectVTable = other.Script.SetupScriptObjectVTable;
|
||||
Script.DefaultInstance = other.Script.DefaultInstance;
|
||||
other.Script.DefaultInstance = nullptr;
|
||||
break;
|
||||
case ScriptingTypes::Structure:
|
||||
Struct.Ctor = other.Struct.Ctor;
|
||||
@@ -207,13 +220,13 @@ ScriptingType::~ScriptingType()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case ScriptingTypes::Class:
|
||||
if (Class.DefaultInstance)
|
||||
Delete(Class.DefaultInstance);
|
||||
if (Class.VTable)
|
||||
Platform::Free((byte*)Class.VTable - GetVTablePrefix());
|
||||
Platform::Free(Class.ScriptVTable);
|
||||
Platform::Free(Class.ScriptVTableBase);
|
||||
case ScriptingTypes::Script:
|
||||
if (Script.DefaultInstance)
|
||||
Delete(Script.DefaultInstance);
|
||||
if (Script.VTable)
|
||||
Platform::Free((byte*)Script.VTable - GetVTablePrefix());
|
||||
Platform::Free(Script.ScriptVTable);
|
||||
Platform::Free(Script.ScriptVTableBase);
|
||||
break;
|
||||
case ScriptingTypes::Structure:
|
||||
break;
|
||||
@@ -235,17 +248,17 @@ ScriptingTypeHandle ScriptingType::GetHandle() const
|
||||
|
||||
ScriptingObject* ScriptingType::GetDefaultInstance() const
|
||||
{
|
||||
ASSERT(Type == ScriptingTypes::Class);
|
||||
if (!Class.DefaultInstance)
|
||||
ASSERT(Type == ScriptingTypes::Script);
|
||||
if (!Script.DefaultInstance)
|
||||
{
|
||||
const ScriptingObjectSpawnParams params(Guid::New(), GetHandle());
|
||||
Class.DefaultInstance = Class.Spawn(params);
|
||||
if (!Class.DefaultInstance)
|
||||
Script.DefaultInstance = Script.Spawn(params);
|
||||
if (!Script.DefaultInstance)
|
||||
{
|
||||
LOG(Error, "Failed to create default instance of type {0}", ToString());
|
||||
}
|
||||
}
|
||||
return Class.DefaultInstance;
|
||||
return Script.DefaultInstance;
|
||||
}
|
||||
|
||||
String ScriptingType::ToString() const
|
||||
@@ -268,6 +281,21 @@ ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const S
|
||||
module->TypeNameToTypeIndex[typeName] = TypeIndex;
|
||||
}
|
||||
|
||||
ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingTypeInitializer* baseType)
|
||||
: ScriptingTypeHandle(module, module->Types.Count())
|
||||
{
|
||||
module->Types.AddUninitialized();
|
||||
new(module->Types.Get() + TypeIndex)ScriptingType(fullname, module, size, initRuntime, ctor, dtor, baseType);
|
||||
const MString typeName(fullname.Get(), fullname.Length());
|
||||
#if BUILD_DEBUG
|
||||
if (module->TypeNameToTypeIndex.ContainsKey(typeName))
|
||||
{
|
||||
LOG(Error, "Duplicated native typename {0} from module {1}.", String(fullname), String(module->GetName()));
|
||||
}
|
||||
#endif
|
||||
module->TypeNameToTypeIndex[typeName] = TypeIndex;
|
||||
}
|
||||
|
||||
ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::Ctor ctor, ScriptingType::Dtor dtor, ScriptingType::Copy copy, ScriptingType::Box box, ScriptingType::Unbox unbox, ScriptingType::GetField getField, ScriptingType::SetField setField, ScriptingTypeInitializer* baseType)
|
||||
: ScriptingTypeHandle(module, module->Types.Count())
|
||||
{
|
||||
@@ -368,7 +396,7 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
// Create native object
|
||||
ScriptingTypeHandle managedTypeHandle = params.Type;
|
||||
const ScriptingType* managedTypePtr = &managedTypeHandle.GetType();
|
||||
while (managedTypePtr->Class.Spawn != &ManagedObjectSpawn)
|
||||
while (managedTypePtr->Script.Spawn != &ManagedObjectSpawn)
|
||||
{
|
||||
managedTypeHandle = managedTypePtr->GetBaseType();
|
||||
managedTypePtr = &managedTypeHandle.GetType();
|
||||
@@ -376,12 +404,12 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
ScriptingType& managedType = (ScriptingType&)*managedTypePtr;
|
||||
ScriptingTypeHandle nativeTypeHandle = managedType.GetBaseType();
|
||||
const ScriptingType* nativeTypePtr = &nativeTypeHandle.GetType();
|
||||
while (nativeTypePtr->Class.Spawn == &ManagedObjectSpawn)
|
||||
while (nativeTypePtr->Script.Spawn == &ManagedObjectSpawn)
|
||||
{
|
||||
nativeTypeHandle = nativeTypePtr->GetBaseType();
|
||||
nativeTypePtr = &nativeTypeHandle.GetType();
|
||||
}
|
||||
ScriptingObject* object = nativeTypePtr->Class.Spawn(params);
|
||||
ScriptingObject* object = nativeTypePtr->Script.Spawn(params);
|
||||
if (!object)
|
||||
{
|
||||
return nullptr;
|
||||
@@ -392,9 +420,9 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
// We create a custom vtable for the C# objects that use a native class object with virtual functions overrides.
|
||||
// To make it easy to use in C++ we inject custom wrapper methods into C++ object vtable to call C# code from them.
|
||||
// Because virtual member functions calls are C++ ABI and impl-defined this is quite hard. But works.
|
||||
if (managedType.Class.ScriptVTable)
|
||||
if (managedType.Script.ScriptVTable)
|
||||
{
|
||||
if (!managedType.Class.VTable)
|
||||
if (!managedType.Script.VTable)
|
||||
{
|
||||
// Duplicate vtable
|
||||
void** vtable = *(void***)object;
|
||||
@@ -403,23 +431,23 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
||||
while (vtable[entriesCount] && entriesCount < 200)
|
||||
entriesCount++;
|
||||
const int32 size = entriesCount * sizeof(void*);
|
||||
managedType.Class.VTable = (void**)((byte*)Platform::Allocate(prefixSize + size, 16) + prefixSize);
|
||||
Platform::MemoryCopy((byte*)managedType.Class.VTable - prefixSize, (byte*)vtable - prefixSize, prefixSize + size);
|
||||
managedType.Script.VTable = (void**)((byte*)Platform::Allocate(prefixSize + size, 16) + prefixSize);
|
||||
Platform::MemoryCopy((byte*)managedType.Script.VTable - prefixSize, (byte*)vtable - prefixSize, prefixSize + size);
|
||||
|
||||
// Override vtable entries by the class
|
||||
for (ScriptingTypeHandle e = nativeTypeHandle; e;)
|
||||
{
|
||||
const ScriptingType& eType = e.GetType();
|
||||
if (eType.Class.SetupScriptObjectVTable)
|
||||
if (eType.Script.SetupScriptObjectVTable)
|
||||
{
|
||||
eType.Class.SetupScriptObjectVTable(managedType.Class.ScriptVTable, managedType.Class.ScriptVTableBase, managedType.Class.VTable, entriesCount, 0);
|
||||
eType.Script.SetupScriptObjectVTable(managedType.Script.ScriptVTable, managedType.Script.ScriptVTableBase, managedType.Script.VTable, entriesCount, 0);
|
||||
}
|
||||
e = eType.GetBaseType();
|
||||
}
|
||||
}
|
||||
|
||||
// Override object vtable with hacked one that has C# functions calls
|
||||
*(void**)object = managedType.Class.VTable;
|
||||
*(void**)object = managedType.Script.VTable;
|
||||
}
|
||||
|
||||
// Mark as managed type
|
||||
@@ -557,7 +585,7 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
|
||||
if (baseClassModule->TypeNameToTypeIndex.TryGet(baseClass->GetFullName(), typeIndex))
|
||||
{
|
||||
nativeType = ScriptingTypeHandle(baseClassModule, typeIndex);
|
||||
if (nativeType.GetType().Class.Spawn != &ManagedObjectSpawn)
|
||||
if (nativeType.GetType().Script.Spawn != &ManagedObjectSpawn)
|
||||
break;
|
||||
}
|
||||
baseClass = baseClass->GetBaseClass();
|
||||
@@ -592,14 +620,14 @@ void ManagedBinaryModule::OnLoaded(MAssembly* assembly)
|
||||
for (ScriptingTypeHandle e = nativeType; e;)
|
||||
{
|
||||
const ScriptingType& eType = e.GetType();
|
||||
if (eType.Class.SetupScriptVTable)
|
||||
if (eType.Script.SetupScriptVTable)
|
||||
{
|
||||
ASSERT(eType.ManagedClass);
|
||||
eType.Class.SetupScriptVTable(eType.ManagedClass, type.Class.ScriptVTable, type.Class.ScriptVTableBase);
|
||||
eType.Script.SetupScriptVTable(eType.ManagedClass, type.Script.ScriptVTable, type.Script.ScriptVTableBase);
|
||||
}
|
||||
e = eType.GetBaseType();
|
||||
}
|
||||
MMethod** scriptVTable = (MMethod**)type.Class.ScriptVTable;
|
||||
MMethod** scriptVTable = (MMethod**)type.Script.ScriptVTable;
|
||||
while (scriptVTable && *scriptVTable)
|
||||
{
|
||||
const MMethod* referenceMethod = *scriptVTable;
|
||||
@@ -657,10 +685,10 @@ void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
|
||||
for (ScriptingType& type : Types)
|
||||
{
|
||||
type.ManagedClass = nullptr;
|
||||
if (type.Type == ScriptingTypes::Class && type.Class.ScriptVTable)
|
||||
if (type.Type == ScriptingTypes::Script && type.Script.ScriptVTable)
|
||||
{
|
||||
Platform::Free(type.Class.ScriptVTable);
|
||||
type.Class.ScriptVTable = nullptr;
|
||||
Platform::Free(type.Script.ScriptVTable);
|
||||
type.Script.ScriptVTable = nullptr;
|
||||
}
|
||||
}
|
||||
ClassToTypeIndex.Clear();
|
||||
|
||||
Reference in New Issue
Block a user