<commit_before>﻿/*
 * (c) 2012 MOSA - The Managed Operating System Alliance
 *
 * Licensed under the terms of the New BSD License.
 *
 * Authors:
 *  <NAME> (tgiphil) <<EMAIL>>
 *  <NAME> (rootnode) <<EMAIL>>
 */

using System.Collections.Generic;
using Mosa.Compiler.Metadata;
using Mosa.Compiler.TypeSystem;
using Mosa.Compiler.Framework.IR;
using Mosa.Compiler.Metadata.Signatures;

namespace Mosa.Compiler.Framework
{
	/// <summary>
	/// 
	/// </summary>
	public static class DelegatePatcher
	{

		/// <summary>
		/// Patches the delegate.
		/// </summary>
		/// <param name="methodCompiler">The method compiler.</param>
		/// <returns></returns>
		public static bool PatchDelegate(BaseMethodCompiler methodCompiler)
		{
			if (!methodCompiler.Method.DeclaringType.IsDelegate)
				return false;

			switch (methodCompiler.Method.Name)
			{
				case ".ctor": PatchConstructor(methodCompiler); return true;
				case "Invoke": PatchInvoke(methodCompiler, false); return true;
				case "InvokeWithReturn": PatchInvoke(methodCompiler, true); return true;
				case "BeginInvoke": PatchBeginInvoke(methodCompiler); return true;
				case "EndInvoke": PatchEndInvoke(methodCompiler); return true;
				default: return false;
			}
		}

		private static void PatchConstructor(BaseMethodCompiler methodCompiler)
		{
			Operand thisOperand = methodCompiler.Parameters[0];
			Operand instanceOperand = methodCompiler.Parameters[1];
			Operand methodPointerOperand = methodCompiler.Parameters[2];

			RuntimeField methodPointerField = GetField(methodCompiler.Method.DeclaringType, "methodPointer");
			int methodPointerOffset = methodCompiler.TypeLayout.GetFieldOffset(methodPointerField);
			Operand methodPointerOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, methodPointerOffset);

			RuntimeField instanceField = GetField(methodCompiler.Method.DeclaringType, "instance");
			int instanceOffset = methodCompiler.TypeLayout.GetFieldOffset(instanceField);
			Operand instanceOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, instanceOffset);

			Context context = CreateMethodStructure(methodCompiler, true);

