Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixes #727 Use ByteBuddy to instrument classes instead Javassist: imp…
…lement suppress constructor

Fix code style issues
  • Loading branch information
Arthur Zagretdinov committed Apr 22, 2018
1 parent cc619f8 commit d6ccb0f
Show file tree
Hide file tree
Showing 49 changed files with 2,192 additions and 418 deletions.
2 changes: 1 addition & 1 deletion config/checkstyle/checkstyle.xml
Expand Up @@ -102,7 +102,7 @@
<property name="max" value="8"/>
</module>
<module name="AbbreviationAsWordInName">
<property name="allowedAbbreviationLength" value="5"/>
<property name="allowedAbbreviationLength" value="8"/>
</module>
<module name="PackageDeclaration">
<property name="matchDirectoryStructure" value="false"/>
Expand Down
1 change: 1 addition & 0 deletions gradle/java-module.gradle
@@ -1,4 +1,5 @@
repositories {
mavenLocal()
mavenCentral()
jcenter()
}
Expand Down
1 change: 1 addition & 0 deletions gradle/release/fullJars.gradle
Expand Up @@ -12,6 +12,7 @@ configure(fullJars){ project ->
}

repositories {
mavenLocal()
mavenCentral()
jcenter()
}
Expand Down
Expand Up @@ -113,6 +113,10 @@ public static Object constructorCall(Class<?> type, Object[] args, Class<?>[] si
}
return PROCEED;
}

public static boolean suppressConstructorCall(Class<?> type, Object[] args, Class<?>[] sig) throws Throwable {
return constructorCall(type, args, sig) != PROCEED;
}

