Simplify managed method invoke generation for AOT vs JIT platforms
This commit is contained in:
@@ -1257,112 +1257,60 @@ namespace Flax.Build.Bindings
|
|||||||
else
|
else
|
||||||
contents.AppendLine($" void* params[{functionInfo.Parameters.Count}];");
|
contents.AppendLine($" void* params[{functionInfo.Parameters.Count}];");
|
||||||
|
|
||||||
contents.AppendLine("#if USE_MONO_AOT");
|
// If platform supports JITed code execution then use method thunk, otherwise fallback to generic mono_runtime_invoke
|
||||||
|
|
||||||
// Convert parameters into managed format as pointers to value
|
|
||||||
if (functionInfo.Parameters.Count != 0)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
|
||||||
{
|
|
||||||
var parameterInfo = functionInfo.Parameters[i];
|
|
||||||
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
|
||||||
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, parameterInfo.Type, parameterInfo.Name, classInfo, paramIsRef, out CppParamsThatNeedLocalVariable[i]);
|
|
||||||
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke method
|
|
||||||
contents.AppendLine(" auto __result = mono_runtime_invoke(method->GetNative(), object->GetOrCreateManagedInstance(), params, &exception);");
|
|
||||||
|
|
||||||
contents.AppendLine("#else");
|
|
||||||
|
|
||||||
// Convert parameters into managed format as boxed values
|
|
||||||
var thunkParams = string.Empty;
|
|
||||||
var thunkCall = string.Empty;
|
|
||||||
if (functionInfo.Parameters.Count != 0)
|
|
||||||
{
|
|
||||||
separator = functionInfo.Parameters.Count != 0;
|
|
||||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
|
||||||
{
|
|
||||||
var parameterInfo = functionInfo.Parameters[i];
|
|
||||||
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
|
||||||
var paramValue = GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, out var apiType, parameterInfo.Name);
|
|
||||||
var useLocalVar = false;
|
|
||||||
if (paramIsRef)
|
|
||||||
{
|
|
||||||
// Pass as pointer to value when using ref/out parameter
|
|
||||||
contents.Append($" auto __param_{parameterInfo.Name} = {paramValue};").AppendLine();
|
|
||||||
var useLocalVarPointer = !apiType.IsValueType;
|
|
||||||
paramValue = $"{(useLocalVarPointer ? "&" : "")}__param_{parameterInfo.Name}";
|
|
||||||
CppParamsThatNeedConversion[i] = useLocalVarPointer;
|
|
||||||
useLocalVar = true;
|
|
||||||
}
|
|
||||||
CppParamsThatNeedLocalVariable[i] = useLocalVar;
|
|
||||||
|
|
||||||
if (separator)
|
|
||||||
thunkParams += ", ";
|
|
||||||
if (separator)
|
|
||||||
thunkCall += ", ";
|
|
||||||
separator = true;
|
|
||||||
thunkParams += "void*";
|
|
||||||
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
|
||||||
thunkCall += $"params[{i}]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke method thunk
|
|
||||||
var returnType = functionInfo.ReturnType;
|
var returnType = functionInfo.ReturnType;
|
||||||
if (returnType.IsVoid)
|
var useThunk = buildData.Platform.HasDynamicCodeExecutionSupport;
|
||||||
|
if (useThunk)
|
||||||
{
|
{
|
||||||
contents.AppendLine($" typedef void (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
// Convert parameters into managed format as boxed values
|
||||||
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
var thunkParams = string.Empty;
|
||||||
contents.AppendLine($" thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
var thunkCall = string.Empty;
|
||||||
}
|
if (functionInfo.Parameters.Count != 0)
|
||||||
else
|
|
||||||
{
|
|
||||||
contents.AppendLine($" typedef MonoObject* (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
|
||||||
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
|
||||||
contents.AppendLine($" auto __result = thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
|
||||||
}
|
|
||||||
|
|
||||||
contents.AppendLine("#endif");
|
|
||||||
contents.AppendLine(" WrapperCallInstance = prevWrapperCallInstance;");
|
|
||||||
contents.AppendLine(" if (exception)");
|
|
||||||
contents.AppendLine(" DebugLog::LogException(exception);");
|
|
||||||
|
|
||||||
// Convert parameter values back from managed to native (could be modified there)
|
|
||||||
bool anyRefOut = false;
|
|
||||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
|
||||||
{
|
|
||||||
var parameterInfo = functionInfo.Parameters[i];
|
|
||||||
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
|
||||||
if (paramIsRef && !parameterInfo.Type.IsConst)
|
|
||||||
{
|
{
|
||||||
if (!anyRefOut)
|
separator = functionInfo.Parameters.Count != 0;
|
||||||
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
anyRefOut = true;
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
contents.AppendLine("#if USE_MONO_AOT");
|
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||||
}
|
var paramValue = GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, out var apiType, parameterInfo.Name);
|
||||||
|
var useLocalVar = false;
|
||||||
|
if (paramIsRef)
|
||||||
|
{
|
||||||
|
// Pass as pointer to value when using ref/out parameter
|
||||||
|
contents.Append($" auto __param_{parameterInfo.Name} = {paramValue};").AppendLine();
|
||||||
|
var useLocalVarPointer = !apiType.IsValueType;
|
||||||
|
paramValue = $"{(useLocalVarPointer ? "&" : "")}__param_{parameterInfo.Name}";
|
||||||
|
CppParamsThatNeedConversion[i] = useLocalVarPointer;
|
||||||
|
useLocalVar = true;
|
||||||
|
}
|
||||||
|
CppParamsThatNeedLocalVariable[i] = useLocalVar;
|
||||||
|
|
||||||
// Direct value convert
|
if (separator)
|
||||||
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, out var managedType, out var apiType, null, out _);
|
thunkParams += ", ";
|
||||||
var passAsParamPtr = managedType.EndsWith("*");
|
if (separator)
|
||||||
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
|
thunkCall += ", ";
|
||||||
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
|
separator = true;
|
||||||
if (!string.IsNullOrEmpty(managedToNative))
|
thunkParams += "void*";
|
||||||
{
|
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
||||||
if (!passAsParamPtr)
|
thunkCall += $"params[{i}]";
|
||||||
paramValue = '*' + paramValue;
|
|
||||||
paramValue = string.Format(managedToNative, paramValue);
|
|
||||||
}
|
}
|
||||||
else if (!passAsParamPtr)
|
|
||||||
paramValue = '*' + paramValue;
|
|
||||||
contents.Append($" {parameterInfo.Name} = {paramValue};").AppendLine();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (anyRefOut)
|
// Invoke method thunk
|
||||||
{
|
if (returnType.IsVoid)
|
||||||
contents.AppendLine("#else");
|
{
|
||||||
|
contents.AppendLine($" typedef void (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
||||||
|
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
||||||
|
contents.AppendLine($" thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
contents.AppendLine($" typedef MonoObject* (*Thunk)(void* instance{thunkParams}, MonoObject** exception);");
|
||||||
|
contents.AppendLine(" const auto thunk = (Thunk)method->GetThunk();");
|
||||||
|
contents.AppendLine($" auto __result = thunk(object->GetOrCreateManagedInstance(){thunkCall}, &exception);");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert parameter values back from managed to native (could be modified there)
|
||||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
var parameterInfo = functionInfo.Parameters[i];
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
@@ -1377,41 +1325,88 @@ namespace Flax.Build.Bindings
|
|||||||
parameterInfo.Type.IsRef = true;
|
parameterInfo.Type.IsRef = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contents.AppendLine("#endif");
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert parameters into managed format as pointers to value
|
||||||
|
if (functionInfo.Parameters.Count != 0)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
|
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||||
|
var paramValue = GenerateCppWrapperNativeToManagedParam(buildData, contents, parameterInfo.Type, parameterInfo.Name, classInfo, paramIsRef, out CppParamsThatNeedLocalVariable[i]);
|
||||||
|
contents.Append($" params[{i}] = {paramValue};").AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke method
|
||||||
|
contents.AppendLine(" auto __result = mono_runtime_invoke(method->GetNative(), object->GetOrCreateManagedInstance(), params, &exception);");
|
||||||
|
|
||||||
|
// Convert parameter values back from managed to native (could be modified there)
|
||||||
|
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||||
|
{
|
||||||
|
var parameterInfo = functionInfo.Parameters[i];
|
||||||
|
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||||
|
if (paramIsRef && !parameterInfo.Type.IsConst)
|
||||||
|
{
|
||||||
|
// Direct value convert
|
||||||
|
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, out var managedType, out var apiType, null, out _);
|
||||||
|
var passAsParamPtr = managedType.EndsWith("*");
|
||||||
|
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
|
||||||
|
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
|
||||||
|
if (!string.IsNullOrEmpty(managedToNative))
|
||||||
|
{
|
||||||
|
if (!passAsParamPtr)
|
||||||
|
paramValue = '*' + paramValue;
|
||||||
|
paramValue = string.Format(managedToNative, paramValue);
|
||||||
|
}
|
||||||
|
else if (!passAsParamPtr)
|
||||||
|
paramValue = '*' + paramValue;
|
||||||
|
contents.Append($" {parameterInfo.Name} = {paramValue};").AppendLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unbox returned value
|
contents.AppendLine(" WrapperCallInstance = prevWrapperCallInstance;");
|
||||||
|
contents.AppendLine(" if (exception)");
|
||||||
|
contents.AppendLine(" DebugLog::LogException(exception);");
|
||||||
|
|
||||||
|
// Unpack returned value
|
||||||
if (!returnType.IsVoid)
|
if (!returnType.IsVoid)
|
||||||
{
|
{
|
||||||
if (returnType.IsRef)
|
if (returnType.IsRef)
|
||||||
throw new NotSupportedException($"Passing return value by reference is not supported for virtual API methods. Used on method '{functionInfo}'.");
|
throw new NotSupportedException($"Passing return value by reference is not supported for virtual API methods. Used on method '{functionInfo}'.");
|
||||||
|
if (useThunk)
|
||||||
// mono_runtime_invoke always returns boxed value as MonoObject*, but thunk might return value within pointer (eg. as int or boolean)
|
|
||||||
contents.AppendLine("#if USE_MONO_AOT");
|
|
||||||
contents.AppendLine($" return MUtils::Unbox<{returnType}>(__result);");
|
|
||||||
contents.AppendLine("#else");
|
|
||||||
switch (returnType.Type)
|
|
||||||
{
|
{
|
||||||
case "bool":
|
// Thunk might return value within pointer (eg. as int or boolean)
|
||||||
contents.AppendLine(" return __result != 0;");
|
switch (returnType.Type)
|
||||||
break;
|
{
|
||||||
case "int8":
|
case "bool":
|
||||||
case "int16":
|
contents.AppendLine(" return __result != 0;");
|
||||||
case "int32":
|
break;
|
||||||
case "int64":
|
case "int8":
|
||||||
contents.AppendLine($" return ({returnType.Type})(intptr)__result;");
|
case "int16":
|
||||||
break;
|
case "int32":
|
||||||
case "uint8":
|
case "int64":
|
||||||
case "uint16":
|
contents.AppendLine($" return ({returnType.Type})(intptr)__result;");
|
||||||
case "uint32":
|
break;
|
||||||
case "uint64":
|
case "uint8":
|
||||||
contents.AppendLine($" return ({returnType.Type})(uintptr)__result;");
|
case "uint16":
|
||||||
break;
|
case "uint32":
|
||||||
default:
|
case "uint64":
|
||||||
contents.AppendLine($" return MUtils::Unbox<{returnType}>(__result);");
|
contents.AppendLine($" return ({returnType.Type})(uintptr)__result;");
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
contents.AppendLine($" return MUtils::Unbox<{returnType}>(__result);");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// mono_runtime_invoke always returns boxed value as MonoObject*
|
||||||
|
contents.AppendLine($" return MUtils::Unbox<{returnType}>(__result);");
|
||||||
}
|
}
|
||||||
contents.AppendLine("#endif");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
contents.AppendLine(" }");
|
contents.AppendLine(" }");
|
||||||
|
|||||||
@@ -106,6 +106,11 @@ namespace Flax.Build
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasExecutableFileReferenceSupport => false;
|
public virtual bool HasExecutableFileReferenceSupport => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether that platform supports executing native code generated dynamically (JIT), otherwise requires ahead-of-time compilation (AOT).
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool HasDynamicCodeExecutionSupport => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the executable file extension (including leading dot).
|
/// Gets the executable file extension (including leading dot).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ namespace Flax.Build.Platforms
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override TargetPlatform Target => TargetPlatform.UWP;
|
public override TargetPlatform Target => TargetPlatform.UWP;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool HasDynamicCodeExecutionSupport => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="UWPPlatform"/> class.
|
/// Initializes a new instance of the <see cref="UWPPlatform"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user