			context.AppendInstruction(IRInstruction.Store, null, thisOperand, methodPointerOffsetOperand, methodPointerOperand);
			context.AppendInstruction(IRInstruction.Store, null, thisOperand, instanceOffsetOperand, instanceOperand);
			context.AppendInstruction(IRInstruction.Return, methodCompiler.BasicBlocks.EpilogueBlock);
			context.SetBranch(BasicBlock.EpilogueLabel);
		}

		private static void PatchInvoke(BaseMethodCompiler methodCompiler, bool withReturn)
		{
			// check if instance is null (if so, it's a static call to the methodPointer)

			Operand thisOperand = methodCompiler.Parameters[0];

			RuntimeField methodPointerField = GetField(methodCompiler.Method.DeclaringType, "methodPointer");
			int methodPointerOffset = methodCompiler.TypeLayout.GetFieldOffset(methodPointerField);
			Operand methodPointerOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, methodPointerOffset);

			RuntimeField instanceField = GetField(methodCompiler.Method.DeclaringType, "instance");
			int instanceOffset = methodCompiler.TypeLayout.GetFieldOffset(instanceField);
			Operand instanceOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, instanceOffset);

			Operand opMethod = methodCompiler.StackLayout.AllocateStackOperand(BuiltInSigType.UInt32, false);
			Operand opInstance = methodCompiler.StackLayout.AllocateStackOperand(thisOperand.Type, false);
			Operand opCompare = methodCompiler.StackLayout.AllocateStackOperand(BuiltInSigType.Int32, false);

			Operand opReturn = withReturn ? methodCompiler.StackLayout.AllocateStackOperand(BuiltInSigType.Object, false) : null;
			Operand c0 = Operand.CreateConstant(BuiltInSigType.Int32, 0);

			Context b0 = CreateMethodStructure(methodCompiler, false);
			Context b1 = CreateNewBlock(methodCompiler);
			Context b2 = CreateNewBlock(methodCompiler);
			Context b3 = CreateNewBlock(methodCompiler);

			b0.AppendInstruction(IRInstruction.Load, opMethod, thisOperand, methodPointerOffsetOperand);
			b0.AppendInstruction(IRInstruction.Load, opInstance, thisOperand, instanceOffsetOperand);
			b0.AppendInstruction(IRInstruction.IntegerCompare, ConditionCode.Equal, opCompare, opInstance, c0);
			b0.AppendInstruction(IRInstruction.IntegerCompareBranch, ConditionCode.NotEqual, null, opCompare, c0);<commit_msg>- Fixed test failure CallInstanceDelegate (fixes #99)<commit_after>﻿/*
 * (c) 2012 MOSA - The Managed Operating System Alliance
 *
 * Licensed under the terms of the New BSD License.
 *
 * Authors:
 *  <NAME> (tgiphil) <<EMAIL>>
 *  <NAME> (rootnode) <<EMAIL>>
 */

using System.Collections.Generic;
using Mosa.Compiler.Metadata;
using Mosa.Compiler.TypeSystem;
using Mosa.Compiler.Framework.IR;
using Mosa.Compiler.Metadata.Signatures;

namespace Mosa.Compiler.Framework
{
	/// <summary>
	/// 
	/// </summary>
	public static class DelegatePatcher
	{

		/// <summary>
		/// Patches the delegate.
		/// </summary>
		/// <param name="methodCompiler">The method compiler.</param>
		/// <returns></returns>
		public static bool PatchDelegate(BaseMethodCompiler methodCompiler)
		{
			if (!methodCompiler.Method.DeclaringType.IsDelegate)
				return false;

			switch (methodCompiler.Method.Name)
			{
				case ".ctor": PatchConstructor(methodCompiler); return true;
				case "Invoke": PatchInvoke(methodCompiler, false); return true;
				case "InvokeWithReturn": PatchInvoke(methodCompiler, true); return true;
				case "BeginInvoke": PatchBeginInvoke(methodCompiler); return true;
				case "EndInvoke": PatchEndInvoke(methodCompiler); return true;
				default: return false;
			}
		}

		private static void PatchConstructor(BaseMethodCompiler methodCompiler)
		{
			Operand thisOperand = methodCompiler.Parameters[0];
			Operand instanceOperand = methodCompiler.Parameters[1];
			Operand methodPointerOperand = methodCompiler.Parameters[2];

			RuntimeField methodPointerField = GetField(methodCompiler.Method.DeclaringType, "methodPointer");
			int methodPointerOffset = methodCompiler.TypeLayout.GetFieldOffset(methodPointerField);
			Operand methodPointerOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, methodPointerOffset);

			RuntimeField instanceField = GetField(methodCompiler.Method.DeclaringType, "instance");
			int instanceOffset = methodCompiler.TypeLayout.GetFieldOffset(instanceField);
			Operand instanceOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, instanceOffset);

			Context context = CreateMethodStructure(methodCompiler, true);

			context.AppendInstruction(IRInstruction.Store, null, thisOperand, methodPointerOffsetOperand, methodPointerOperand);
			context.AppendInstruction(IRInstruction.Store, null, thisOperand, instanceOffsetOperand, instanceOperand);
			context.AppendInstruction(IRInstruction.Return, methodCompiler.BasicBlocks.EpilogueBlock);
			context.SetBranch(BasicBlock.EpilogueLabel);
		}

		private static void PatchInvoke(BaseMethodCompiler methodCompiler, bool withReturn)
		{
			// check if instance is null (if so, it's a static call to the methodPointer)

			Operand thisOperand = methodCompiler.Parameters[0];

			RuntimeField methodPointerField = GetField(methodCompiler.Method.DeclaringType, "methodPointer");
			int methodPointerOffset = methodCompiler.TypeLayout.GetFieldOffset(methodPointerField);
			Operand methodPointerOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, methodPointerOffset);

			RuntimeField instanceField = GetField(methodCompiler.Method.DeclaringType, "instance");
			int instanceOffset = methodCompiler.TypeLayout.GetFieldOffset(instanceField);
			Operand instanceOffsetOperand = Operand.CreateConstant(BuiltInSigType.IntPtr, instanceOffset);

			Operand opMethod = methodCompiler.StackLayout.AllocateStackOperand(BuiltInSigType.UInt32, false);
			Operand opInstance = methodCompiler.StackLayout.AllocateStackOperand(thisOperand.Type, false);
			Operand opCompare = methodCompiler.StackLayout.AllocateStackOperand(BuiltInSigType.Int32, false);

			Operand opReturn = withReturn ? methodCompiler.StackLayout.AllocateStackOperand(BuiltInSigType.Object, false) : null;
			Operand c0 = Operand.CreateConstant(BuiltInSigType.Int32, 0);

			Context b0 = CreateMethodStructure(methodCompiler, false);
			Context b1 = CreateNewBlock(methodCompiler);
			Context b2 = CreateNewBlock(methodCompiler);
			Context b3 = CreateNewBlock(methodCompiler);

			b0.AppendInstruction(IRInstruction.Load, opMethod, thisOperand, methodPointerOffsetOperand);
			b0.AppendInstruction(IRInstruction.Load, opInstance, thisOperand, instanceOffsetOperand);
			b0.AppendInstruction(IRInstruction.IntegerCompare, ConditionCode.Equal, opCompare, opInstance, c0);
			b0.AppendInstruction(IRInstruction.IntegerCompareBranch, ConditionCode.Equal, null, opCompare, c0);
{'fraction_non_alphanumeric': 0.09424793762007007, 'fraction_numerical': 0.006102384450220364, 'mean_word_length': 6.068690095846645, 'pattern_counts': {'":': 10, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2644583', 'n_tokens_mistral': 2592, 'n_tokens_neox': 2391, 'n_words': 497}