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