private void AddParameterMetadata(MethodBuilder method, MethodWrapper mw) { ParameterBuilder[] pbs; if((mw.DeclaringType.IsPublic && (mw.IsPublic || mw.IsProtected)) || classLoader.EmitDebugInfo) { string[] parameterNames = new string[mw.GetParameters().Length]; GetParameterNamesFromXml(mw.Name, mw.Signature, parameterNames); GetParameterNamesFromSig(mw.Signature, parameterNames); pbs = GetParameterBuilders(method, parameterNames.Length, parameterNames); } else { pbs = GetParameterBuilders(method, mw.GetParameters().Length, null); } if((mw.Modifiers & Modifiers.VarArgs) != 0 && pbs.Length > 0) { AttributeHelper.SetParamArrayAttribute(pbs[pbs.Length - 1]); } AddXmlMapParameterAttributes(method, Name, mw.Name, mw.Signature, ref pbs); }
internal InvokeArgsProcessor(MethodWrapper mw, MethodBase method, object original_obj, object[] original_args, [email protected] callerID) { TypeWrapper[] argTypes = mw.GetParameters(); if(!mw.IsStatic && method.IsStatic && mw.Name != "<init>") { // we've been redirected to a static method, so we have to copy the 'obj' into the args object[] nargs = new object[original_args.Length + 1]; nargs[0] = original_obj; original_args.CopyTo(nargs, 1); this.obj = null; this.args = nargs; for(int i = 0; i < argTypes.Length; i++) { if(!argTypes[i].IsUnloadable && argTypes[i].IsGhost) { object v = Activator.CreateInstance(argTypes[i].TypeAsSignatureType); argTypes[i].GhostRefField.SetValue(v, args[i + 1]); args[i + 1] = v; } } } else { this.obj = original_obj; this.args = original_args; for(int i = 0; i < argTypes.Length; i++) { if(!argTypes[i].IsUnloadable && argTypes[i].IsGhost) { if(this.args == original_args) { this.args = (object[])args.Clone(); } object v = Activator.CreateInstance(argTypes[i].TypeAsSignatureType); argTypes[i].GhostRefField.SetValue(v, args[i]); this.args[i] = v; } } } if(mw.HasCallerID) { object[] nargs = new object[args.Length + 1]; Array.Copy(args, nargs, args.Length); nargs[args.Length] = callerID; args = nargs; } }
internal BaseFinalMethodWrapper(DotNetTypeWrapper tw, MethodWrapper m) : base(tw, m.Name, m.Signature, m.GetMethod(), m.ReturnType, m.GetParameters(), (m.Modifiers & ~Modifiers.Abstract) | Modifiers.Final, MemberFlags.None) { this.m = m; }
private static bool MatchSignatures(MethodWrapper mw1, MethodWrapper mw2) { return mw1.ReturnType == mw2.ReturnType && MatchTypes(mw1.GetParameters(), mw2.GetParameters()); }
private static bool MatchSignatures(MethodWrapper interfaceMethod, ClassFile.ConstantPoolItemMethodType samMethodType) { return interfaceMethod.ReturnType == samMethodType.GetRetType() && MatchTypes(interfaceMethod.GetParameters(), samMethodType.GetArgTypes()); }
private static void EmitDispatch(DynamicTypeWrapper.FinishContext context, TypeWrapper[] args, TypeBuilder tb, MethodWrapper interfaceMethod, TypeWrapper[] implParameters, ClassFile.ConstantPoolItemMethodHandle implMethod, ClassFile.ConstantPoolItemMethodType instantiatedMethodType, FieldBuilder[] capturedFields) { MethodBuilder mb = interfaceMethod.GetDefineMethodHelper().DefineMethod(context.TypeWrapper, tb, interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final); if (interfaceMethod.Name != interfaceMethod.RealName) { tb.DefineMethodOverride(mb, (MethodInfo)interfaceMethod.GetMethod()); } CodeEmitter ilgen = CodeEmitter.Create(mb); for (int i = 0; i < capturedFields.Length; i++) { ilgen.EmitLdarg(0); OpCode opc = OpCodes.Ldfld; if (i == 0 && args[0].IsGhost) { switch (implMethod.Kind) { case ClassFile.RefKind.invokeInterface: case ClassFile.RefKind.invokeVirtual: case ClassFile.RefKind.invokeSpecial: opc = OpCodes.Ldflda; break; } } ilgen.Emit(opc, capturedFields[i]); } for (int i = 0, count = interfaceMethod.GetParameters().Length, k = capturedFields.Length; i < count; i++) { ilgen.EmitLdarg(i + 1); TypeWrapper Ui = interfaceMethod.GetParameters()[i]; TypeWrapper Ti = instantiatedMethodType.GetArgTypes()[i]; TypeWrapper Aj = implParameters[i + k]; if (Ui == PrimitiveTypeWrapper.BYTE) { ilgen.Emit(OpCodes.Conv_I1); } if (Ti != Ui) { if (Ti.IsGhost) { Ti.EmitConvStackTypeToSignatureType(ilgen, Ui); } else if (Ui.IsGhost) { Ui.EmitConvSignatureTypeToStackType(ilgen); } else { Ti.EmitCheckcast(ilgen); } } if (Ti != Aj) { if (Ti.IsPrimitive && !Aj.IsPrimitive) { Boxer.EmitBox(ilgen, Ti); } else if (!Ti.IsPrimitive && Aj.IsPrimitive) { TypeWrapper primitive = GetPrimitiveFromWrapper(Ti); Boxer.EmitUnbox(ilgen, primitive, false); if (primitive == PrimitiveTypeWrapper.BYTE) { ilgen.Emit(OpCodes.Conv_I1); } } else if (Aj == PrimitiveTypeWrapper.LONG) { ilgen.Emit(OpCodes.Conv_I8); } else if (Aj == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Conv_R4); } else if (Aj == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Conv_R8); } } } switch (implMethod.Kind) { case ClassFile.RefKind.invokeVirtual: case ClassFile.RefKind.invokeInterface: ((MethodWrapper)implMethod.Member).EmitCallvirt(ilgen); break; case ClassFile.RefKind.newInvokeSpecial: ((MethodWrapper)implMethod.Member).EmitNewobj(ilgen); break; case ClassFile.RefKind.invokeStatic: case ClassFile.RefKind.invokeSpecial: ((MethodWrapper)implMethod.Member).EmitCall(ilgen); break; default: throw new InvalidOperationException(); } TypeWrapper Ru = interfaceMethod.ReturnType; TypeWrapper Ra = GetImplReturnType(implMethod); TypeWrapper Rt = instantiatedMethodType.GetRetType(); if (Ra == PrimitiveTypeWrapper.BYTE) { ilgen.Emit(OpCodes.Conv_I1); } if (Ra != Ru) { if (Ru == PrimitiveTypeWrapper.VOID) { ilgen.Emit(OpCodes.Pop); } else if (Ra.IsGhost) { Ra.EmitConvSignatureTypeToStackType(ilgen); } else if (Ru.IsGhost) { Ru.EmitConvStackTypeToSignatureType(ilgen, Ra); } } if (Ra != Rt) { if (Rt.IsPrimitive) { if (Rt == PrimitiveTypeWrapper.VOID) { // already popped } else if (!Ra.IsPrimitive) { TypeWrapper primitive = GetPrimitiveFromWrapper(Ra); if (primitive != null) { Boxer.EmitUnbox(ilgen, primitive, false); } else { // If Q is not a primitive wrapper, cast Q to the base Wrapper(S); for example Number for numeric types EmitConvertingUnbox(ilgen, Rt); } } else if (Rt == PrimitiveTypeWrapper.LONG) { ilgen.Emit(OpCodes.Conv_I8); } else if (Rt == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Conv_R4); } else if (Rt == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Conv_R8); } } else if (Ra.IsPrimitive) { Boxer.EmitBox(ilgen, GetPrimitiveFromWrapper(Rt)); } else { Rt.EmitCheckcast(ilgen); } } ilgen.EmitTailCallPrevention(); ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); }
internal JsrMethodAnalyzer(MethodWrapper mw, ClassFile classFile, ClassFile.Method method, ClassLoaderWrapper classLoader, InstructionFlags[] flags) { if (method.VerifyError != null) { throw new VerifyError(method.VerifyError); } this.classFile = classFile; state = new InstructionState[method.Instructions.Length]; callsites = new List<int>[method.Instructions.Length]; returnsites = new List<int>[method.Instructions.Length]; // because types have to have identity, the subroutine return address types are cached here Dictionary<int, SimpleType> returnAddressTypes = new Dictionary<int, SimpleType>(); try { // ensure that exception blocks and handlers start and end at instruction boundaries for (int i = 0; i < method.ExceptionTable.Length; i++) { int start = method.ExceptionTable[i].startIndex; int end = method.ExceptionTable[i].endIndex; int handler = method.ExceptionTable[i].handlerIndex; if (start >= end || start == -1 || end == -1 || handler <= 0) { throw new IndexOutOfRangeException(); } } } catch (IndexOutOfRangeException) { throw new ClassFormatError(string.Format("Illegal exception table (class: {0}, method: {1}, signature: {2}", classFile.Name, method.Name, method.Signature)); } // start by computing the initial state, the stack is empty and the locals contain the arguments state[0] = new InstructionState(method.MaxLocals, method.MaxStack); SimpleType thisType; int firstNonArgLocalIndex = 0; if (!method.IsStatic) { thisType = SimpleType.Object; state[0].SetLocalType(firstNonArgLocalIndex++, thisType, -1); } else { thisType = null; } TypeWrapper[] argTypeWrappers = mw.GetParameters(); for (int i = 0; i < argTypeWrappers.Length; i++) { TypeWrapper tw = argTypeWrappers[i]; SimpleType type; if (tw.IsWidePrimitive) { type = SimpleType.WidePrimitive; } else if (tw.IsPrimitive) { type = SimpleType.Primitive; } else { type = SimpleType.Object; } state[0].SetLocalType(firstNonArgLocalIndex++, type, -1); if (type.IsWidePrimitive) { firstNonArgLocalIndex++; } } SimpleType[] argumentsByLocalIndex = new SimpleType[firstNonArgLocalIndex]; for (int i = 0; i < argumentsByLocalIndex.Length; i++) { argumentsByLocalIndex[i] = state[0].GetLocalTypeEx(i); } InstructionState s = state[0].Copy(); bool done = false; ClassFile.Method.Instruction[] instructions = method.Instructions; while (!done) { done = true; for (int i = 0; i < instructions.Length; i++) { if (state[i] != null && state[i].changed) { try { //Console.WriteLine(method.Instructions[i].PC + ": " + method.Instructions[i].OpCode.ToString()); done = false; state[i].changed = false; // mark the exception handlers reachable from this instruction for (int j = 0; j < method.ExceptionTable.Length; j++) { if (method.ExceptionTable[j].startIndex <= i && i < method.ExceptionTable[j].endIndex) { MergeExceptionHandler(method.ExceptionTable[j].handlerIndex, state[i]); } } state[i].CopyTo(s); ClassFile.Method.Instruction instr = instructions[i]; switch (instr.NormalizedOpCode) { case NormalizedByteCode.__aload: { SimpleType type = s.GetLocalType(instr.NormalizedArg1); if (type == SimpleType.Invalid || type.IsPrimitive) { throw new VerifyError("Object reference expected"); } s.PushType(type); break; } case NormalizedByteCode.__astore: s.SetLocalType(instr.NormalizedArg1, s.PopObjectType(), i); break; case NormalizedByteCode.__aconst_null: s.PushObject(); break; case NormalizedByteCode.__aaload: s.PopPrimitive(); s.PopObjectType(); s.PushObject(); break; case NormalizedByteCode.__aastore: s.PopObjectType(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__baload: s.PopPrimitive(); s.PopObjectType(); s.PushPrimitive(); break; case NormalizedByteCode.__bastore: s.PopPrimitive(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__caload: s.PopPrimitive(); s.PopObjectType(); s.PushPrimitive(); break; case NormalizedByteCode.__castore: s.PopPrimitive(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__saload: s.PopPrimitive(); s.PopObjectType(); s.PushPrimitive(); break; case NormalizedByteCode.__sastore: s.PopPrimitive(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__iaload: s.PopPrimitive(); s.PopObjectType(); s.PushPrimitive(); break; case NormalizedByteCode.__iastore: s.PopPrimitive(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__laload: s.PopPrimitive(); s.PopObjectType(); s.PushWidePrimitive(); break; case NormalizedByteCode.__lastore: s.PopWidePrimitive(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__daload: s.PopPrimitive(); s.PopObjectType(); s.PushWidePrimitive(); break; case NormalizedByteCode.__dastore: s.PopWidePrimitive(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__faload: s.PopPrimitive(); s.PopObjectType(); s.PushPrimitive(); break; case NormalizedByteCode.__fastore: s.PopPrimitive(); s.PopPrimitive(); s.PopObjectType(); break; case NormalizedByteCode.__arraylength: s.PopObjectType(); s.PushPrimitive(); break; case NormalizedByteCode.__iconst: s.PushPrimitive(); break; case NormalizedByteCode.__if_icmpeq: case NormalizedByteCode.__if_icmpne: case NormalizedByteCode.__if_icmplt: case NormalizedByteCode.__if_icmpge: case NormalizedByteCode.__if_icmpgt: case NormalizedByteCode.__if_icmple: s.PopPrimitive(); s.PopPrimitive(); break; case NormalizedByteCode.__ifeq: case NormalizedByteCode.__ifge: case NormalizedByteCode.__ifgt: case NormalizedByteCode.__ifle: case NormalizedByteCode.__iflt: case NormalizedByteCode.__ifne: s.PopPrimitive(); break; case NormalizedByteCode.__ifnonnull: case NormalizedByteCode.__ifnull: s.PopObjectType(); break; case NormalizedByteCode.__if_acmpeq: case NormalizedByteCode.__if_acmpne: s.PopObjectType(); s.PopObjectType(); break; case NormalizedByteCode.__getstatic: s.PushType(GetFieldref(instr.Arg1).Signature); break; case NormalizedByteCode.__putstatic: s.PopType(GetFieldref(instr.Arg1).Signature); break; case NormalizedByteCode.__getfield: s.PopObjectType(); s.PushType(GetFieldref(instr.Arg1).Signature); break; case NormalizedByteCode.__putfield: s.PopType(GetFieldref(instr.Arg1).Signature); s.PopObjectType(); break; case NormalizedByteCode.__ldc: { switch (GetConstantPoolConstantType(instr.Arg1)) { case ClassFile.ConstantType.Double: s.PushWidePrimitive(); break; case ClassFile.ConstantType.Float: s.PushPrimitive(); break; case ClassFile.ConstantType.Integer: s.PushPrimitive(); break; case ClassFile.ConstantType.Long: s.PushWidePrimitive(); break; case ClassFile.ConstantType.String: case ClassFile.ConstantType.Class: s.PushObject(); break; default: // NOTE this is not a VerifyError, because it cannot happen (unless we have // a bug in ClassFile.GetConstantPoolConstantType) throw new InvalidOperationException(); } break; } case NormalizedByteCode.__invokevirtual: case NormalizedByteCode.__invokespecial: case NormalizedByteCode.__invokeinterface: case NormalizedByteCode.__invokestatic: { ClassFile.ConstantPoolItemMI cpi = GetMethodref(instr.Arg1); s.MultiPopAnyType(cpi.GetArgTypes().Length); if (instr.NormalizedOpCode != NormalizedByteCode.__invokestatic) { s.PopType(); } string sig = cpi.Signature; sig = sig.Substring(sig.IndexOf(')') + 1); if (sig != "V") { s.PushType(sig); } break; } case NormalizedByteCode.__goto: break; case NormalizedByteCode.__istore: s.PopPrimitive(); s.SetLocalPrimitive(instr.NormalizedArg1, i); break; case NormalizedByteCode.__iload: s.PushPrimitive(); break; case NormalizedByteCode.__ineg: s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__iadd: case NormalizedByteCode.__isub: case NormalizedByteCode.__imul: case NormalizedByteCode.__idiv: case NormalizedByteCode.__irem: case NormalizedByteCode.__iand: case NormalizedByteCode.__ior: case NormalizedByteCode.__ixor: case NormalizedByteCode.__ishl: case NormalizedByteCode.__ishr: case NormalizedByteCode.__iushr: s.PopPrimitive(); s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__lneg: s.PopWidePrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__ladd: case NormalizedByteCode.__lsub: case NormalizedByteCode.__lmul: case NormalizedByteCode.__ldiv: case NormalizedByteCode.__lrem: case NormalizedByteCode.__land: case NormalizedByteCode.__lor: case NormalizedByteCode.__lxor: s.PopWidePrimitive(); s.PopWidePrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__lshl: case NormalizedByteCode.__lshr: case NormalizedByteCode.__lushr: s.PopPrimitive(); s.PopWidePrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__fneg: s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__fadd: case NormalizedByteCode.__fsub: case NormalizedByteCode.__fmul: case NormalizedByteCode.__fdiv: case NormalizedByteCode.__frem: s.PopPrimitive(); s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__dneg: s.PopWidePrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__dadd: case NormalizedByteCode.__dsub: case NormalizedByteCode.__dmul: case NormalizedByteCode.__ddiv: case NormalizedByteCode.__drem: s.PopWidePrimitive(); s.PopWidePrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__new: s.PushObject(); break; case NormalizedByteCode.__multianewarray: { if (instr.Arg2 < 1) { throw new VerifyError("Illegal dimension argument"); } for (int j = 0; j < instr.Arg2; j++) { s.PopPrimitive(); } s.PushObject(); break; } case NormalizedByteCode.__anewarray: s.PopPrimitive(); s.PushObject(); break; case NormalizedByteCode.__newarray: s.PopPrimitive(); s.PushObject(); break; case NormalizedByteCode.__swap: { SimpleType t1 = s.PopType(); SimpleType t2 = s.PopType(); s.PushType(t1); s.PushType(t2); break; } case NormalizedByteCode.__dup: { SimpleType t = s.PopType(); s.PushType(t); s.PushType(t); break; } case NormalizedByteCode.__dup2: { SimpleType t = s.PopAnyType(); if (t.IsWidePrimitive) { s.PushType(t); s.PushType(t); } else { SimpleType t2 = s.PopType(); s.PushType(t2); s.PushType(t); s.PushType(t2); s.PushType(t); } break; } case NormalizedByteCode.__dup_x1: { SimpleType value1 = s.PopType(); SimpleType value2 = s.PopType(); s.PushType(value1); s.PushType(value2); s.PushType(value1); break; } case NormalizedByteCode.__dup2_x1: { SimpleType value1 = s.PopAnyType(); if (value1.IsWidePrimitive) { SimpleType value2 = s.PopType(); s.PushType(value1); s.PushType(value2); s.PushType(value1); } else { SimpleType value2 = s.PopType(); SimpleType value3 = s.PopType(); s.PushType(value2); s.PushType(value1); s.PushType(value3); s.PushType(value2); s.PushType(value1); } break; } case NormalizedByteCode.__dup_x2: { SimpleType value1 = s.PopType(); SimpleType value2 = s.PopAnyType(); if (value2.IsWidePrimitive) { s.PushType(value1); s.PushType(value2); s.PushType(value1); } else { SimpleType value3 = s.PopType(); s.PushType(value1); s.PushType(value3); s.PushType(value2); s.PushType(value1); } break; } case NormalizedByteCode.__dup2_x2: { SimpleType value1 = s.PopAnyType(); if (value1.IsWidePrimitive) { SimpleType value2 = s.PopAnyType(); if (value2.IsWidePrimitive) { // Form 4 s.PushType(value1); s.PushType(value2); s.PushType(value1); } else { // Form 2 SimpleType value3 = s.PopType(); s.PushType(value1); s.PushType(value3); s.PushType(value2); s.PushType(value1); } } else { SimpleType value2 = s.PopType(); SimpleType value3 = s.PopAnyType(); if (value3.IsWidePrimitive) { // Form 3 s.PushType(value2); s.PushType(value1); s.PushType(value3); s.PushType(value2); s.PushType(value1); } else { // Form 4 SimpleType value4 = s.PopType(); s.PushType(value2); s.PushType(value1); s.PushType(value4); s.PushType(value3); s.PushType(value2); s.PushType(value1); } } break; } case NormalizedByteCode.__pop: s.PopType(); break; case NormalizedByteCode.__pop2: { SimpleType type = s.PopAnyType(); if (!type.IsWidePrimitive) { s.PopType(); } break; } case NormalizedByteCode.__monitorenter: case NormalizedByteCode.__monitorexit: s.PopObjectType(); break; case NormalizedByteCode.__return: break; case NormalizedByteCode.__areturn: s.PopObjectType(); break; case NormalizedByteCode.__ireturn: s.PopPrimitive(); break; case NormalizedByteCode.__lreturn: s.PopWidePrimitive(); break; case NormalizedByteCode.__freturn: s.PopPrimitive(); break; case NormalizedByteCode.__dreturn: s.PopWidePrimitive(); break; case NormalizedByteCode.__fload: s.PushPrimitive(); break; case NormalizedByteCode.__fstore: s.PopPrimitive(); s.SetLocalPrimitive(instr.NormalizedArg1, i); break; case NormalizedByteCode.__dload: s.PushWidePrimitive(); break; case NormalizedByteCode.__dstore: s.PopWidePrimitive(); s.SetLocalWidePrimitive(instr.NormalizedArg1, i); break; case NormalizedByteCode.__lload: s.PushWidePrimitive(); break; case NormalizedByteCode.__lstore: s.PopWidePrimitive(); s.SetLocalWidePrimitive(instr.NormalizedArg1, i); break; case NormalizedByteCode.__lconst_0: case NormalizedByteCode.__lconst_1: s.PushWidePrimitive(); break; case NormalizedByteCode.__fconst_0: case NormalizedByteCode.__fconst_1: case NormalizedByteCode.__fconst_2: s.PushPrimitive(); break; case NormalizedByteCode.__dconst_0: case NormalizedByteCode.__dconst_1: s.PushWidePrimitive(); break; case NormalizedByteCode.__lcmp: s.PopWidePrimitive(); s.PopWidePrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__fcmpl: case NormalizedByteCode.__fcmpg: s.PopPrimitive(); s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__dcmpl: case NormalizedByteCode.__dcmpg: s.PopWidePrimitive(); s.PopWidePrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__checkcast: s.PopObjectType(); s.PushObject(); break; case NormalizedByteCode.__instanceof: s.PopObjectType(); s.PushPrimitive(); break; case NormalizedByteCode.__iinc: break; case NormalizedByteCode.__athrow: s.PopObjectType(); break; case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: s.PopPrimitive(); break; case NormalizedByteCode.__i2b: s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__i2c: s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__i2s: s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__i2l: s.PopPrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__i2f: s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__i2d: s.PopPrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__l2i: s.PopWidePrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__l2f: s.PopWidePrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__l2d: s.PopWidePrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__f2i: s.PopPrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__f2l: s.PopPrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__f2d: s.PopPrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__d2i: s.PopWidePrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__d2f: s.PopWidePrimitive(); s.PushPrimitive(); break; case NormalizedByteCode.__d2l: s.PopWidePrimitive(); s.PushWidePrimitive(); break; case NormalizedByteCode.__jsr: // TODO make sure we're not calling a subroutine we're already in break; case NormalizedByteCode.__ret: { // TODO if we're returning from a higher level subroutine, invalidate // all the intermediate return addresses int subroutineIndex = s.GetLocalRet(instr.Arg1); s.CheckSubroutineActive(subroutineIndex); break; } case NormalizedByteCode.__nop: if (i + 1 == instructions.Length) { throw new VerifyError("Falling off the end of the code"); } break; case NormalizedByteCode.__invokedynamic: // it is impossible to have a valid invokedynamic in a pre-7.0 class file throw new VerifyError("Illegal type in constant pool"); default: throw new NotImplementedException(instr.NormalizedOpCode.ToString()); } if (s.GetStackHeight() > method.MaxStack) { throw new VerifyError("Stack size too large"); } for (int j = 0; j < method.ExceptionTable.Length; j++) { if (method.ExceptionTable[j].endIndex == i + 1) { MergeExceptionHandler(method.ExceptionTable[j].handlerIndex, s); } } try { // another big switch to handle the opcode targets switch (instr.NormalizedOpCode) { case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: for (int j = 0; j < instr.SwitchEntryCount; j++) { state[instr.GetSwitchTargetIndex(j)] += s; } state[instr.DefaultTarget] += s; break; case NormalizedByteCode.__ifeq: case NormalizedByteCode.__ifne: case NormalizedByteCode.__iflt: case NormalizedByteCode.__ifge: case NormalizedByteCode.__ifgt: case NormalizedByteCode.__ifle: case NormalizedByteCode.__if_icmpeq: case NormalizedByteCode.__if_icmpne: case NormalizedByteCode.__if_icmplt: case NormalizedByteCode.__if_icmpge: case NormalizedByteCode.__if_icmpgt: case NormalizedByteCode.__if_icmple: case NormalizedByteCode.__if_acmpeq: case NormalizedByteCode.__if_acmpne: case NormalizedByteCode.__ifnull: case NormalizedByteCode.__ifnonnull: state[i + 1] += s; state[instr.TargetIndex] += s; break; case NormalizedByteCode.__goto: state[instr.TargetIndex] += s; break; case NormalizedByteCode.__jsr: { int index = instr.TargetIndex; s.SetSubroutineId(index); SimpleType retAddressType; if (!returnAddressTypes.TryGetValue(index, out retAddressType)) { retAddressType = SimpleType.MakeRet(index); returnAddressTypes[index] = retAddressType; } s.PushType(retAddressType); state[index] += s; List<int> returns = GetReturnSites(i); if (returns != null) { foreach (int returnIndex in returns) { state[i + 1] = InstructionState.MergeSubroutineReturn(state[i + 1], s, state[returnIndex], state[returnIndex].GetLocalsModified(index)); } } AddCallSite(index, i); break; } case NormalizedByteCode.__ret: { // HACK if the ret is processed before all of the jsr instructions to this subroutine // we wouldn't be able to properly merge, so that is why we track the number of callsites // for each subroutine instruction (see Instruction.AddCallSite()) int subroutineIndex = s.GetLocalRet(instr.Arg1); int[] cs = GetCallSites(subroutineIndex); bool[] locals_modified = s.GetLocalsModified(subroutineIndex); for (int j = 0; j < cs.Length; j++) { AddReturnSite(cs[j], i); state[cs[j] + 1] = InstructionState.MergeSubroutineReturn(state[cs[j] + 1], state[cs[j]], s, locals_modified); } break; } case NormalizedByteCode.__ireturn: case NormalizedByteCode.__lreturn: case NormalizedByteCode.__freturn: case NormalizedByteCode.__dreturn: case NormalizedByteCode.__areturn: case NormalizedByteCode.__return: case NormalizedByteCode.__athrow: break; default: state[i + 1] += s; break; } } catch (IndexOutOfRangeException) { // we're going to assume that this always means that we have an invalid branch target // NOTE because PcIndexMap returns -1 for illegal PCs (in the middle of an instruction) and // we always use that value as an index into the state array, any invalid PC will result // in an IndexOutOfRangeException throw new VerifyError("Illegal target of jump or branch"); } } catch (VerifyError x) { string opcode = instructions[i].NormalizedOpCode.ToString(); if (opcode.StartsWith("__")) { opcode = opcode.Substring(2); } throw new VerifyError(string.Format("{5} (class: {0}, method: {1}, signature: {2}, offset: {3}, instruction: {4})", classFile.Name, method.Name, method.Signature, instructions[i].PC, opcode, x.Message), x); } } } } // Now we do another pass to compute reachability done = false; flags[0] |= InstructionFlags.Reachable; while (!done) { done = true; bool didJsrOrRet = false; for (int i = 0; i < instructions.Length; i++) { if ((flags[i] & (InstructionFlags.Reachable | InstructionFlags.Processed)) == InstructionFlags.Reachable) { done = false; flags[i] |= InstructionFlags.Processed; // mark the exception handlers reachable from this instruction for (int j = 0; j < method.ExceptionTable.Length; j++) { if (method.ExceptionTable[j].startIndex <= i && i < method.ExceptionTable[j].endIndex) { flags[method.ExceptionTable[j].handlerIndex] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; } } // mark the successor instructions switch (instructions[i].NormalizedOpCode) { case NormalizedByteCode.__tableswitch: case NormalizedByteCode.__lookupswitch: { bool hasbackbranch = false; for (int j = 0; j < instructions[i].SwitchEntryCount; j++) { hasbackbranch |= instructions[i].GetSwitchTargetIndex(j) < i; flags[instructions[i].GetSwitchTargetIndex(j)] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; } hasbackbranch |= instructions[i].DefaultTarget < i; flags[instructions[i].DefaultTarget] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; break; } case NormalizedByteCode.__goto: flags[instructions[i].TargetIndex] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; break; case NormalizedByteCode.__ifeq: case NormalizedByteCode.__ifne: case NormalizedByteCode.__iflt: case NormalizedByteCode.__ifge: case NormalizedByteCode.__ifgt: case NormalizedByteCode.__ifle: case NormalizedByteCode.__if_icmpeq: case NormalizedByteCode.__if_icmpne: case NormalizedByteCode.__if_icmplt: case NormalizedByteCode.__if_icmpge: case NormalizedByteCode.__if_icmpgt: case NormalizedByteCode.__if_icmple: case NormalizedByteCode.__if_acmpeq: case NormalizedByteCode.__if_acmpne: case NormalizedByteCode.__ifnull: case NormalizedByteCode.__ifnonnull: flags[instructions[i].TargetIndex] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; flags[i + 1] |= InstructionFlags.Reachable; break; case NormalizedByteCode.__jsr: flags[instructions[i].TargetIndex] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; // Note that we don't mark the next instruction as reachable, // because that depends on the corresponding ret actually being // reachable. We handle this in the loop below. didJsrOrRet = true; break; case NormalizedByteCode.__ret: // Note that we can't handle ret here, because we might encounter the ret // before having seen all the corresponding jsr instructions, so we can't // update all the call sites. // We handle ret in the loop below. didJsrOrRet = true; break; case NormalizedByteCode.__ireturn: case NormalizedByteCode.__lreturn: case NormalizedByteCode.__freturn: case NormalizedByteCode.__dreturn: case NormalizedByteCode.__areturn: case NormalizedByteCode.__return: case NormalizedByteCode.__athrow: break; default: flags[i + 1] |= InstructionFlags.Reachable; break; } } } if (didJsrOrRet) { for (int i = 0; i < instructions.Length; i++) { if (instructions[i].NormalizedOpCode == NormalizedByteCode.__ret && (flags[i] & InstructionFlags.Reachable) != 0) { int subroutineIndex = state[i].GetLocalRet(instructions[i].Arg1); int[] cs = GetCallSites(subroutineIndex); for (int j = 0; j < cs.Length; j++) { if ((flags[cs[j]] & InstructionFlags.Reachable) != 0) { flags[cs[j] + 1] |= InstructionFlags.Reachable | InstructionFlags.BranchTarget; } } } } } } }