/// <summary>Simulate the local variable and op stack for a super block.</summary> /// <remarks>Simulate the local variable and op stack for a super block.</remarks> private void ExecuteBlock(SuperBlock work) { int bc = 0; int next = 0; for (int bci = work.GetStart(); bci < work.GetEnd(); bci += next) { bc = this._enclosing.itsCodeBuffer[bci] & unchecked((int)(0xFF)); next = this.Execute(bci); // If we have a branch to some super block, we need to merge // the current state of the local table and op stack with what's // currently stored as the initial state of the super block. If // something actually changed, we need to add it to the work // list. if (this.IsBranch(bc)) { SuperBlock targetSB = this.GetBranchTarget(bci); this.FlowInto(targetSB); } else { if (bc == ByteCode.TABLESWITCH) { int switchStart = bci + 1 + (3 & ~bci); // 3 - bci % 4 int defaultOffset = this.GetOperand(switchStart, 4); SuperBlock targetSB = this.GetSuperBlockFromOffset(bci + defaultOffset); this.FlowInto(targetSB); int low = this.GetOperand(switchStart + 4, 4); int high = this.GetOperand(switchStart + 8, 4); int numCases = high - low + 1; int caseBase = switchStart + 12; for (int i = 0; i < numCases; i++) { int label = bci + this.GetOperand(caseBase + 4 * i, 4); targetSB = this.GetSuperBlockFromOffset(label); this.FlowInto(targetSB); } } } for (int i_1 = 0; i_1 < this._enclosing.itsExceptionTableTop; i_1++) { ExceptionTableEntry ete = this._enclosing.itsExceptionTable[i_1]; short startPC = (short)this._enclosing.GetLabelPC(ete.itsStartLabel); short endPC = (short)this._enclosing.GetLabelPC(ete.itsEndLabel); if (bci < startPC || bci >= endPC) { continue; } short handlerPC = (short)this._enclosing.GetLabelPC(ete.itsHandlerLabel); SuperBlock sb = this.GetSuperBlockFromOffset(handlerPC); int exceptionType; if (ete.itsCatchType == 0) { exceptionType = TypeInfo.OBJECT(this._enclosing.itsConstantPool.AddClass("java/lang/Throwable")); } else { exceptionType = TypeInfo.OBJECT(ete.itsCatchType); } sb.Merge(this.locals, this.localsTop, new int[] { exceptionType }, 1, this._enclosing.itsConstantPool); this.AddToWorkList(sb); } } // Check the last instruction to see if it is a true end of a // super block (ie., if the instruction is a return). If it // isn't, we need to continue processing the next chunk. if (!this.IsSuperBlockEnd(bc)) { int nextIndex = work.GetIndex() + 1; if (nextIndex < this.superBlocks.Length) { this.FlowInto(this.superBlocks[nextIndex]); } } }
/// <summary>Replace the contents of a super block with no-ops.</summary> /// <remarks> /// Replace the contents of a super block with no-ops. /// The above description is not strictly true; the last instruction is /// an athrow instruction. This technique is borrowed from ASM's /// developer guide: http://asm.ow2.org/doc/developer-guide.html#deadcode /// The proposed algorithm fills a block with nop, ending it with an /// athrow. The stack map generated would be empty locals with an /// exception on the stack. In theory, it shouldn't matter what the /// locals are, as long as the stack has an exception for the athrow bit. /// However, it turns out that if the code being modified falls into an /// exception handler, it causes problems. Therefore, if it does, then /// we steal the locals from the exception block. /// If the block itself is an exception handler, we remove it from the /// exception table to simplify block dependencies. /// </remarks> private void KillSuperBlock(SuperBlock sb) { int[] locals = new int[0]; int[] stack = new int[] { TypeInfo.OBJECT("java/lang/Throwable", this._enclosing.itsConstantPool) }; // If the super block is handled by any exception handler, use its // locals as the killed block's locals. Ignore uninitialized // handlers, because they will also be killed and removed from the // exception table. for (int i = 0; i < this._enclosing.itsExceptionTableTop; i++) { ExceptionTableEntry ete = this._enclosing.itsExceptionTable[i]; int eteStart = this._enclosing.GetLabelPC(ete.itsStartLabel); int eteEnd = this._enclosing.GetLabelPC(ete.itsEndLabel); int handlerPC = this._enclosing.GetLabelPC(ete.itsHandlerLabel); SuperBlock handlerSB = this.GetSuperBlockFromOffset(handlerPC); if ((sb.GetStart() > eteStart && sb.GetStart() < eteEnd) || (eteStart > sb.GetStart() && eteStart < sb.GetEnd()) && handlerSB.IsInitialized()) { locals = handlerSB.GetLocals(); break; } } // Remove any exception table entry whose handler is the killed // block. This removes block dependencies to make stack maps for // dead blocks easier to create. for (int i_1 = 0; i_1 < this._enclosing.itsExceptionTableTop; i_1++) { ExceptionTableEntry ete = this._enclosing.itsExceptionTable[i_1]; int eteStart = this._enclosing.GetLabelPC(ete.itsStartLabel); if (eteStart == sb.GetStart()) { for (int j = i_1 + 1; j < this._enclosing.itsExceptionTableTop; j++) { this._enclosing.itsExceptionTable[j - 1] = this._enclosing.itsExceptionTable[j]; } this._enclosing.itsExceptionTableTop--; i_1--; } } sb.Merge(locals, locals.Length, stack, stack.Length, this._enclosing.itsConstantPool); int end = sb.GetEnd() - 1; this._enclosing.itsCodeBuffer[end] = unchecked((byte)ByteCode.ATHROW); for (int bci = sb.GetStart(); bci < end; bci++) { this._enclosing.itsCodeBuffer[bci] = unchecked((byte)ByteCode.NOP); } }