/**
* Tells PowerMock whether or not to mock
Expand Down
@@ -0,0 +1,78 @@
/*
*
* Copyright 2017 the original author or authors.
*
* 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.powermock.core.bytebuddy;

import net.bytebuddy.implementation.Implementation.Context;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.jar.asm.Label;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;

public class ConditionalStateStackManipulation implements StackManipulation {


private final StackManipulation condition;
private final StackManipulation action;
private final StackManipulation otherwise;
private final Frame frame;

public ConditionalStateStackManipulation(final StackManipulation condition,
final StackManipulation action,
final StackManipulation otherwise,
final Frame frame) {

this.condition = condition;
this.action = action;
this.otherwise = otherwise;
this.frame = frame;
}

@Override
public boolean isValid() {
return true;
}

@Override
public Size apply(final MethodVisitor mv, final Context implementationContext) {

Size size = new Size(0, 0);

Label proceed = new Label();
Label exit = new Label();

size = size.aggregate(condition.apply(mv, implementationContext));

mv.visitJumpInsn(Opcodes.IFEQ, proceed);

size = size.aggregate(action.apply(mv, implementationContext));

mv.visitJumpInsn(Opcodes.GOTO, exit);

mv.visitLabel(proceed);
mv.visitFrame(Opcodes.F_FULL, frame.localSize(), frame.locals(), 0, null);

size = size.aggregate(otherwise.apply(mv, implementationContext));

mv.visitLabel(exit);

mv.visitFrame(Opcodes.F_FULL, 0, null, 0, null);

return size;
}
}
143 changes: 143 additions & 0 deletions powermock-core/src/main/java/org/powermock/core/bytebuddy/Frame.java
@@ -0,0 +1,143 @@
/*
*
* Copyright 2017 the original author or authors.
*
* 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.powermock.core.bytebuddy;


import net.bytebuddy.description.method.ParameterDescription;
import net.bytebuddy.description.method.ParameterDescription.InDefinedShape;
import net.bytebuddy.description.method.ParameterList;
import net.bytebuddy.description.type.TypeDescription.Generic;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.utility.CompoundList;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;

public class Frame {

public static Frame beforeConstructorCall(final Iterable<? extends ParameterDescription> constructorParameters) {
List<LocalVariable> locals = new ArrayList<LocalVariable>();

locals.add(LocalVariable.UNINITIALIZED_THIS);

int maxLocals = 1;

for (ParameterDescription sourceParameter : constructorParameters) {
Generic type = sourceParameter.getType();
locals.add(LocalVariable.from(type));
maxLocals += type.getStackSize().getSize();
}

return new Frame(locals);
}

private Deque<Object> stack;
private List<LocalVariable> locals;

public Frame(final List<LocalVariable> locals) {
this.locals = Collections.unmodifiableList(locals);
this.stack = new LinkedList<Object>();
}

public Frame addTopToLocals(final int count) {
List<LocalVariable> locals = new ArrayList<LocalVariable>();
for (int i = 0; i < count; i++) {
locals.add(LocalVariable.TOP);
}

return new Frame(
CompoundList.of(this.locals, locals)
);
}

public Frame addLocalVariable(final LocalVariable localVariable) {
return new Frame(
CompoundList.of(this.locals, localVariable)
);
}

public Frame addLocalVariables(final ParameterList<InDefinedShape> types) {

List<LocalVariable> frameLocals = new ArrayList<LocalVariable>();

for (ParameterDescription parameter : types) {
Generic type = parameter.getType();
frameLocals.add(LocalVariable.from(type));
}

return new Frame(CompoundList.of(this.locals, frameLocals));
}

public Object[] locals() {
Object[] frameLocals = new Object[this.locals.size()];
for (int i = 0; i < this.locals.size(); i++) {
frameLocals[i] = this.locals.get(i).getType();
}
return frameLocals;
}

public int localSize() {
return locals.size();
}

public int maxLocalVariableIndex() {
int localStackSize = 0;
for (LocalVariable localVariable : locals) {
localStackSize += localVariable.getStackSize().getSize();
}
return localStackSize;
}

public static class LocalVariable {
public static LocalVariable from(final Generic type) {
if (type.represents(double.class)) {
return DOUBLE;
} else {
return new LocalVariable(
type.getTypeName().replace('.', '/'),
type.getStackSize()
);
}
}

public static final LocalVariable UNINITIALIZED_THIS = new LocalVariable(Opcodes.UNINITIALIZED_THIS, StackSize.SINGLE);
public static final LocalVariable TOP = new LocalVariable(Opcodes.TOP, StackSize.SINGLE);
public static final LocalVariable DOUBLE = new LocalVariable(Opcodes.DOUBLE, StackSize.DOUBLE);

private final Object type;
private final StackSize stackSize;

private LocalVariable(final Object type, StackSize size) {
this.type = type;
this.stackSize = size;
}

public Object getType() {
return type;
}

public StackSize getStackSize() {
return stackSize;
}
}
}
@@ -0,0 +1,76 @@
/*
*
* Copyright 2017 the original author or authors.
*
* 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.powermock.core.bytebuddy;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.jar.asm.ClassVisitor;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;

public class MaxLocalsExtractor extends ClassVisitor {

private MethodMaxLocals methodMaxLocals;

public MaxLocalsExtractor() {
super(Opcodes.ASM5);
}

@Override
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature,
final String[] exceptions) {
if (MethodDescription.CONSTRUCTOR_INTERNAL_NAME.equals(name)) {
methodMaxLocals = new MethodMaxLocals();
return new MaxLocalsMethodVisitor(name, desc, methodMaxLocals);
}
return super.visitMethod(access, name, desc, signature, exceptions);
}

public MethodMaxLocals getMethods() {
return methodMaxLocals;
}

private static class MaxLocalsMethodVisitor extends MethodVisitor {

private final String name;
private final String signature;
private final MethodMaxLocals methodMaxLocals;
private int maxLocals;

private MaxLocalsMethodVisitor(final String name, final String signature,
final MethodMaxLocals methodMaxLocals) {
super(Opcodes.ASM5);
this.name = name;
this.signature = signature;
this.methodMaxLocals = methodMaxLocals;
}

@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
this.maxLocals = maxLocals;
super.visitMaxs(maxStack, maxLocals);
}

@Override
public void visitEnd() {
methodMaxLocals.add(name, signature, maxLocals);
super.visitEnd();
}
}

}
@@ -0,0 +1,44 @@
/*
*
* Copyright 2017 the original author or authors.
*
* 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.powermock.core.bytebuddy;

import net.bytebuddy.description.method.MethodDescription;

import java.util.HashMap;
import java.util.Map;


public class MethodMaxLocals {

private final Map<String, Integer> methodMaxLocals;

MethodMaxLocals() {
methodMaxLocals = new HashMap<String, Integer>();
}

public void add(String name, String signature, int maxLocals) {
methodMaxLocals.put(name + signature, maxLocals);
}

public int getMethodMaxLocal(final MethodDescription instrumentedMethod) {
final String key = instrumentedMethod.getInternalName() + instrumentedMethod.getDescriptor();
final Integer maxLocals = methodMaxLocals.get(key);
return maxLocals == null ? 0 : maxLocals;
}
}

0 comments on commit d6ccb0f

Please sign in to comment.