FrameSnapshot.java revision 351b20ee84db15e054b01c3a5e7b4234cecad890
1/*******************************************************************************
2 * Copyright (c) 2009, 2014 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12
13package org.jacoco.core.internal.flow;
14
15import java.util.ArrayList;
16import java.util.List;
17
18import org.objectweb.asm.MethodVisitor;
19import org.objectweb.asm.Opcodes;
20import org.objectweb.asm.commons.AnalyzerAdapter;
21
22/**
23 * IFrame implementation which creates snapshots from an {@link AnalyzerAdapter}
24 */
25class FrameSnapshot implements IFrame {
26
27	private static final FrameSnapshot NOP = new FrameSnapshot(null, null);
28
29	private final Object[] locals;
30	private final Object[] stack;
31
32	private FrameSnapshot(final Object[] locals, final Object[] stack) {
33		this.locals = locals;
34		this.stack = stack;
35	}
36
37	/**
38	 * Create a IFrame instance based on the given analyzer.
39	 *
40	 * @param analyzer
41	 *            analyzer instance or <code>null</code>
42	 * @param popCount
43	 *            number of items to remove from the operand stack
44	 * @return IFrame instance. In case the analyzer is <code>null</code> or
45	 *         does not contain stackmap information a "NOP" IFrame is returned.
46	 */
47	static IFrame create(final AnalyzerAdapter analyzer, final int popCount) {
48		if (analyzer == null || analyzer.locals == null) {
49			return NOP;
50		}
51		final Object[] locals = reduce(analyzer.locals, 0);
52		final Object[] stack = reduce(analyzer.stack, popCount);
53		return new FrameSnapshot(locals, stack);
54	}
55
56	/**
57	 * Reduce double word types into a single slot as required
58	 * {@link MethodVisitor#visitFrame(int, int, Object[], int, Object[])}
59	 * method.
60	 */
61	private static Object[] reduce(final List<Object> source, final int popCount) {
62		final List<Object> copy = new ArrayList<Object>(source);
63		final int size = source.size() - popCount;
64		copy.subList(size, source.size()).clear();
65		for (int i = size; --i >= 0;) {
66			final Object type = source.get(i);
67			if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
68				copy.remove(i + 1);
69			}
70		}
71		return copy.toArray();
72	}
73
74	// === IFrame implementation ===
75
76	public void accept(final MethodVisitor mv) {
77		if (locals != null) {
78			mv.visitFrame(Opcodes.F_NEW, locals.length, locals, stack.length,
79					stack);
80		}
81	}
82
83}
84