public Instruction GetInstruction(Instruction instruction) { _usages++; if (OpCodeHelper.IsLoadArg(instruction)) { if (_usages == 1) { return(Defer()); } ProcessDeferred(); return(GetLdArgInstruction()); } ProcessDeferred(); if (OpCodeHelper.IsLoadArgA(instruction)) { return(OpCodeHelper.CreateLoadLocA(GetVariableDefinition())); } if (OpCodeHelper.IsStoreArg(instruction)) { return(OpCodeHelper.CreateStoreLoc(GetVariableDefinition())); } throw new NotSupportedException($"Unknown arg instruction {instruction.OpCode}"); }
private Instruction GetLdArgInstruction() { if (CanInline) { var ldArgInstruction = OpCodeHelper.Clone(_pushInstruction); _inlinedInstructions.Add(ldArgInstruction); return(ldArgInstruction); } return(OpCodeHelper.CreateLoadLoc(GetVariableDefinition())); }
public void Finish() { if (_deferredInstruction != null) { // keep on stack if (KeepOnStack) { _inlineMethodWeaver.Remove(_deferredInstruction); _deferredInstruction = null; return; } } ProcessDeferred(); if (_variableDefinition == null) { if (CanRemovePush) { _inlineMethodWeaver.Remove(_pushInstruction); } else { // neutralize push instruction if (_pushInstruction == null) { InsertConsumeTopArg(Instruction.Create(OpCodes.Pop)); } else { for (var i = 0; i < _pushInstruction.GetPushCount(); i++) { _inlineMethodWeaver.InsertAfter(_pushInstruction, Instruction.Create(OpCodes.Pop)); } } } } else { // place store loc var storeLoc = OpCodeHelper.CreateStoreLoc(_variableDefinition); if (_pushInstruction == null) { InsertConsumeTopArg(storeLoc); } else { _inlineMethodWeaver.InsertAfter(_pushInstruction, storeLoc); } } _inlineMethodWeaver._argStack.Consume(this); }
private void ProcessDeferred() { if (_deferredInstruction != null) { var ldArgInstruction = GetLdArgInstruction(); OpCodeHelper.ReplaceInstruction(_deferredInstruction, ldArgInstruction); if (_inlinedInstructions.Count > 0 && _inlinedInstructions[_inlinedInstructions.Count - 1] == ldArgInstruction) { _inlinedInstructions[_inlinedInstructions.Count - 1] = _deferredInstruction; } _deferredInstruction = null; } }
private VariableDefinition GetVariableDefinition() { if (_variableDefinition == null) { _variableDefinition = new VariableDefinition(_inlineMethodWeaver._parameters[_paramIndex].ParameterType); _inlineMethodWeaver._parentMethod.Body.Variables.Add(_variableDefinition); // revert inline if (_inlinedInstructions.Count > 0) { foreach (var inlinedInstruction in _inlinedInstructions) { OpCodeHelper.ReplaceInstruction(inlinedInstruction, OpCodeHelper.CreateLoadLoc(_variableDefinition)); } _inlinedInstructions.Clear(); } } return(_variableDefinition); }
public void Process() { CreateVars(); CreateArgs(); var innerVariables = _method.Body.Variables; var parentVariables = _parentMethod.Body.Variables; var isLoadArgs = true; // inline body var instructions = _method.Body.Instructions; foreach (var instruction in instructions) { var nextInstruction = instruction.Next; Instruction newInstruction = null; // arg var parameterDefinition = OpCodeHelper.GetArgParameterDefinition(instruction, _parameters); if (parameterDefinition != null) { var arg = _args[parameterDefinition.Sequence]; newInstruction = arg.GetInstruction(instruction); if (isLoadArgs) { if (OpCodeHelper.IsLoadArg(instruction) && arg.IsDeferred) { _firstLoadArgs.Add(new LoadArgInfo(parameterDefinition.Sequence)); } else { isLoadArgs = false; } } } else { if (isLoadArgs && instruction.OpCode != OpCodes.Nop) { isLoadArgs = false; } } // loc var innerVariableDefinition = OpCodeHelper.GetLocVariableDefinition(instruction, innerVariables); if (innerVariableDefinition != null) { newInstruction = OpCodeHelper.CreateVarInstruction(instruction, parentVariables[innerVariableDefinition.Index + _firstInnerVariableIndex]); } // branch if (instruction.OpCode.OperandType == OperandType.InlineBrTarget || instruction.OpCode.OperandType == OperandType.ShortInlineBrTarget) { var target = (Instruction)instruction.Operand; // fix target ret if (target?.OpCode.Code == Code.Ret) { newInstruction = Instruction.Create(instruction.OpCode, _callInstruction.Next); } } // ret if (instruction.OpCode.Code == Code.Ret) { // skip last return if (nextInstruction == null) { break; } newInstruction = Instruction.Create(OpCodes.Br, _callInstruction.Next); } if (newInstruction == null) { newInstruction = OpCodeHelper.Clone(instruction); } _instructionMap[instruction] = newInstruction; AppendToBody(newInstruction); } FinishArgs(); Remove(_callInstruction); // replace call target if (_firstBodyInstruction != null || _beforeBodyInstruction != null) { _instructionMap[_callInstruction] = _beforeBodyInstruction ?? _firstBodyInstruction; } FixInstructions(); }
private void FixInstructions() { // TODO: optimize (do once per parent method) // fix targets, extend instructions var instruction = _parentMethod.Body.Instructions.FirstOrDefault(); var offset = 0; var shortBranchInstructions = new List <Instruction>(); while (instruction != null) { var nextInstruction = instruction.Next; if (instruction.Operand is Instruction opInstruction) { if (GetInstructionFromMap(opInstruction, out var newInstruction)) { instruction.Operand = newInstruction; } } else if (instruction.Operand is Instruction[] opInstructions) { for (var index = 0; index < opInstructions.Length; index++) { if (GetInstructionFromMap(opInstructions[index], out var newInstruction)) { opInstructions[index] = newInstruction; } } } if (instruction.OpCode.OperandType == OperandType.ShortInlineBrTarget) { shortBranchInstructions.Add(instruction); } // extend short variable instructions to long if needed OpCodeHelper.ExtendVariableOpCode(instruction); instruction.Offset = offset; offset += instruction.GetSize(); instruction = nextInstruction; } // extend short branch instructions if needed bool wasExtended; do { wasExtended = false; for (var i = shortBranchInstructions.Count - 1; i >= 0; i--) { var shortBranchInstruction = shortBranchInstructions[i]; var target = (Instruction)shortBranchInstruction.Operand; var diff = target.Offset - shortBranchInstruction.Offset - shortBranchInstruction.GetSize(); if (diff < sbyte.MinValue || diff > sbyte.MaxValue) { OpCodeHelper.ExtendBranchOpCode(shortBranchInstruction); shortBranchInstructions.RemoveAt(i); wasExtended = true; } } if (wasExtended && shortBranchInstructions.Count > 0) { CalcParentMethodOffsets(); } } while (wasExtended); }