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