public override void ConvertToLIR(LIRMethod pLIRMethod)
		{
			Label[] lbls = new Label[TargetIRInstructions.Length];
			for (int i = 0; i < lbls.Length; i++)
			{
				lbls[i] = TargetIRInstructions[i].Label;
			}
			var swDatItem = new SwitchEmittableDataItem(lbls);
			pLIRMethod.CompileUnit.AddData(swDatItem);

			// Need to load and compare original value first...
			var vs = pLIRMethod.RequestLocal(Sources[0].GetTypeOfLocation());
			Sources[0].LoadTo(pLIRMethod, vs);
			var vt = pLIRMethod.RequestLocal(AppDomain.System_Boolean);
			new LIRInstructions.Compare(pLIRMethod, vs, (LIRImm)0, vt, vs.Type, LIRInstructions.CompareCondition.LessThan);
			new LIRInstructions.BranchTrue(pLIRMethod, vt, ParentMethod.Instructions[this.IRIndex + 1].Label);
			new LIRInstructions.Compare(pLIRMethod, vs, (LIRImm)lbls.Length, vt, vs.Type, LIRInstructions.CompareCondition.GreaterThan);
			new LIRInstructions.BranchTrue(pLIRMethod, vt, ParentMethod.Instructions[this.IRIndex + 1].Label);
			pLIRMethod.ReleaseLocal(vt);
			var sBase = pLIRMethod.RequestLocal(AppDomain.System_UIntPtr);
			new LIRInstructions.Move(pLIRMethod, swDatItem.Label, sBase, AppDomain.System_UIntPtr);
			new LIRInstructions.Math(pLIRMethod, vs, (LIRImm)VMConfig.PointerSizeForTarget, vs, LIRInstructions.MathOperation.Multiply, vs.Type);
			new LIRInstructions.Math(pLIRMethod, vs, sBase, sBase, LIRInstructions.MathOperation.Add, sBase.Type);
			pLIRMethod.ReleaseLocal(vs);
			new LIRInstructions.Move(pLIRMethod, new Indirect(sBase), sBase, sBase.Type);
			new LIRInstructions.BranchIndirect(pLIRMethod, sBase);
			pLIRMethod.ReleaseLocal(sBase);
		}
		public static void EmitStaticConstructorCheck(LIRMethod m, IRType targetType, IRType curType, bool forceEmit = false)
		{
			if (targetType.HasStaticConstructor && (forceEmit || targetType != curType))
			{
				var con = targetType.StaticConstructor;
				if (
					(
						con.Instructions.Count == 1 &&
						con.Instructions[0].Opcode == IROpcode.Return
					) ||
					(
						con.Instructions.Count == 2 &&
						con.Instructions[0].Opcode == IROpcode.Nop &&
						con.Instructions[1].Opcode == IROpcode.Return
					)
				)
				{
					// We don't need a static constructor call
				}
				else
				{
					StaticConstructorCalledEmittableDataItem d = null;
					if (!KnownStaticConstructors.TryGetValue(targetType, out d))
					{
						d = new StaticConstructorCalledEmittableDataItem(targetType);
						m.CompileUnit.AddData(d);
						KnownStaticConstructors.Add(targetType, d);
					}
					new LIRInstructions.Comment(m, "Static Constructor Check");
					var c = m.RequestLocal(targetType.Assembly.AppDomain.System_Boolean);
					new LIRInstructions.Move(m, new Indirect(d.Label), c, targetType.Assembly.AppDomain.System_Boolean);
					Label called = new Label();
					new LIRInstructions.BranchTrue(m, c, called);
					m.ReleaseLocal(c);
					new LIRInstructions.Move(m, (LIRImm)1, new Indirect(d.Label), targetType.Assembly.AppDomain.System_Boolean);
					new LIRInstructions.Call(m, con);
					m.MarkLabel(called);
				}
			}
		}
		public override void ConvertToLIR(LIRMethod pLIRMethod)
		{
			var src = pLIRMethod.RequestLocal(Sources[0].GetTypeOfLocation());
			Sources[0].LoadTo(pLIRMethod, src);
			var dest = pLIRMethod.RequestLocal(Destination.GetTypeOfLocation());
			var canCastResult = pLIRMethod.RequestLocal(ParentMethod.Assembly.AppDomain.System_Boolean);
			var getTypeByGlobalTypeIDResult = pLIRMethod.RequestLocal(ParentMethod.Assembly.AppDomain.System_Type);

			// Call to Proton.Runtime.RuntimeHelpers.GetTypeByGlobalTypeID method, which returns the runtime System.Type
			new LIRInstructions.Call(pLIRMethod, ParentMethod.Assembly.AppDomain.Proton_Runtime_RuntimeHelpers_GetTypeByGlobalTypeID.LIRMethod, new List<ISource>(1) { (LIRImm)Type.GlobalTypeID }, getTypeByGlobalTypeIDResult);

			// Call to Proton.Runtime.RuntimeHelpers.CanCast method, which determines if an object can be cast to a type
			// TODO: can src be a value type? if so then we may need to box it first to pass it into this call as an object
			// TODO: this method should throw an exception if the Type is null, so we can skip testing castType before the call
			new LIRInstructions.Call(pLIRMethod, ParentMethod.Assembly.AppDomain.Proton_Runtime_RuntimeHelpers_CanCast.LIRMethod, new List<ISource>(2) { src, getTypeByGlobalTypeIDResult }, canCastResult);

			// Don't need getTypeByGlobalTypeIDResult anymore, we have canCastResult
			pLIRMethod.ReleaseLocal(getTypeByGlobalTypeIDResult);

			// Branch if we can cast, fall through if we cannot
			LIRInstructions.BranchTrue canCastBranchTrue = new LIRInstructions.BranchTrue(pLIRMethod, canCastResult);

			// Getting here means CanCast returned false, so the emitted code depends on ThrowExceptionOnFailure
			if (!ThrowExceptionOnFailure)
			{
				// If we don't throw an exception, then we are expected to set the destination to it's default value (null, 0, etc)
				new LIRInstructions.Move(pLIRMethod, dest.Type.Empty, dest, dest.Type);
			}
			// Now we jump past the previous BranchTrue logic below
			LIRInstructions.Branch cannotCastBranchOut = new LIRInstructions.Branch(pLIRMethod);
			// Getting here means CanCast returned true, so we need to set the BranchTrue target label
			canCastBranchTrue.SetTarget(new Label());
			// And now copy src to dest, based on the destination casted type
			// TODO: Is it safe to use src here, after it was passed as a source to the Call above?
			new LIRInstructions.Move(pLIRMethod, src, dest, dest.Type);

			cannotCastBranchOut.SetTarget(new Label());

			// We're done with src now, clean that up
			pLIRMethod.ReleaseLocal(src);

			if (!ThrowExceptionOnFailure)
			{
				// If we don't throw an exception, then we end up moving null to destination
				// so we can just do a normal cleanup and store here
				pLIRMethod.ReleaseLocal(canCastResult);
				Destination.StoreTo(pLIRMethod, dest);
				pLIRMethod.ReleaseLocal(dest);
			}
			else
			{
				// Branch if we can cast, fall through if we cannot
				canCastBranchTrue = new LIRInstructions.BranchTrue(pLIRMethod, canCastResult);
				// Getting here means we were not able to cast, so we need to cleanup before we throw an
				// exception, but we do not store anything to the destination
				pLIRMethod.ReleaseLocal(canCastResult);
				pLIRMethod.ReleaseLocal(dest);

				// TODO: Throw exception here, Branch is here to loop infinite, but this is not valid
				// it is here only as a placeholder, we need to prepare the object being thrown in a
				// way that the reference is held until an exception handler has the reference
				Label loopLabel = new Label();
				new LIRInstructions.Comment(pLIRMethod, "TODO: Replace this infinite loop with Throw logic");
				new LIRInstructions.Branch(pLIRMethod, loopLabel);

				// Getting here means we were able to cast, just do a normal cleanup
				canCastBranchTrue.SetTarget(new Label());
				pLIRMethod.ReleaseLocal(canCastResult);
				Destination.StoreTo(pLIRMethod, dest);
				pLIRMethod.ReleaseLocal(dest);
			}
			// Fall through to next IR instruction if we had a successful cast, or failed without
			// throwing an exception
		}
Beispiel #4
0
		public void MarkLabel(Label l)
		{
			l.Index = mInstructions.Count;
			mInstructions.Add(l);
		}