172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann/******************************************************************************* 234cd880f4e52a32b9f88ed4ea687b8f3f892395bEvgeny Mandrikov * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors 372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * All rights reserved. This program and the accompanying materials 472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * are made available under the terms of the Eclipse Public License v1.0 572793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * which accompanies this distribution, and is available at 672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * http://www.eclipse.org/legal/epl-v10.html 772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * 872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * Contributors: 928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov * Evgeny Mandrikov - initial API and implementation 1028a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov * 1172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann *******************************************************************************/ 1272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmannpackage org.jacoco.core.internal.instr; 1372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 1472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmannimport org.jacoco.core.runtime.IExecutionDataAccessorGenerator; 1572793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmannimport org.objectweb.asm.ClassVisitor; 1672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmannimport org.objectweb.asm.Label; 1772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmannimport org.objectweb.asm.MethodVisitor; 1872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmannimport org.objectweb.asm.Opcodes; 1972793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 2072793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann/** 2128a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov * This strategy for Java 8 interfaces adds a static method requesting the probe 2228a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov * array from the runtime, a static field to hold the probe array and adds code 2328a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov * for its initialization into interface initialization method. 2472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann */ 2528a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikovclass InterfaceFieldProbeArrayStrategy implements IProbeArrayStrategy { 2672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 2772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann /** 2872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * Frame stack with a single boolean array. 2972793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann */ 306e5a8197072aad904473a1850cb06ce9e7006cd8Marc R. Hoffmann private static final Object[] FRAME_STACK_ARRZ = new Object[] { InstrSupport.DATAFIELD_DESC }; 3172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 3272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann /** 3372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann * Empty frame locals. 3472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann */ 356e5a8197072aad904473a1850cb06ce9e7006cd8Marc R. Hoffmann private static final Object[] FRAME_LOCALS_EMPTY = new Object[0]; 3672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 3772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann private final String className; 3872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann private final long classId; 3928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov private final int probeCount; 4072793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann private final IExecutionDataAccessorGenerator accessorGenerator; 4172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 4228a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov private boolean seenClinit = false; 4328a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 4428a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov InterfaceFieldProbeArrayStrategy(final String className, final long classId, 4528a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov final int probeCount, 4672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann final IExecutionDataAccessorGenerator accessorGenerator) { 4772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann this.className = className; 4872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann this.classId = classId; 4928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov this.probeCount = probeCount; 5072793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann this.accessorGenerator = accessorGenerator; 5172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann } 5272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 5328a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov public int storeInstance(final MethodVisitor mv, final boolean clinit, 5428a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov final int variable) { 5528a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov if (clinit) { 5628a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov final int maxStack = accessorGenerator.generateDataAccessor(classId, 5728a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov className, probeCount, mv); 5828a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 5928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov // Stack[0]: [Z 6028a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 6128a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitInsn(Opcodes.DUP); 6228a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 6328a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov // Stack[1]: [Z 6428a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov // Stack[0]: [Z 6528a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 6628a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitFieldInsn(Opcodes.PUTSTATIC, className, 6728a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC); 6828a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 6928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov // Stack[0]: [Z 7028a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 7128a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitVarInsn(Opcodes.ASTORE, variable); 7228a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov 7328a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov seenClinit = true; 7428a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov return Math.max(maxStack, 2); 7528a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov } else { 7628a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, 7728a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov InstrSupport.INITMETHOD_NAME, InstrSupport.INITMETHOD_DESC, 7828a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov true); 7928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitVarInsn(Opcodes.ASTORE, variable); 8028a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov return 1; 8128a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov } 8272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann } 8372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 8472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann public void addMembers(final ClassVisitor cv, final int probeCount) { 8572793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann createDataField(cv); 8672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann createInitMethod(cv, probeCount); 8728a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov if (!seenClinit) { 8828a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov createClinitMethod(cv, probeCount); 8928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov } 9072793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann } 9172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 9272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann private void createDataField(final ClassVisitor cv) { 9328a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov cv.visitField(InstrSupport.DATAFIELD_INTF_ACC, 9428a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC, null, 9528a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov null); 9672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann } 9772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 9872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann private void createInitMethod(final ClassVisitor cv, final int probeCount) { 9972793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann final MethodVisitor mv = cv.visitMethod(InstrSupport.INITMETHOD_ACC, 10072793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann InstrSupport.INITMETHOD_NAME, InstrSupport.INITMETHOD_DESC, 10172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann null, null); 10272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitCode(); 10372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 10472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Load the value of the static data field: 10572793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitFieldInsn(Opcodes.GETSTATIC, className, 10672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC); 10772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitInsn(Opcodes.DUP); 10872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 10972793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Stack[1]: [Z 11072793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Stack[0]: [Z 11172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 11272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Skip initialization when we already have a data array: 11372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann final Label alreadyInitialized = new Label(); 11472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitJumpInsn(Opcodes.IFNONNULL, alreadyInitialized); 11572793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 11672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Stack[0]: [Z 11772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 11872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitInsn(Opcodes.POP); 11928a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov final int size = accessorGenerator.generateDataAccessor(classId, 12028a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov className, probeCount, mv); 12172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 12272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Stack[0]: [Z 12372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 12472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Return the class' probe array: 12528a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitFrame(Opcodes.F_NEW, 0, FRAME_LOCALS_EMPTY, 1, 12628a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov FRAME_STACK_ARRZ); 12772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitLabel(alreadyInitialized); 12872793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitInsn(Opcodes.ARETURN); 12972793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 13072793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitMaxs(Math.max(size, 2), 0); // Maximum local stack size is 2 13172793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitEnd(); 13272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann } 13372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 13428a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov private void createClinitMethod(final ClassVisitor cv, 13572793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann final int probeCount) { 13628a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov final MethodVisitor mv = cv.visitMethod(InstrSupport.CLINIT_ACC, 13728a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov InstrSupport.CLINIT_NAME, InstrSupport.CLINIT_DESC, null, null); 13828a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitCode(); 13972793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 14028a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov final int maxStack = accessorGenerator.generateDataAccessor(classId, 14128a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov className, probeCount, mv); 14272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 14372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann // Stack[0]: [Z 14472793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 14572793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann mv.visitFieldInsn(Opcodes.PUTSTATIC, className, 14672793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann InstrSupport.DATAFIELD_NAME, InstrSupport.DATAFIELD_DESC); 14772793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 14828a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitInsn(Opcodes.RETURN); 14972793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 15028a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitMaxs(maxStack, 0); 15128a112ca6c6f46cd385f00aa932ec0e334e045a7Evgeny Mandrikov mv.visitEnd(); 15272793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann } 15372793f84314a393b86c5dc344499888b7113d20bMarc R. Hoffmann 15470565308277973dfd8b61c7545c03bc4fb1fd725Evgeny Mandrikov} 155