Java tutorial
/* * JBoss, Home of Professional Open Source * Copyright 2009, Red Hat Middleware LLC, and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.arquillian.extension.jacoco.container; import org.jacoco.core.internal.instr.InstrSupport; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.RuntimeData; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * ArquillianRuntime * * @author <a href="mailto:aslak@redhat.com">Aslak Knutsen</a> * @version $Revision: $ */ public class ArquillianRuntime implements IRuntime { private static ArquillianRuntime runtime = null; public static synchronized ArquillianRuntime getInstance() { if (runtime == null) { runtime = new ArquillianRuntime(); } return runtime; } private RuntimeData runtimeData; /** * */ private ArquillianRuntime() { } /** * Retrieves the execution probe array for a given class. The passed * {@link Object} array instance is used for parameters and the return value * as follows. Call parameters: * * <ul> * <li>args[0]: class id ({@link Long}) * <li>args[1]: vm class name ({@link String}) * <li>args[2]: probe count ({@link Integer}) * </ul> * * Return value: * * <ul> * <li>args[0]: probe array (<code>boolean[]</code>) * </ul> * * @param args * parameter array of length 3 */ public void swapExecutionData(Object[] args) { final Long classid = (Long) args[0]; final String name = (String) args[1]; final int probecount = ((Integer) args[2]).intValue(); synchronized (runtimeData) { args[0] = runtimeData.getExecutionData(classid, name, probecount).getProbes(); } } RuntimeData getRuntimeData() { return runtimeData; } /* (non-Javadoc) * @see org.jacoco.core.runtime.IRuntime#startup() */ public void startup(RuntimeData rd) throws Exception { this.runtimeData = rd; } /* (non-Javadoc) * @see org.jacoco.core.runtime.IRuntime#shutdown() */ public void shutdown() { } /* (non-Javadoc) * @see org.jacoco.core.runtime.IRuntime#reset() */ public void reset() { runtimeData.reset(); } /* (non-Javadoc) * @see org.jacoco.core.runtime.IExecutionDataAccessorGenerator#generateDataAccessor(long, java.lang.String, int, org.objectweb.asm.MethodVisitor) */ public int generateDataAccessor(long classid, String classname, int probecount, MethodVisitor mv) { // 1. Create parameter array: generateArgumentArray(classid, classname, probecount, mv); // stack[0]: [Ljava/lang/Object; mv.visitInsn(Opcodes.DUP); // stack[1]: [Ljava/lang/Object; // stack[0]: [Ljava/lang/Object; // 2. Invoke ArquillianRuntime: mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/jboss/arquillian/extension/jacoco/container/ArquillianRuntime", "getInstance", "()Lorg/jboss/arquillian/extension/jacoco/container/ArquillianRuntime;"); // stack[2]: LArquillianRuntime; // stack[1]: [Ljava/lang/Object; // stack[0]: [Ljava/lang/Object; mv.visitInsn(Opcodes.SWAP); // stack[2]: [Ljava/lang/Object; // stack[1]: LArquillianRuntime; // stack[0]: [Ljava/lang/Object; // 3. Invoke ArquillianRuntime swapExecutionData, gets the boolean[] in Object[0]: mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/jboss/arquillian/extension/jacoco/container/ArquillianRuntime", "swapExecutionData", "([Ljava/lang/Object;)V"); // Stack[0]: [Ljava/lang/Object; mv.visitInsn(Opcodes.ICONST_0); mv.visitInsn(Opcodes.AALOAD); mv.visitTypeInsn(Opcodes.CHECKCAST, InstrSupport.DATAFIELD_DESC); // Stack[0]: [Z; return 5; } /** * Generates code that creates the argument array for the * <code>getExecutionData()</code> method. The array instance is left on the * operand stack. The generated code requires a stack size of 5. * * @param classid * class identifier * @param classname * VM class name * @param probecount * probe count for this class * @param mv * visitor to emit generated code */ public static void generateArgumentArray(final long classid, final String classname, final int probecount, final MethodVisitor mv) { mv.visitInsn(Opcodes.ICONST_3); mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); // Class Id: mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.ICONST_0); mv.visitLdcInsn(Long.valueOf(classid)); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); mv.visitInsn(Opcodes.AASTORE); // Class Name: mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.ICONST_1); mv.visitLdcInsn(classname); mv.visitInsn(Opcodes.AASTORE); // Probe Count: mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.ICONST_2); InstrSupport.push(mv, probecount); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); mv.visitInsn(Opcodes.AASTORE); } @Override public void disconnect(Class<?> type) throws Exception { throw new UnsupportedOperationException(); } }