⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 methodrewriter.java

📁 配置文件
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
	 */
	private void inlineSubroutines() 
		throws AnalyzerException 
	{
		// Set up the first instruction region to be
		// processed as the entire method code...
		Region methodRegion = new Region(0, srcMethod.instructions.size());

		// Scan through the instructions in the method and
		// get organized
		createSubroutineMap();
		sortTryCatchBlocks(methodRegion);
		
		// Copy the non-code information
		updatedMethod = copyMethodMetadata(srcMethod);
		
		// Set up some mapping information
		lineNumberMap = createLineNumberMap();
		localVariableByStartLabelMap = createLocalVariableMap();

		// Copy the instructions while inlining subroutines
		copyRegion(updatedMethod, methodRegion);
		
		// The WTK reduces the visibility of the local variables
		if (shouldReduceVariableVisibility(updatedMethod)) {
			List instructions = updatedMethod.instructions;
			int instructionCount = instructions.size();
			AbstractInsnNode lastLabel = 
				(AbstractInsnNode) instructions.remove(instructionCount - 1);
			instructions.add(instructionCount - 2, lastLabel);
		}
		
		updatedMethod.visitMaxs(srcMethod.maxStack, srcMethod.maxLocals);
	}

	/**
	 * Add a new local variabled to the variables by end label map.
	 * 
	 * @param newLocalVariable
	 */
	private void addNewLocalVariableByEnd(LocalVariableNode newLocalVariable) {
		ArrayList endLocalVariables = 
			(ArrayList) localVariableByEndLabelMap.get(newLocalVariable.end);
		
		if (endLocalVariables == null) {
			endLocalVariables = new ArrayList();
			localVariableByEndLabelMap.put(newLocalVariable.end, endLocalVariables);
		}
		
		endLocalVariables.add(newLocalVariable);
	}

	/**
	 * Add a new stack map type.
	 * 
	 * @param localOrStack
	 * @param region
	 * @param label
	 * @param value
	 */
	private void addStackMapType(List localOrStack, Label label, Value value) {
		BasicValue basicValue = (BasicValue) value;
		
        if (this == BasicValue.UNINITIALIZED_VALUE) {
			localOrStack.add(newStackMapType(label, StackMapType.ITEM_Uninitialized));
        } else {
    		Type valueType = basicValue.getType();

			if (valueType == null) {
				localOrStack.add(newStackMapType(label, StackMapType.ITEM_Top));
			} else {
				switch (valueType.getSort()) {
					case Type.BOOLEAN:
					case Type.BYTE:
					case Type.CHAR:
					case Type.INT:
					case Type.SHORT:
						localOrStack.add(newStackMapType(label, StackMapType.ITEM_Integer));
						break;
					
					case Type.DOUBLE:
						localOrStack.add(newStackMapType(label, StackMapType.ITEM_Double));
						localOrStack.add(newStackMapType(label, StackMapType.ITEM_Top));
						break;
					
					case Type.FLOAT:
						localOrStack.add(newStackMapType(label, StackMapType.ITEM_Float));
						break;
					
					case Type.LONG:
						localOrStack.add(newStackMapType(label, StackMapType.ITEM_Long));
						localOrStack.add(newStackMapType(label, StackMapType.ITEM_Top));
						break;
					
					case Type.OBJECT:
					{
						StackMapType mapType = null;
						
						String typeName = valueType.getInternalName();
						if (typeName.equals("null")) {
							mapType = newStackMapType(label, StackMapType.ITEM_Null);
						} else {
							mapType = newStackMapType(label, StackMapType.ITEM_Object);
							mapType.setObject(typeName);
						}
						
						localOrStack.add(mapType);
						break;
					}
					
					case Type.ARRAY:
					{
						StackMapType mapType = newStackMapType(label, StackMapType.ITEM_Object);
						mapType.setObject(valueType.toString());
						localOrStack.add(mapType);
						break;
					}
				}
			}
		}
	}

	/**
	 * Copy all of the try/catch blocks in the method, realigning based on
	 * the rewritten code.
	 * 
	 * @param methodNode
	 * @param methodRegion
	 */
	private void copyTryCatchBlocks(MethodNode methodNode, Region region, List blocks) {
		Iterator tryCatchBlocks = blocks.iterator();
		while (tryCatchBlocks.hasNext()) {
			TryCatchBlockNode tryCatch = (TryCatchBlockNode) tryCatchBlocks.next();
			if (shouldCopy(tryCatch)) {
				methodNode.visitTryCatchBlock(
						region.getMappedLabel(tryCatch.start), 
						region.getMappedLabel(tryCatch.end), 
						region.getMappedLabel(tryCatch.handler), 
						tryCatch.type);
			}			
		}
	}

	/**
	 * Create a mapping from line number location (Label) to the instance
	 * of the line number nodes.
	 * 
	 * @return
	 */
	private Map createLineNumberMap() {
		Map map = new HashMap();

		Iterator lineNumbers = srcMethod.lineNumbers.iterator();
		while (lineNumbers.hasNext()) {
			LineNumberNode lineNumber = (LineNumberNode) lineNumbers.next();
			map.put(lineNumber.start, lineNumber);
		}
		
		return map;
	}

	/**
	 * Create a mapping from local variable location (Label) to the instance
	 * of the local variable nodes.
	 * 
	 * @return
	 */
	private Map createLocalVariableMap() {
		Map map = new HashMap();
		
		Iterator localVariables = srcMethod.localVariables.iterator();
		while (localVariables.hasNext()) {
			LocalVariableNode localVariable = (LocalVariableNode) localVariables.next();
			ArrayList startList = (ArrayList) map.get(localVariable.start);
			if (startList == null) {
				startList = new ArrayList();
				map.put(localVariable.start, startList);
			}
			
			startList.add(localVariable);
		}
		
		return map;
	}

	/**
	 * Copy the method node's metadata that is not changing.
	 * 
	 * @param method
	 * @return
	 */
	private MethodNode copyMethodMetadata(MethodNode method) {
		// Start a new method node
		String[] exceptions = 
			(String[]) method.exceptions.toArray(new String[method.exceptions.size()]);
		
		return new MethodNode(
			method.access,
			method.name,
			method.desc,
			method.signature,
			exceptions);
	}

	/**
	 * Copy the specified region of code potentially recursively.
	 * 
	 * @param method
	 * @param region
	 * @throws AnalyzerException
	 */
	private void copyRegion(MethodNode method, Region region) 
		throws AnalyzerException 
	{
		// Do any region-specific setup
		region.enter(method);
		
		// Walk the instructions.. inlining as we go
		for (int index = region.startIndex; index < region.endIndex; ++index) {
			AbstractInsnNode insnNode = getInstruction(srcMethod, index); 
			
			// Special case for labels, as they may indicate the start of
			// a subroutine that can be skipped.
			if (insnNode.getType() == AbstractInsnNode.LABEL) {
				Label label = ((LabelNode) insnNode).label;
				visitLabel(method, region, label);
				
				if (isSubroutineStart(label)) {
					// Skip over this subroutine implementation
					Subroutine subroutine = (Subroutine) subroutineMap.get(label);
					index = subroutine.endIndex;
				} 
			} else {
				if (!region.isSubroutineReturnStore(srcMethod, index)) {
					visitInstruction(method, region, insnNode);
				}
			} 
		}
		
		// Do any region-specific cleanup
		region.exit(method);
	}

	/**
	 * Create a new stack map frame.
	 * 
	 * @param region
	 * @param label
	 * @param frame
	 * @return
	 * @throws AnalyzerException
	 */
	private StackMapFrame newStackMapFrame(Label label, Frame frame) 
		throws AnalyzerException 
	{
		// Handle the locals
		ArrayList locals = new ArrayList();
		int localsCount = frame.getLocals();
		for (int i = 0; i < localsCount; i++) {
			addStackMapType(locals, label, frame.getLocal(i));
		}
		removeTrailingTops(locals);
		
		// Handle the stack
		ArrayList stack = new ArrayList();
		int stackCount = frame.getStackSize();
		for (int i = 0; i < stackCount; i++) {
			addStackMapType(stack, label, frame.getStack(i));
		}
		removeTrailingTops(stack);
		
		return new StackMapFrame(label, locals, stack);
	}
	
	/**
	 * Create a new StackMapType instance for the specified label.
	 * 
	 * @param label
	 * @param typeCode
	 * @return
	 */
	private StackMapType newStackMapType(Label label, int typeCode) {
		StackMapType type = StackMapType.getTypeInfo(typeCode);
		type.setLabel(label);
		return type;
	}

	/**
	 * Remove the trailing TOP types from the specified locals or stack.
	 * 
	 * @param locals
	 */
	private void removeTrailingTops(ArrayList localsOrStack) {
		while (removeTrailingTop(localsOrStack)) { }
	}

	/**
	 * Remove the trailing TOP value from the list.
	 * 
	 * @param localsOrStack
	 * @return
	 */
	private boolean removeTrailingTop(ArrayList localsOrStack) {
		boolean removed = false;
		
		if (localsOrStack.size() > 0) {
			int lastIndex = localsOrStack.size() - 1;
			
			StackMapType type = (StackMapType) localsOrStack.get(lastIndex);
			if (type.getType() == StackMapType.ITEM_Top) {
				localsOrStack.remove(lastIndex);
				removed = true;
			}
		}
		
		return removed;
	}

	/**
	 * Scan the instructions in the source method and find
	 * the subroutines and locations of any target labels.
	 * 
	 * @param method
	 * @throws AnalyzerException
	 */
	private void createSubroutineMap() 
		throws AnalyzerException 
    {
		subroutineMap = new HashMap();
		
		// Look through the JSR instructions and collect the
		// target labels.  Those target labels are the starting
		// points for the subroutines.
		Set subroutineStartLabels = new HashSet();
		Iterator jsrInstructionIndices = srcMethod.getJsrInstructionIndices().iterator();
		while (jsrInstructionIndices.hasNext()) {
			Integer instructionIndex = (Integer) jsrInstructionIndices.next();
			JumpInsnNode jumpNode = 
				(JumpInsnNode) getInstruction(srcMethod, instructionIndex.intValue());
			subroutineStartLabels.add(jumpNode.label);
		}

		// Now, start searching for the subroutine starts.  This
		// must be done to account for nested subroutine implementations
		if (subroutineStartLabels.size() > 0) {
			for (int i = 0; i < srcMethod.instructions.size(); i++) {
				AbstractInsnNode insnNode = getInstruction(srcMethod, i); 
				if (insnNode.getType() == AbstractInsnNode.LABEL) {
					LabelNode labelNode = (LabelNode) insnNode;
					if (subroutineStartLabels.contains(labelNode.label)) {
						// This is the start of a subroutine
						i = captureSubroutine(
								subroutineStartLabels, 
								subroutineMap, 
								i, 
								srcMethod, 
								(LabelNode) insnNode);
					}
				}
			}
		}
	}

	/**
	 * Capture the specified subroutine, potentially recursively
	 * capturing nested subroutines.  Captured subroutines are
	 * added to the map of subroutines.
	 * 
	 * @param subroutineStartLabels
	 * @param subroutineMap
	 * @param index
	 * @param method
	 * @param labelNode
	 * @return
	 */
	private int captureSubroutine(
		Set subroutineStartLabels,
		Map subroutineMap, 
		int index,
		MethodNode method,
		LabelNode labelNode) 
	{
		Subroutine subroutine = new Subroutine(labelNode.label);
		
		subroutine.startIndex = index + 1;
		for (subroutine.endIndex = subroutine.startIndex; true; subroutine.endIndex++) 
		{
			AbstractInsnNode insn = getInstruction(method, subroutine.endIndex);
			
			if (insn.getType() == AbstractInsnNode.LABEL) {
				Label label = ((LabelNode) insn).label;
				if (subroutineStartLabels.contains(label)) {
					subroutine.endIndex = captureSubroutine(
							subroutineStartLabels, 
							subroutineMap, 
							subroutine.endIndex, 
							srcMethod, 
							(LabelNode) insn);
				} else {
					subroutine.addLabel(label);
				}
			} else {
				if (insn.getOpcode() == Opcodes.RET) {
					// Figure out the variable that is being used
					// for the return instruction
					VarInsnNode varInsnNode = (VarInsnNode) insn;
					int variableNumber = varInsnNode.var;
					subroutine.setReturnVariable(variableNumber);
					
					break;
				} 
			}
		}

		// Add the newly found subroutine to the map
		Label label = labelNode.label;
		if (!subroutineMap.containsKey(label)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -