A super block is defined as a contiguous chunk of code with a single entry point and multiple exit points (therefore ending in an unconditional jump or the end of the method).
A super block is defined as a contiguous chunk of code with a single entry point and multiple exit points (therefore ending in an unconditional jump or the end of the method). This is used to emulate OpenJDK's compiler, which outputs stack map frames at the start of every super block except the method start.
Ejemplo n.º 1
0
			private void AddToWorkList(SuperBlock sb)
			{
				if (!sb.IsInQueue())
				{
					sb.SetInQueue(true);
					sb.SetInitialized(true);
					if (this.workListTop == this.workList.Length)
					{
						SuperBlock[] tmp = new SuperBlock[this.workListTop * 2];
						System.Array.Copy(this.workList, 0, tmp, 0, this.workListTop);
						this.workList = tmp;
					}
					this.workList[this.workListTop++] = sb;
				}
			}
Ejemplo n.º 2
0
			/// <summary>
			/// Perform a merge of type state and add the super block to the work
			/// list if the merge changed anything.
			/// </summary>
			/// <remarks>
			/// Perform a merge of type state and add the super block to the work
			/// list if the merge changed anything.
			/// </remarks>
			private void FlowInto(SuperBlock sb)
			{
				if (sb.Merge(this.locals, this.localsTop, this.stack, this.stackTop, this._enclosing.itsConstantPool))
				{
					this.AddToWorkList(sb);
				}
			}
Ejemplo n.º 3
0
			/// <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);
				}
			}
Ejemplo n.º 4
0
			/// <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]);
					}
				}
			}
Ejemplo n.º 5
0
			/// <summary>Calculate partial dependencies for super blocks.</summary>
			/// <remarks>
			/// Calculate partial dependencies for super blocks.
			/// This is used as a workaround for dead code that is generated. Only
			/// one dependency per super block is given.
			/// </remarks>
			private SuperBlock[] GetSuperBlockDependencies()
			{
				SuperBlock[] deps = new SuperBlock[this.superBlocks.Length];
				for (int i = 0; i < this._enclosing.itsExceptionTableTop; i++)
				{
					ExceptionTableEntry ete = this._enclosing.itsExceptionTable[i];
					short startPC = (short)this._enclosing.GetLabelPC(ete.itsStartLabel);
					short handlerPC = (short)this._enclosing.GetLabelPC(ete.itsHandlerLabel);
					SuperBlock handlerSB = this.GetSuperBlockFromOffset(handlerPC);
					SuperBlock dep = this.GetSuperBlockFromOffset(startPC);
					deps[handlerSB.GetIndex()] = dep;
				}
				int[] targetPCs = this._enclosing.itsJumpFroms.GetKeys();
				for (int i_1 = 0; i_1 < targetPCs.Length; i_1++)
				{
					int targetPC = targetPCs[i_1];
					int branchPC = this._enclosing.itsJumpFroms.GetInt(targetPC, -1);
					SuperBlock branchSB = this.GetSuperBlockFromOffset(branchPC);
					SuperBlock targetSB = this.GetSuperBlockFromOffset(targetPC);
					deps[targetSB.GetIndex()] = branchSB;
				}
				return deps;
			}