cz.advel.stack.instrument.StackGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stack-alloc Show documentation
Show all versions of stack-alloc Show documentation
Allocate Java objects on method stack instead of program heap.
The newest version!
/*
* JStackAlloc (c) 2008 Martin Dvorak
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
package cz.advel.stack.instrument;
import java.lang.reflect.Method;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
class StackGenerator implements Opcodes {
/**
* A private constructor to inhibit instantiation of this class.
*/
private StackGenerator() {
// do nothing
}
private static int getParentDistance(Class concrete, Class parent) {
int cnt = 0;
while (concrete != null) {
if (concrete == parent) {
break;
}
cnt++;
concrete = concrete.getSuperclass();
}
return cnt;
}
public static Method findGetMethodType(String type) {
try {
Class cls = Class.forName(type.replace('/', '.'));
Method bestMethod = null;
int bestDist = Integer.MAX_VALUE;
for (Method method : cls.getMethods()) {
if (method.getName().equals("set") && method.getParameterTypes().length == 1) {
if (method.getParameterTypes()[0].isAssignableFrom(cls)) {
int dist = getParentDistance(cls, method.getParameterTypes()[0]);
if (bestMethod == null || dist < bestDist) {
bestMethod = method;
bestDist = dist;
}
}
}
}
if (bestMethod == null) {
throw new IllegalStateException("can't find set method for "+cls);
}
return bestMethod;
}
catch (ClassNotFoundException e) {
throw new IllegalStateException(e);
}
}
public static byte[] generateStackClass(Instrumenter instr, String[] types) {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
cw.visit(V1_5, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, instr.getStackInternalName(), null, "java/lang/Object", null);
cw.visitInnerClass(instr.getStackInternalName()+"$1", null, null, ACC_FINAL + ACC_STATIC);
// fields:
if (instr.isSingleThread()) {
fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "INSTANCE", "L"+instr.getStackInternalName()+";", null, null);
fv.visitEnd();
}
else {
fv = cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "threadLocal", "Ljava/lang/ThreadLocal;", null, null);
fv.visitEnd();
}
for (String type : types) {
String mangled = Instrumenter.mangleInternalName(type);
fv = cw.visitField(ACC_PRIVATE, "list$"+mangled, "Ljava/util/ArrayList;", null, null);
fv.visitEnd();
fv = cw.visitField(ACC_PRIVATE, "stack$"+mangled, "[I", null, null);
fv.visitEnd();
fv = cw.visitField(ACC_PRIVATE, "count$"+mangled, "I", null, null);
fv.visitEnd();
fv = cw.visitField(ACC_PRIVATE, "pos$"+mangled, "I", null, null);
fv.visitEnd();
}
// constructor:
{
mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V");
for (String type : types) {
String mangled = Instrumenter.mangleInternalName(type);
mv.visitVarInsn(ALOAD, 0);
mv.visitTypeInsn(NEW, "java/util/ArrayList");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "", "()V");
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "list$"+mangled, "Ljava/util/ArrayList;");
mv.visitVarInsn(ALOAD, 0);
mv.visitIntInsn(BIPUSH, 16);
mv.visitIntInsn(NEWARRAY, T_INT);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(ICONST_0);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "count$"+mangled, "I");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(ICONST_0);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "pos$"+mangled, "I");
}
mv.visitInsn(RETURN);
mv.visitMaxs(3, 1);
mv.visitEnd();
}
// static stack get method:
if (!instr.isSingleThread()) {
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "get", "()L"+instr.getStackInternalName()+";", null, null);
mv.visitCode();
mv.visitFieldInsn(GETSTATIC, instr.getStackInternalName(), "threadLocal", "Ljava/lang/ThreadLocal;");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ThreadLocal", "get", "()Ljava/lang/Object;");
mv.visitTypeInsn(CHECKCAST, instr.getStackInternalName());
mv.visitInsn(ARETURN);
mv.visitMaxs(1, 0);
mv.visitEnd();
}
// per-type methods:
for (String type : types) {
String mangled = Instrumenter.mangleInternalName(type);
{
mv = cw.visitMethod(ACC_PUBLIC, "push$"+mangled, "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "count$"+mangled, "I");
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitInsn(ARRAYLENGTH);
Label l0 = new Label();
mv.visitJumpInsn(IF_ICMPNE, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, instr.getStackInternalName(), "resize$"+mangled, "()V");
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(DUP);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "count$"+mangled, "I");
mv.visitInsn(DUP_X1);
mv.visitInsn(ICONST_1);
mv.visitInsn(IADD);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "count$"+mangled, "I");
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "pos$"+mangled, "I");
mv.visitInsn(IASTORE);
mv.visitInsn(RETURN);
mv.visitMaxs(5, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PRIVATE, "resize$"+mangled, "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitInsn(ARRAYLENGTH);
mv.visitInsn(ICONST_1);
mv.visitInsn(ISHL);
mv.visitIntInsn(NEWARRAY, T_INT);
mv.visitVarInsn(ASTORE, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitInsn(ARRAYLENGTH);
mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitInsn(RETURN);
mv.visitMaxs(5, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "pop$"+mangled, "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "stack$"+mangled, "[I");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(DUP);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "count$"+mangled, "I");
mv.visitInsn(ICONST_1);
mv.visitInsn(ISUB);
mv.visitInsn(DUP_X1);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "count$"+mangled, "I");
mv.visitInsn(IALOAD);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "pos$"+mangled, "I");
mv.visitInsn(RETURN);
mv.visitMaxs(5, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "get$"+mangled, "()L"+type+";", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "pos$"+mangled, "I");
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "list$"+mangled, "Ljava/util/ArrayList;");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/ArrayList", "size", "()I");
Label l0 = new Label();
mv.visitJumpInsn(IF_ICMPNE, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "list$"+mangled, "Ljava/util/ArrayList;");
mv.visitTypeInsn(NEW, type);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, type, "", "()V");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/ArrayList", "add", "(Ljava/lang/Object;)Z");
mv.visitInsn(POP);
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "list$"+mangled, "Ljava/util/ArrayList;");
mv.visitVarInsn(ALOAD, 0);
mv.visitInsn(DUP);
mv.visitFieldInsn(GETFIELD, instr.getStackInternalName(), "pos$"+mangled, "I");
mv.visitInsn(DUP_X1);
mv.visitInsn(ICONST_1);
mv.visitInsn(IADD);
mv.visitFieldInsn(PUTFIELD, instr.getStackInternalName(), "pos$"+mangled, "I");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/ArrayList", "get", "(I)Ljava/lang/Object;");
mv.visitTypeInsn(CHECKCAST, type);
mv.visitInsn(ARETURN);
mv.visitMaxs(5, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "get$"+mangled, "(L"+type+";)L"+type+";", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, instr.getStackInternalName(), "get$"+mangled, "()L"+type+";");
mv.visitVarInsn(ASTORE, 2);
mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, 1);
Method m = findGetMethodType(type);
mv.visitMethodInsn(INVOKEVIRTUAL, type, "set", "(L"+Type.getInternalName(m.getParameterTypes()[0])+";)V");
mv.visitVarInsn(ALOAD, 2);
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 3);
mv.visitEnd();
}
}
// class init:
{
mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null);
mv.visitCode();
if (instr.isSingleThread()) {
mv.visitTypeInsn(NEW, instr.getStackInternalName());
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, instr.getStackInternalName(), "", "()V");
mv.visitFieldInsn(PUTSTATIC, instr.getStackInternalName(), "INSTANCE", "L"+instr.getStackInternalName()+";");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 0);
}
else {
mv.visitTypeInsn(NEW, instr.getStackInternalName()+"$1");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, instr.getStackInternalName()+"$1", "", "()V");
mv.visitFieldInsn(PUTSTATIC, instr.getStackInternalName(), "threadLocal", "Ljava/lang/ThreadLocal;");
if (!instr.isIsolated()) {
mv.visitFieldInsn(GETSTATIC, instr.getStackInternalName(), "threadLocal", "Ljava/lang/ThreadLocal;");
mv.visitMethodInsn(INVOKESTATIC, Instrumenter.STACK_NAME, "internalRegisterThreadLocal", "(Ljava/lang/ThreadLocal;)V");
}
mv.visitInsn(RETURN);
mv.visitMaxs(2, 0);
}
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
public static byte[] generateStackClass1(Instrumenter instr) {
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
cw.visit(V1_5, ACC_FINAL + ACC_SUPER, instr.getStackInternalName()+"$1", null, "java/lang/ThreadLocal", null);
cw.visitOuterClass(instr.getStackInternalName(), null, null);
cw.visitInnerClass(instr.getStackInternalName()+"$1", null, null, ACC_FINAL + ACC_STATIC);
{
mv = cw.visitMethod(0, "", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ThreadLocal", "", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PROTECTED, "initialValue", "()Ljava/lang/Object;", null, null);
mv.visitCode();
mv.visitTypeInsn(NEW, instr.getStackInternalName());
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, instr.getStackInternalName(), "", "()V");
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy