Fix native scripting interface method override in managed scripts on Clang-platforms

This commit is contained in:
Wojtek Figat
2023-01-10 11:43:39 +01:00
parent a74b847e65
commit ca2e2e1f41

View File

@@ -1500,7 +1500,10 @@ namespace Flax.Build.Bindings
var langInfo = ScriptingLangInfos[i];
if (!langInfo.Enabled)
continue;
contents.AppendLine(count == 0 ? " if (wrapperIndex == 0)" : $" else if (wrapperIndex == {count})");
if (count == 0)
contents.AppendLine(" if (wrapperIndex == 0)");
else
contents.AppendLine($" else if (wrapperIndex == {count})");
contents.AppendLine(" {");
contents.AppendLine($" auto thunkPtr = &{classInfo.NativeName}Internal::{functionInfo.UniqueName}{langInfo.VirtualWrapperMethodsPostfix};");
contents.AppendLine(" vtable[vtableIndex] = *(void**)&thunkPtr;");
@@ -1516,6 +1519,50 @@ namespace Flax.Build.Bindings
scriptVTableIndex++;
}
// Native interfaces override in managed code requires vtables hacking which requires additional inject on Clang-platforms
if (buildData.Toolchain.Compiler == TargetCompiler.Clang && classInfo.IsClass && classInfo.Interfaces != null)
{
// Override vtable entries of interface methods (for each virtual function in each interface)
foreach (var interfaceInfo in classInfo.Interfaces)
{
if (interfaceInfo.Access == AccessLevel.Private)
continue;
foreach (var functionInfo in interfaceInfo.Functions)
{
if (!functionInfo.IsVirtual)
continue;
contents.AppendLine(" {");
{
var thunkParams = string.Empty;
var separator = false;
for (var i = 0; i < functionInfo.Parameters.Count; i++)
{
var parameterInfo = functionInfo.Parameters[i];
if (separator)
thunkParams += ", ";
separator = true;
thunkParams += parameterInfo.Type;
}
var t = functionInfo.IsConst ? " const" : string.Empty;
contents.AppendLine($" typedef {functionInfo.ReturnType} ({classInfo.NativeName}::*{functionInfo.UniqueName}_Signature)({thunkParams}){t};");
}
contents.AppendLine($" {functionInfo.UniqueName}_Signature funcPtr = &{classInfo.NativeName}::{functionInfo.Name};");
contents.AppendLine(" const int32 vtableIndex = GetVTableIndex(vtable, entriesCount, *(void**)&funcPtr);");
contents.AppendLine(" if (vtableIndex >= 0 && vtableIndex < entriesCount)");
contents.AppendLine(" {");
contents.AppendLine($" extern void {interfaceInfo.NativeName}Internal_{functionInfo.UniqueName}_VTableOverride(void*& vtableEntry, int32 wrapperIndex);");
contents.AppendLine($" {interfaceInfo.NativeName}Internal_{functionInfo.UniqueName}_VTableOverride(vtable[vtableIndex], wrapperIndex);");
contents.AppendLine(" }");
contents.AppendLine(" else");
contents.AppendLine(" {");
contents.AppendLine($" LOG(Error, \"Failed to find the vtable entry for method {{0}} in class {{1}}\", TEXT(\"{functionInfo.Name}\"), TEXT(\"{classInfo.Name}\"));");
contents.AppendLine(" }");
contents.AppendLine(" }");
}
}
}
contents.AppendLine(" }");
contents.AppendLine("");
@@ -2318,6 +2365,36 @@ namespace Flax.Build.Bindings
contents.Append('}').Append(';').AppendLine();
contents.AppendLine();
// Native interfaces override in managed code requires vtables hacking which requires additional inject on Clang-platforms
if (buildData.Toolchain.Compiler == TargetCompiler.Clang)
{
// Generate functions that inject script wrappers into vtable entry
foreach (var functionInfo in interfaceInfo.Functions)
{
if (!functionInfo.IsVirtual)
continue;
contents.AppendLine($"void {interfaceInfo.NativeName}Internal_{functionInfo.UniqueName}_VTableOverride(void*& vtableEntry, int32 wrapperIndex)");
contents.AppendLine("{");
for (int i = 0, count = 0; i < ScriptingLangInfos.Count; i++)
{
var langInfo = ScriptingLangInfos[i];
if (!langInfo.Enabled)
continue;
if (count == 0)
contents.AppendLine(" if (wrapperIndex == 0)");
else
contents.AppendLine($" else if (wrapperIndex == {count})");
contents.AppendLine(" {");
contents.AppendLine($" auto thunkPtr = &{interfaceInfo.NativeName}Internal::{functionInfo.UniqueName}{langInfo.VirtualWrapperMethodsPostfix};");
contents.AppendLine(" vtableEntry = *(void**)&thunkPtr;");
contents.AppendLine(" }");
count++;
}
contents.AppendLine("}");
contents.AppendLine("");
}
}
// Type initializer
contents.Append($"ScriptingTypeInitializer {interfaceTypeNameNative}::TypeInitializer((BinaryModule*)GetBinaryModule{moduleInfo.Name}(), ");
contents.Append($"StringAnsiView(\"{interfaceTypeNameManaged}\", {interfaceTypeNameManaged.Length}), &{interfaceTypeNameInternal}Internal::InitRuntime,");