@Override public Size apply( MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { StackManipulation thisReference = MethodVariableAccess.REFERENCE.loadOffset(0); FieldList<?> fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; for (FieldDescription fieldDescription : fieldList) { fieldLoading[index] = new StackManipulation.Compound( thisReference, MethodVariableAccess.forType(fieldDescription.getType().asErasure()) .loadOffset(instrumentedMethod.getParameters().get(index).getOffset()), FieldAccess.forField(fieldDescription).putter()); index++; } StackManipulation.Size stackSize = new StackManipulation.Compound( thisReference, MethodInvocation.invoke(ConstructorCall.INSTANCE.objectTypeDefaultConstructor), new StackManipulation.Compound(fieldLoading), MethodReturn.VOID) .apply(methodVisitor, implementationContext); return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); }
@Override public Size apply( MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { StackManipulation thisReference = MethodVariableAccess.forType(instrumentedType).loadOffset(0); FieldList<?> fieldList = instrumentedType.getDeclaredFields(); StackManipulation[] fieldLoading = new StackManipulation[fieldList.size()]; int index = 0; for (FieldDescription fieldDescription : fieldList) { fieldLoading[index++] = new StackManipulation.Compound( thisReference, FieldAccess.forField(fieldDescription).getter()); } StackManipulation.Size stackSize = new StackManipulation.Compound( new StackManipulation.Compound(fieldLoading), MethodInvocation.invoke(accessorMethod), assigner.assign( accessorMethod.getReturnType().asErasure(), instrumentedMethod.getReturnType().asErasure(), Assigner.Typing.DYNAMIC), MethodReturn.returning(instrumentedMethod.getReturnType().asErasure())) .apply(methodVisitor, implementationContext); return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); }
@Test public void testBoxing() throws Exception { StackManipulation boxingStackManipulation = PrimitiveBoxingDelegate.forPrimitive(primitiveTypeDescription) .assignBoxedTo(targetType, chainedAssigner, Assigner.Typing.STATIC); assertThat(boxingStackManipulation.isValid(), is(true)); StackManipulation.Size size = boxingStackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(sizeChange)); assertThat(size.getMaximalSize(), is(0)); verify(primitiveTypeDescription).represents(primitiveType); verify(primitiveTypeDescription, atLeast(1)).represents(any(Class.class)); verifyNoMoreInteractions(primitiveTypeDescription); verify(chainedAssigner) .assign(referenceTypeDescription.asGenericType(), targetType, Assigner.Typing.STATIC); verifyNoMoreInteractions(chainedAssigner); verify(methodVisitor) .visitMethodInsn( Opcodes.INVOKESTATIC, referenceTypeDescription.getInternalName(), VALUE_OF, boxingMethodDescriptor, false); verifyNoMoreInteractions(methodVisitor); verify(stackManipulation, atLeast(1)).isValid(); verify(stackManipulation).apply(methodVisitor, implementationContext); verifyNoMoreInteractions(stackManipulation); }
@Test public void testLegalSlackBinding() throws Exception { when(target.getIndex()).thenReturn(1); when(annotation.value()).thenReturn(AllArguments.Assignment.SLACK); when(stackManipulation.isValid()).thenReturn(false); when(source.getParameters()) .thenReturn(new ParameterList.Explicit.ForTypes(source, firstSourceType, secondSourceType)); when(source.isStatic()).thenReturn(false); when(targetType.isArray()).thenReturn(true); when(targetType.getComponentType()).thenReturn(componentType); when(componentType.getStackSize()).thenReturn(StackSize.SINGLE); when(target.getType()).thenReturn(targetType); when(target.getDeclaredAnnotations()).thenReturn(new AnnotationList.Empty()); when(rawComponentType.getInternalName()).thenReturn(FOO); MethodDelegationBinder.ParameterBinding<?> parameterBinding = AllArguments.Binder.INSTANCE.bind( annotationDescription, source, target, implementationTarget, assigner); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = parameterBinding.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(1)); assertThat(size.getMaximalSize(), is(1)); verify(methodVisitor).visitInsn(Opcodes.ICONST_0); verify(methodVisitor).visitTypeInsn(Opcodes.ANEWARRAY, FOO); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(parameterBinding.isValid(), is(true)); verify(source, atLeast(1)).getParameters(); verify(source, atLeast(1)).isStatic(); verify(target, atLeast(1)).getType(); verify(target, atLeast(1)).getDeclaredAnnotations(); verify(assigner).assign(firstSourceType, componentType, Assigner.Typing.STATIC); verify(assigner).assign(secondSourceType, componentType, Assigner.Typing.STATIC); verifyNoMoreInteractions(assigner); }
@Test public void testAssignmentEqual() throws Exception { StackManipulation stackManipulation = Assigner.EqualTypesOnly.INSTANCE.assign(first, first, dynamicallyTyped); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); }
@Test public void testPrimitiveAssignabilityWhenEqual() throws Exception { TypeDescription primitiveType = new TypeDescription.ForLoadedType(int.class); // Note: cannot mock equals StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign(primitiveType, primitiveType, true); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); }
@Test public void testSourceToTargetAssignable() throws Exception { defineAssignability(true, false); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign( sourceTypeDescription, targetTypeDescription, false); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); }
@Test public void testTargetToSourceAssignableRuntimeType() throws Exception { defineAssignability(false, false); when(targetTypeDescription.getInternalName()).thenReturn(FOO); StackManipulation stackManipulation = ReferenceTypeAwareAssigner.INSTANCE.assign( sourceTypeDescription, targetTypeDescription, true); assertThat(stackManipulation.isValid(), is(true)); StackManipulation.Size size = stackManipulation.apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verify(methodVisitor).visitTypeInsn(Opcodes.CHECKCAST, FOO); verifyNoMoreInteractions(methodVisitor); }
@Test public void testSuperConstructorIsInvokable() throws Exception { when(superMethod.isConstructor()).thenReturn(true); Implementation.SpecialMethodInvocation specialMethodInvocation = implementationTarget.invokeSuper(superMethod, methodLookup); assertThat(specialMethodInvocation.isValid(), is(true)); assertThat(specialMethodInvocation.getMethodDescription(), is(superMethodConstructor)); assertThat(specialMethodInvocation.getTypeDescription(), is(superType)); MethodVisitor methodVisitor = mock(MethodVisitor.class); Implementation.Context implementationContext = mock(Implementation.Context.class); StackManipulation.Size size = specialMethodInvocation.apply(methodVisitor, implementationContext); verify(methodVisitor).visitMethodInsn(Opcodes.INVOKESPECIAL, BAR, QUXBAZ, BAZBAR, false); verifyNoMoreInteractions(methodVisitor); verifyZeroInteractions(implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); }
public Size apply( MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) { checkMethodSignature(instrumentedMethod); try { StackManipulation stack = buildStack(); StackManipulation.Size finalStackSize = stack.apply(methodVisitor, implementationContext); return new Size( finalStackSize.getMaximalSize(), instrumentedMethod.getStackSize() + 2); // 2 stack slots for a single local variable } catch (NoSuchMethodException | NoSuchFieldException e) { throw new RuntimeException(e); } }
/** * Blueprint method that for applying the actual implementation. * * @param methodVisitor The method visitor to which the implementation is applied to. * @param implementationContext The implementation context for the given implementation. * @param instrumentedMethod The instrumented method that is target of the implementation. * @param fixedValueType A description of the type of the fixed value that is loaded by the {@code * valueLoadingInstruction}. * @param valueLoadingInstruction A stack manipulation that represents the loading of the fixed * value onto the operand stack. * @return A representation of the stack and variable array sized that are required for this * implementation. */ protected ByteCodeAppender.Size apply( MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod, TypeDescription.Generic fixedValueType, StackManipulation valueLoadingInstruction) { StackManipulation assignment = assigner.assign(fixedValueType, instrumentedMethod.getReturnType(), typing); if (!assignment.isValid()) { throw new IllegalArgumentException( "Cannot return value of type " + fixedValueType + " for " + instrumentedMethod); } StackManipulation.Size stackSize = new StackManipulation.Compound( valueLoadingInstruction, assignment, MethodReturn.returning(instrumentedMethod.getReturnType().asErasure())) .apply(methodVisitor, implementationContext); return new ByteCodeAppender.Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); }
@Test public void testPreservation() throws Exception { MethodRebaseResolver.Resolution resolution = new MethodRebaseResolver.Resolution.ForRebasedMethod( methodDescription, methodNameTransformer); assertThat(resolution.isRebased(), is(true)); assertThat(resolution.getResolvedMethod().getDeclaringType(), is(typeDescription)); assertThat(resolution.getResolvedMethod().getInternalName(), is(QUX)); assertThat( resolution.getResolvedMethod().getModifiers(), is(MethodRebaseResolver.REBASED_METHOD_MODIFIER)); assertThat(resolution.getResolvedMethod().getReturnType(), is(returnType)); assertThat( resolution.getResolvedMethod().getParameters(), is( ParameterList.Explicit.latent( resolution.getResolvedMethod(), Collections.singletonList(parameterType)))); StackManipulation.Size size = resolution.getAdditionalArguments().apply(methodVisitor, implementationContext); assertThat(size.getSizeImpact(), is(0)); assertThat(size.getMaximalSize(), is(0)); verifyZeroInteractions(methodVisitor); verifyZeroInteractions(implementationContext); }