public void LoadCompiledFunctions(List <CKlaxScriptTypeInfo> types, List <CKlaxScriptFunctionInfo> libraryFunctions) { DirectoryInfo info = new DirectoryInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); m_compiledAssemblyPath = info + "\\" + ASSEMBLY_PATH; if (File.Exists(m_compiledAssemblyPath)) { Assembly newAssembly = Assembly.LoadFrom(m_compiledAssemblyPath); foreach (var type in newAssembly.DefinedTypes) { MethodInfo method = type.GetMethod(METHOD_NAME, BindingFlags.Static | BindingFlags.Public); if (method != null) { KlaxScriptFunctionSignature del = (KlaxScriptFunctionSignature)Delegate.CreateDelegate(typeof(KlaxScriptFunctionSignature), null, method); FieldInfo locationInfo = type.GetField(METHOD_LOCATION_NAME, BindingFlags.Public | BindingFlags.Static); EKlaxFunctionLocation location = (EKlaxFunctionLocation)locationInfo.GetValue(null); switch (location) { case EKlaxFunctionLocation.Type: { FieldInfo typeIndexInfo = type.GetField(TYPE_INDEX_NAME, BindingFlags.Public | BindingFlags.Static); int typeIndex = (int)typeIndexInfo.GetValue(null); FieldInfo functionIndexInfo = type.GetField(FUNCTION_INDEX_NAME, BindingFlags.Public | BindingFlags.Static); int functionIndex = (int)functionIndexInfo.GetValue(null); types[typeIndex].Functions[functionIndex].compiledMethod = del; } break; case EKlaxFunctionLocation.Library: { FieldInfo functionIndexInfo = type.GetField(FUNCTION_INDEX_NAME, BindingFlags.Public | BindingFlags.Static); int functionIndex = (int)functionIndexInfo.GetValue(null); libraryFunctions[functionIndex].compiledMethod = del; } break; } } } } }
private void GenerateMethod(CKlaxScriptFunctionInfo function, EKlaxFunctionLocation location, int typeIndex, int functionIndex) { MethodInfo methodInfo = function.methodInfo; ParameterInfo[] parameters = methodInfo.GetParameters(); ParameterInfo[] outParameters = parameters.Where(param => param.IsOut || (param.ParameterType.IsByRef && !param.IsIn)).ToArray(); ParameterInfo[] inRefParameters = parameters.Where(param => param.ParameterType.IsByRef && param.IsIn).ToArray(); ParameterInfo returnParameter = methodInfo.ReturnParameter; //Check if any invalid parameters are detected TypeBuilder typeBuilder = m_moduleBuilder.DefineType(methodInfo.DeclaringType + "_" + methodInfo.Name + "_Type", TypeAttributes.Public); //Build MethodInfo field to map generated type to method info FieldBuilder methodLocationFieldBuilder = typeBuilder.DefineField(METHOD_LOCATION_NAME, typeof(EKlaxFunctionLocation), FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.HasDefault | FieldAttributes.Literal); methodLocationFieldBuilder.SetConstant(location); FieldBuilder typeIndexFieldBuilder = typeBuilder.DefineField(TYPE_INDEX_NAME, typeof(int), FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.HasDefault | FieldAttributes.Literal); typeIndexFieldBuilder.SetConstant(typeIndex); FieldBuilder functionIndexFieldBuilder = typeBuilder.DefineField(FUNCTION_INDEX_NAME, typeof(int), FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.HasDefault | FieldAttributes.Literal); functionIndexFieldBuilder.SetConstant(functionIndex); //Build execution method MethodBuilder methodBuilder = typeBuilder.DefineMethod(METHOD_NAME, MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, CallingConventions.Standard, null, new Type[] { m_genericObjectListType, m_genericObjectListType }); ILGenerator generator = methodBuilder.GetILGenerator(); bool bHasReturnType = returnParameter.ParameterType != typeof(void); bool bIsStaticFunction = methodInfo.IsStatic; int returnParameterCount = 0; int outParameterCount = 0; int inRefParameterCount = 0; if (returnParameter.ParameterType != typeof(void)) { generator.DeclareLocal(returnParameter.ParameterType); returnParameterCount++; } foreach (var outParam in outParameters) { generator.DeclareLocal(outParam.ParameterType.IsByRef ? outParam.ParameterType.GetElementType() : outParam.ParameterType); outParameterCount = outParameters.Length; } foreach (var inParam in inRefParameters) { generator.DeclareLocal(inParam.ParameterType.GetElementType()); inRefParameterCount = inRefParameters.Length; } //Fill local variables for in ref parameters of desired function for (int i = 0, length = inRefParameters.Length; i < length; i++) { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldc_I4_S, (sbyte)(Array.IndexOf(parameters, inRefParameters[i]) + (bIsStaticFunction ? 0 : 1))); generator.Emit(OpCodes.Callvirt, m_genericObjectListGetter); Type underlyingType = inRefParameters[i].ParameterType.GetElementType(); if (underlyingType.IsValueType) { generator.Emit(OpCodes.Unbox_Any, underlyingType); } generator.Emit(OpCodes.Stloc, (short)(returnParameterCount + outParameterCount + i)); } //If we call a member function, convert the first argument into the target type and put onto evaluation stack if (!bIsStaticFunction) { generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldc_I4_0); generator.Emit(OpCodes.Callvirt, m_genericObjectListGetter); generator.Emit(OpCodes.Castclass, methodInfo.DeclaringType); } for (int i = 0, length = parameters.Length; i < length; i++) { if (parameters[i].IsOut) { //Put out parameters onto evaluation stack generator.Emit(OpCodes.Ldloca_S, (byte)(Array.IndexOf(outParameters, parameters[i]) + (bHasReturnType ? 1 : 0))); } else if (parameters[i].IsIn && parameters[i].ParameterType.IsByRef) { generator.Emit(OpCodes.Ldloca_S, (byte)(Array.IndexOf(inRefParameters, parameters[i]) + returnParameterCount + outParameterCount)); } else { PutObjectOntoEvaluationStack_IL(generator, i - GetOutParametersBefore(i, parameters) + (bIsStaticFunction ? 0 : 1), parameters[i].ParameterType); } } generator.Emit(OpCodes.Call, methodInfo); if (returnParameter.ParameterType != typeof(void)) { //Store return value in output list generator.Emit(OpCodes.Stloc_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Ldloc_0); AddObjectToObjectList_IL(generator, returnParameter.ParameterType); } if (outParameters.Length > 0) { for (int i = 0, length = outParameters.Length; i < length; i++) { generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Ldloc, (short)(i + (bHasReturnType ? 1 : 0))); AddObjectToObjectList_IL(generator, outParameters[i].ParameterType); } } generator.Emit(OpCodes.Ret); typeBuilder.CreateType(); }