/// <summary> /// Writes an <see cref="OperandType.InlineSwitch"/> operand /// </summary> /// <param name="writer">Instruction writer</param> /// <param name="instr">Instruction</param> protected virtual void WriteInlineSwitch(ref ArrayWriter writer, Instruction instr) { var targets = instr.Operand as IList <Instruction>; if (targets is null) { Error("switch operand is not a list of instructions"); writer.WriteInt32(0); } else { uint offsetAfter = (uint)(ToInstructionOffset(ref writer) + 4 + targets.Count * 4); writer.WriteInt32(targets.Count); for (int i = 0; i < targets.Count; i++) { var target = targets[i]; writer.WriteUInt32(GetOffset(target) - offsetAfter); } } }
/// <summary> /// Writes a <see cref="OperandType.ShortInlineVar"/> operand /// </summary> /// <param name="writer">Instruction writer</param> /// <param name="instr">Instruction</param> protected virtual void WriteShortInlineVar(ref ArrayWriter writer, Instruction instr) { var variable = instr.Operand as IVariable; if (variable is null) { Error("Operand is not a local/arg"); writer.WriteByte(0); } else { int index = variable.Index; if (byte.MinValue <= index && index <= byte.MaxValue) { writer.WriteByte((byte)index); } else { Error("Local/arg index doesn't fit in a Byte. Use the longer ldloc/ldarg/stloc/starg instruction."); writer.WriteByte(0); } } }
/// <summary> /// Writes an <see cref="OperandType.InlineVar"/> operand /// </summary> /// <param name="writer">Instruction writer</param> /// <param name="instr">Instruction</param> protected virtual void WriteInlineVar(ref ArrayWriter writer, Instruction instr) { var variable = instr.Operand as IVariable; if (variable is null) { Error("Operand is not a local/arg"); writer.WriteUInt16(0); } else { int index = variable.Index; if (ushort.MinValue <= index && index <= ushort.MaxValue) { writer.WriteUInt16((ushort)index); } else { Error("Local/arg index doesn't fit in a UInt16"); writer.WriteUInt16(0); } } }
/// <summary> /// Writes an <see cref="OperandType.InlineType"/> operand /// </summary> /// <param name="writer">Instruction writer</param> /// <param name="instr">Instruction</param> protected abstract void WriteInlineType(ref ArrayWriter writer, Instruction instr);
/// <summary> /// Writes an <see cref="OperandType.InlinePhi"/> operand /// </summary> /// <param name="writer">Instruction writer</param> /// <param name="instr">Instruction</param> protected virtual void WriteInlinePhi(ref ArrayWriter writer, Instruction instr) { }
/// <summary> /// Writes an <see cref="OperandType.InlineBrTarget"/> operand /// </summary> /// <param name="writer">Instruction writer</param> /// <param name="instr">Instruction</param> protected virtual void WriteInlineBrTarget(ref ArrayWriter writer, Instruction instr) { uint displ = GetOffset(instr.Operand as Instruction) - (ToInstructionOffset(ref writer) + 4); writer.WriteUInt32(displ); }
/// <summary> /// Writes an instruction /// </summary> /// <param name="writer">The instruction writer</param> /// <param name="instr">The instruction</param> protected virtual void WriteInstruction(ref ArrayWriter writer, Instruction instr) { WriteOpCode(ref writer, instr); WriteOperand(ref writer, instr); }
/// <summary> /// Gets the current offset in the instruction stream. This offset is relative to /// the first written instruction. /// </summary> /// <param name="writer">The instruction writer</param> /// <returns>Current offset, relative to the first written instruction</returns> protected uint ToInstructionOffset(ref ArrayWriter writer) => (uint)writer.Position - firstInstructionOffset;