internal void Emit(OpCode opcode, CodeEmitterLocal local) { EmitOpCode(opcode, local); }
private void OptimizePatterns() { SetLabelRefCounts(); for (int i = 1; i < code.Count; i++) { if (code[i].opcode == OpCodes.Isinst && code[i + 1].opcode == OpCodes.Ldnull && code[i + 2].opcode == OpCodes.Cgt_Un && (code[i + 3].opcode == OpCodes.Brfalse || code[i + 3].opcode == OpCodes.Brtrue)) { code.RemoveRange(i + 1, 2); } else if (code[i].opcode == OpCodes.Ldelem_I1 && code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 1].ValueInt32 == 255 && code[i + 2].opcode == OpCodes.And) { code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null); code.RemoveRange(i + 1, 2); } else if (code[i].opcode == OpCodes.Ldelem_I1 && code[i + 1].opcode == OpCodes.Conv_I8 && code[i + 2].opcode == OpCodes.Ldc_I8 && code[i + 2].ValueInt64 == 255 && code[i + 3].opcode == OpCodes.And) { code[i] = new OpCodeWrapper(OpCodes.Ldelem_U1, null); code.RemoveRange(i + 2, 2); } else if (code[i].opcode == OpCodes.Ldc_I4 && code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 2].opcode == OpCodes.And) { code[i] = new OpCodeWrapper(OpCodes.Ldc_I4, code[i].ValueInt32 & code[i + 1].ValueInt32); code.RemoveRange(i + 1, 2); } else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Double) // dcmpl || MatchCompare(i, OpCodes.Cgt, OpCodes.Clt_Un, Types.Single)) // fcmpl { PatchCompare(i, OpCodes.Ble_Un, OpCodes.Blt_Un, OpCodes.Bge, OpCodes.Bgt); } else if (MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Double) // dcmpg || MatchCompare(i, OpCodes.Cgt_Un, OpCodes.Clt, Types.Single)) // fcmpg { PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge_Un, OpCodes.Bgt_Un); } else if (MatchCompare(i, OpCodes.Cgt, OpCodes.Clt, Types.Int64)) // lcmp { PatchCompare(i, OpCodes.Ble, OpCodes.Blt, OpCodes.Bge, OpCodes.Bgt); } else if (i < code.Count - 10 && code[i].opcode == OpCodes.Ldc_I4 && code[i + 1].opcode == OpCodes.Dup && code[i + 2].opcode == OpCodes.Ldc_I4_M1 && code[i + 3].opcode == OpCodes.Bne_Un && code[i + 4].opcode == OpCodes.Pop && code[i + 5].opcode == OpCodes.Neg && code[i + 6].opcode == OpCodes.Br && code[i + 7].pseudo == CodeType.Label && code[i + 7].MatchLabel(code[i + 3]) && code[i + 7].Label.Temp == 1 && code[i + 8].opcode == OpCodes.Div && code[i + 9].pseudo == CodeType.Label && code[i + 9].Label == code[i + 6].Label && code[i + 9].Label.Temp == 1) { int divisor = code[i].ValueInt32; if (divisor == -1) { code[i] = code[i + 5]; code.RemoveRange(i + 1, 9); } else { code[i + 1] = code[i + 8]; code.RemoveRange(i + 2, 8); } } else if (i < code.Count - 11 && code[i].opcode == OpCodes.Ldc_I8 && code[i + 1].opcode == OpCodes.Dup && code[i + 2].opcode == OpCodes.Ldc_I4_M1 && code[i + 3].opcode == OpCodes.Conv_I8 && code[i + 4].opcode == OpCodes.Bne_Un && code[i + 5].opcode == OpCodes.Pop && code[i + 6].opcode == OpCodes.Neg && code[i + 7].opcode == OpCodes.Br && code[i + 8].pseudo == CodeType.Label && code[i + 8].MatchLabel(code[i + 4]) && code[i + 8].Label.Temp == 1 && code[i + 9].opcode == OpCodes.Div && code[i + 10].pseudo == CodeType.Label && code[i + 10].MatchLabel(code[i + 7]) && code[i + 10].Label.Temp == 1) { long divisor = code[i].ValueInt64; if (divisor == -1) { code[i] = code[i + 6]; code.RemoveRange(i + 1, 10); } else { code[i + 1] = code[i + 9]; code.RemoveRange(i + 2, 9); } } else if (code[i].opcode == OpCodes.Box && code[i + 1].opcode == OpCodes.Unbox && code[i + 1].Type == code[i].Type) { CodeEmitterLocal local = new CodeEmitterLocal(code[i].Type); code[i] = new OpCodeWrapper(OpCodes.Stloc, local); code[i + 1] = new OpCodeWrapper(OpCodes.Ldloca, local); } else if (i < code.Count - 13 && code[i + 0].opcode == OpCodes.Box && code[i + 1].opcode == OpCodes.Dup && code[i + 2].opcode == OpCodes.Brtrue && code[i + 3].opcode == OpCodes.Pop && code[i + 4].opcode == OpCodes.Ldloca && code[i + 4].Local.LocalType == code[i + 0].Type && code[i + 5].opcode == OpCodes.Initobj && code[i + 5].Type == code[i + 0].Type && code[i + 6].opcode == OpCodes.Ldloc && code[i + 6].Local == code[i + 4].Local && code[i + 7].pseudo == CodeType.ReleaseTempLocal && code[i + 7].Local == code[i + 6].Local && code[i + 8].opcode == OpCodes.Br && code[i + 9].pseudo == CodeType.Label && code[i + 9].MatchLabel(code[i + 2]) && code[i + 9].Label.Temp == 1 && code[i + 10].opcode == OpCodes.Unbox && code[i + 10].Type == code[i + 0].Type && code[i + 11].opcode == OpCodes.Ldobj && code[i + 11].Type == code[i + 0].Type && code[i + 12].pseudo == CodeType.Label && code[i + 12].MatchLabel(code[i + 8]) && code[i + 12].Label.Temp == 1) { code.RemoveRange(i, 13); } // NOTE intentionally not an else, because we want to optimize the code generated by the earlier compare optimization if (i < code.Count - 6 && code[i].opcode.FlowControl == FlowControl.Cond_Branch && code[i + 1].opcode == OpCodes.Ldc_I4 && code[i + 1].ValueInt32 == 1 && code[i + 2].opcode == OpCodes.Br && code[i + 3].pseudo == CodeType.Label && code[i + 3].MatchLabel(code[i]) && code[i + 3].Label.Temp == 1 && code[i + 4].opcode == OpCodes.Ldc_I4 && code[i + 4].ValueInt32 == 0 && code[i + 5].pseudo == CodeType.Label && code[i + 5].MatchLabel(code[i + 2]) && code[i + 5].Label.Temp == 1) { if (code[i].opcode == OpCodes.Bne_Un) { code[i] = new OpCodeWrapper(OpCodes.Ceq, null); code.RemoveRange(i + 1, 5); } else if (code[i].opcode == OpCodes.Beq) { code[i + 0] = new OpCodeWrapper(OpCodes.Ceq, null); code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0); code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null); code.RemoveRange(i + 3, 3); } else if (code[i].opcode == OpCodes.Ble || code[i].opcode == OpCodes.Ble_Un) { code[i] = new OpCodeWrapper(OpCodes.Cgt, null); code.RemoveRange(i + 1, 5); } else if (code[i].opcode == OpCodes.Blt) { code[i] = new OpCodeWrapper(OpCodes.Clt, null); code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0); code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null); code.RemoveRange(i + 3, 3); } else if (code[i].opcode == OpCodes.Blt_Un) { code[i] = new OpCodeWrapper(OpCodes.Clt_Un, null); code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0); code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null); code.RemoveRange(i + 3, 3); } else if (code[i].opcode == OpCodes.Bge || code[i].opcode == OpCodes.Bge_Un) { code[i] = new OpCodeWrapper(OpCodes.Clt, null); code.RemoveRange(i + 1, 5); } else if (code[i].opcode == OpCodes.Bgt) { code[i] = new OpCodeWrapper(OpCodes.Cgt, null); code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0); code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null); code.RemoveRange(i + 3, 3); } else if (code[i].opcode == OpCodes.Bgt_Un) { code[i] = new OpCodeWrapper(OpCodes.Cgt_Un, null); code[i + 1] = new OpCodeWrapper(OpCodes.Ldc_I4, 0); code[i + 2] = new OpCodeWrapper(OpCodes.Ceq, null); code.RemoveRange(i + 3, 3); } } } }
internal CodeEmitterLocal DeclareLocal(Type localType) { CodeEmitterLocal local = new CodeEmitterLocal(localType); EmitPseudoOpCode(CodeType.DeclareLocal, local); return local; }
internal void ReleaseTempLocal(CodeEmitterLocal lb) { EmitPseudoOpCode(CodeType.ReleaseTempLocal, lb); for (int i = 0; i < tempLocals.Length; i++) { if (tempLocals[i] == null) { tempLocals[i] = lb; break; } } }
private int FindLocal(CodeEmitterLocal local) { for (int i = 0; i < code.Count; i++) { if (code[i].pseudo == CodeType.DeclareLocal && code[i].Local == local) { return i; } } // if the local variable isn't declared, it is a temporary that is allocated on demand // (so we can move their usage freely) return 0; }
private void ConvertByRefArgs(CodeEmitter ilgen) { CodeEmitterLocal[] locals = new CodeEmitterLocal[args.Length]; for (int i = args.Length - 1; i >= 0; i--) { Type type = args[i]; if (type.IsByRef) { type = ArrayTypeWrapper.MakeArrayType(type.GetElementType(), 1); } locals[i] = ilgen.DeclareLocal(type); ilgen.Emit(OpCodes.Stloc, locals[i]); } for (int i = 0; i < args.Length; i++) { ilgen.Emit(OpCodes.Ldloc, locals[i]); if (args[i].IsByRef) { ilgen.Emit(OpCodes.Ldc_I4_0); ilgen.Emit(OpCodes.Ldelema, args[i].GetElementType()); } } }
internal sealed override void Generate(CodeGenContext context, CodeEmitter ilgen) { Debug.Assert(Name != null); if(Name == ".ctor") { Debug.Assert(Class == null && type != null); Type[] argTypes = context.ClassLoader.ArgTypeListFromSig(Sig); ConstructorInfo ci = StaticCompiler.GetTypeForMapXml(context.ClassLoader, type).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null); if(ci == null) { throw new InvalidOperationException("Missing .ctor: " + type + "..ctor" + Sig); } ilgen.Emit(opcode, ci); } else { Debug.Assert(Class == null ^ type == null); if(Class != null) { Debug.Assert(Sig != null); MethodWrapper method = context.ClassLoader.LoadClassByDottedName(Class).GetMethodWrapper(Name, Sig, false); if(method == null) { throw new InvalidOperationException("method not found: " + Class + "." + Name + Sig); } method.Link(); // TODO this code is part of what Compiler.CastInterfaceArgs (in compiler.cs) does, // it would be nice if we could avoid this duplication... TypeWrapper[] argTypeWrappers = method.GetParameters(); for(int i = 0; i < argTypeWrappers.Length; i++) { if(argTypeWrappers[i].IsGhost) { CodeEmitterLocal[] temps = new CodeEmitterLocal[argTypeWrappers.Length + (method.IsStatic ? 0 : 1)]; for(int j = temps.Length - 1; j >= 0; j--) { TypeWrapper tw; if(method.IsStatic) { tw = argTypeWrappers[j]; } else { if(j == 0) { tw = method.DeclaringType; } else { tw = argTypeWrappers[j - 1]; } } if(tw.IsGhost) { tw.EmitConvStackTypeToSignatureType(ilgen, null); } temps[j] = ilgen.DeclareLocal(tw.TypeAsSignatureType); ilgen.Emit(OpCodes.Stloc, temps[j]); } for(int j = 0; j < temps.Length; j++) { ilgen.Emit(OpCodes.Ldloc, temps[j]); } break; } } if(opcode.Value == OpCodes.Call.Value) { method.EmitCall(ilgen); } else if(opcode.Value == OpCodes.Callvirt.Value) { method.EmitCallvirt(ilgen); } else if(opcode.Value == OpCodes.Newobj.Value) { method.EmitNewobj(ilgen); } else { // ldftn or ldvirtftn ilgen.Emit(opcode, (MethodInfo)method.GetMethod()); } } else { Type[] argTypes; if(Sig.StartsWith("(")) { argTypes = context.ClassLoader.ArgTypeListFromSig(Sig); } else if(Sig == "") { argTypes = Type.EmptyTypes; } else { string[] types = Sig.Split(';'); argTypes = new Type[types.Length]; for(int i = 0; i < types.Length; i++) { argTypes[i] = StaticCompiler.GetTypeForMapXml(context.ClassLoader, types[i]); } } MethodInfo mi = StaticCompiler.GetTypeForMapXml(context.ClassLoader, type).GetMethod(Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, null, argTypes, null); if(mi == null) { throw new InvalidOperationException("Missing method: " + type + "." + Name + Sig); } ilgen.Emit(opcode, mi); } } }