internal static bool Emit(DynamicTypeWrapper.FinishContext context, TypeWrapper wrapper, CodeEmitter ilgen, ClassFile classFile, int i, ClassFile.Method.Instruction[] code, InstructionFlags[] flags) { if (i >= 3 && (flags[i - 0] & InstructionFlags.BranchTarget) == 0 && (flags[i - 1] & InstructionFlags.BranchTarget) == 0 && (flags[i - 2] & InstructionFlags.BranchTarget) == 0 && (flags[i - 3] & InstructionFlags.BranchTarget) == 0 && code[i - 1].NormalizedOpCode == NormalizedByteCode.__ldc && code[i - 2].NormalizedOpCode == NormalizedByteCode.__ldc && code[i - 3].NormalizedOpCode == NormalizedByteCode.__ldc) { // we now have a structural match, now we need to make sure that the argument values are what we expect TypeWrapper tclass = classFile.GetConstantPoolClassType(code[i - 3].Arg1); TypeWrapper vclass = classFile.GetConstantPoolClassType(code[i - 2].Arg1); string fieldName = classFile.GetConstantPoolConstantString(code[i - 1].Arg1); if (tclass == wrapper && !vclass.IsUnloadable && !vclass.IsPrimitive && !vclass.IsNonPrimitiveValueType) { FieldWrapper field = wrapper.GetFieldWrapper(fieldName, vclass.SigName); if (field != null && !field.IsStatic && field.IsVolatile && field.DeclaringType == wrapper && field.FieldTypeWrapper == vclass) { // everything matches up, now call the actual emitter DoEmit(context, wrapper, ilgen, field); return true; } } } return false; }
private JsrInliner(ClassFile.Method.Instruction[] codeCopy, InstructionFlags[] flags, ClassFile.Method m, JsrMethodAnalyzer ma) { this.codeCopy = codeCopy; codeLength = codeCopy.Length; this.flags = flags; this.m = m; this.ma = ma; }
internal static void InlineJsrs(ClassLoaderWrapper classLoader, MethodWrapper mw, ClassFile classFile, ClassFile.Method m) { JsrInliner inliner; do { ClassFile.Method.Instruction[] codeCopy = (ClassFile.Method.Instruction[])m.Instructions.Clone(); InstructionFlags[] flags = new InstructionFlags[codeCopy.Length]; JsrMethodAnalyzer ma = new JsrMethodAnalyzer(mw, classFile, m, classLoader, flags); inliner = new JsrInliner(codeCopy, flags, m, ma); } while (inliner.InlineJsrs()); }
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; } } } } } } }