]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/MethodBuilderBase.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / utils / MethodBuilderBase.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/MethodBuilderBase.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/MethodBuilderBase.java
new file mode 100644 (file)
index 0000000..0f56aba
--- /dev/null
@@ -0,0 +1,579 @@
+package org.simantics.scl.compiler.internal.codegen.utils;
+
+import org.cojen.classfile.MethodDesc;
+import org.cojen.classfile.TypeDesc;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class MethodBuilderBase {
+    private ClassBuilder classBuilder;
+    private MethodVisitor methodVisitor;
+    private LocalVariable[] parameters;
+    private int localVariableCount = 0;
+    
+    public MethodBuilderBase(ClassBuilder classBuilder, boolean isStatic, MethodVisitor methodVisitor, TypeDesc[] parameterTypes) {
+        this.classBuilder = classBuilder;
+        this.methodVisitor = methodVisitor;
+        this.parameters = new LocalVariable[parameterTypes.length];
+        if(!isStatic)
+            ++localVariableCount;
+        for(int i=0;i<parameterTypes.length;++i) {
+            parameters[i] = createLocalVariable("p" + i, parameterTypes[i]);
+            methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
+        }
+        methodVisitor.visitCode();
+    }
+
+    public void loadConstant(boolean value) {
+        if(value)
+            methodVisitor.visitInsn(Opcodes.ICONST_1);
+        else
+            methodVisitor.visitInsn(Opcodes.ICONST_0);
+    }
+    
+    public void loadConstant(int value) {
+        if (value >= -1 && value <= 5) {
+            methodVisitor.visitInsn(Opcodes.ICONST_0 + value);
+        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+            methodVisitor.visitIntInsn(Opcodes.BIPUSH, value);
+        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+            methodVisitor.visitIntInsn(Opcodes.SIPUSH, value);
+        } else {
+            methodVisitor.visitLdcInsn(value);
+        }
+    }
+    
+    public void loadConstant(long value) {
+        if(value == 0L)
+            methodVisitor.visitInsn(Opcodes.LCONST_0);
+        else if(value == 1L)
+            methodVisitor.visitInsn(Opcodes.LCONST_1);
+        else
+            methodVisitor.visitLdcInsn(value);
+    }
+    
+    public void loadConstant(float value) {
+        if(value == 0.0f)
+            methodVisitor.visitInsn(Opcodes.FCONST_0);
+        else if(value == 1.0f)
+            methodVisitor.visitInsn(Opcodes.FCONST_1);
+        else
+            methodVisitor.visitLdcInsn(value);
+    }
+    
+    public void loadConstant(double value) {
+        if(value == 0.0)
+            methodVisitor.visitInsn(Opcodes.DCONST_0);
+        else if(value == 1.0)
+            methodVisitor.visitInsn(Opcodes.DCONST_1);
+        else
+            methodVisitor.visitLdcInsn(value);
+    }
+    
+    public void loadConstant(String value) {
+        methodVisitor.visitLdcInsn(value);
+    }
+    
+    public void loadConstant(TypeDesc value) {
+        if(value.isPrimitive())
+            loadStaticField(getClassName(value.toObjectType()), "TYPE", Constants.CLASS);
+        else
+            methodVisitor.visitLdcInsn(Type.getType(value.getDescriptor()));
+    }
+
+    public void dup() {
+        methodVisitor.visitInsn(Opcodes.DUP);
+    }
+    
+    public void dup2() {
+        methodVisitor.visitInsn(Opcodes.DUP2);
+    }
+
+    public void dupX1() {
+        methodVisitor.visitInsn(Opcodes.DUP_X1);
+    }
+    
+    public void swap() {
+        methodVisitor.visitInsn(Opcodes.SWAP);
+    }
+
+    public void pop() {
+        methodVisitor.visitInsn(Opcodes.POP);
+    }
+    
+    public void pop2() {
+        methodVisitor.visitInsn(Opcodes.POP2);
+    }
+
+    public void convert(TypeDesc fromType, TypeDesc toType) {
+        switch(fromType.getTypeCode() + 16*toType.getTypeCode()) {
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.BOOLEAN_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
+            return;
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.INT_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
+            return;
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.FLOAT_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
+            return;
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
+            return;
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.CHAR_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
+            return;
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.LONG_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
+            return;
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.SHORT_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
+            return;
+        case TypeDesc.OBJECT_CODE + 16*TypeDesc.BYTE_CODE:
+            methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
+            return;
+        case TypeDesc.DOUBLE_CODE + 16*TypeDesc.FLOAT_CODE:
+            methodVisitor.visitInsn(Opcodes.D2F);
+            return;
+        case TypeDesc.FLOAT_CODE + 16*TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitInsn(Opcodes.F2D);
+            return;
+        case TypeDesc.INT_CODE + 16*TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitInsn(Opcodes.I2D);
+            return;
+        case TypeDesc.DOUBLE_CODE + 16*TypeDesc.INT_CODE:
+            methodVisitor.visitInsn(Opcodes.D2I);
+            return;
+        case TypeDesc.INT_CODE + 16*TypeDesc.FLOAT_CODE:
+            methodVisitor.visitInsn(Opcodes.I2F);
+            return;
+        case TypeDesc.FLOAT_CODE + 16*TypeDesc.INT_CODE:
+            methodVisitor.visitInsn(Opcodes.F2I);
+            return;
+        case TypeDesc.LONG_CODE + 16*TypeDesc.FLOAT_CODE:
+            methodVisitor.visitInsn(Opcodes.L2F);
+            return;
+        case TypeDesc.FLOAT_CODE + 16*TypeDesc.LONG_CODE:
+            methodVisitor.visitInsn(Opcodes.F2L);
+            return;
+        case TypeDesc.LONG_CODE + 16*TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitInsn(Opcodes.L2D);
+            return;
+        case TypeDesc.DOUBLE_CODE + 16*TypeDesc.LONG_CODE:
+            methodVisitor.visitInsn(Opcodes.D2L);
+            return;
+        case TypeDesc.INT_CODE + 16*TypeDesc.LONG_CODE:
+            methodVisitor.visitInsn(Opcodes.I2L);
+            return;
+        case TypeDesc.LONG_CODE + 16*TypeDesc.INT_CODE:
+            methodVisitor.visitInsn(Opcodes.L2I);
+            return;
+        case TypeDesc.INT_CODE + 16*TypeDesc.SHORT_CODE:
+            methodVisitor.visitInsn(Opcodes.I2S);
+            return;
+        case TypeDesc.SHORT_CODE + 16*TypeDesc.INT_CODE:
+        case TypeDesc.BOOLEAN_CODE + 16*TypeDesc.INT_CODE:
+            // NOP
+            return;
+        case TypeDesc.INT_CODE + 16*TypeDesc.BYTE_CODE:
+            methodVisitor.visitInsn(Opcodes.I2B);
+            return;
+        case TypeDesc.BYTE_CODE + 16*TypeDesc.INT_CODE:
+            // NOP
+            return;
+        case TypeDesc.INT_CODE + 16*TypeDesc.CHAR_CODE:
+            methodVisitor.visitInsn(Opcodes.I2C);
+            return;
+        case TypeDesc.CHAR_CODE + 16*TypeDesc.INT_CODE:
+            // NOP
+            return;
+        default:
+            System.out.println("convert: " + fromType + " -> " + toType);
+        }
+    }
+
+    public void convert(TypeDesc fromType, TypeDesc toType,
+            int convertFpNormal) {
+        convert(fromType, toType);
+    }
+
+    public LocalVariable createLocalVariable(String name, TypeDesc type) {
+        int index = localVariableCount;
+        localVariableCount += type == TypeDesc.DOUBLE || type == TypeDesc.LONG ? 2 : 1;
+        return new LocalVariable(index, type);
+    }
+
+    public void storeLocal(LocalVariable local) {
+        switch(local.type.getTypeCode()) {
+        case TypeDesc.BOOLEAN_CODE:
+        case TypeDesc.BYTE_CODE:
+        case TypeDesc.CHAR_CODE:
+        case TypeDesc.SHORT_CODE:
+        case TypeDesc.INT_CODE:
+            methodVisitor.visitVarInsn(Opcodes.ISTORE, local.index);
+            break;     
+        case TypeDesc.FLOAT_CODE:
+            methodVisitor.visitVarInsn(Opcodes.FSTORE, local.index);
+            break;     
+        case TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitVarInsn(Opcodes.DSTORE, local.index);
+            break;     
+        case TypeDesc.LONG_CODE:
+            methodVisitor.visitVarInsn(Opcodes.LSTORE, local.index);
+            break;     
+        case TypeDesc.OBJECT_CODE:
+            methodVisitor.visitVarInsn(Opcodes.ASTORE, local.index);
+            break;     
+        default: throw new IllegalArgumentException();
+        }
+    }
+
+    public void ifZeroComparisonBranch(Label location, String choice) {
+        int opcode;
+        if(choice.equals("!="))
+            opcode = Opcodes.IFNE; 
+        else if(choice.equals("=="))
+            opcode = Opcodes.IFEQ;
+        else if(choice.equals("<"))
+            opcode = Opcodes.IFLT;
+        else if(choice.equals(">"))
+            opcode = Opcodes.IFGT;
+        else if(choice.equals("<="))
+            opcode = Opcodes.IFLE;
+        else if(choice.equals(">="))
+            opcode = Opcodes.IFGE;
+        else
+            throw new IllegalArgumentException("Invalid choice \"" + choice + "\".");
+        methodVisitor.visitJumpInsn(opcode, location);
+    }
+
+    public void ifComparisonBranch(Label location, String choice, TypeDesc type) {
+        switch(type.getTypeCode()) {
+        case TypeDesc.BOOLEAN_CODE:
+        case TypeDesc.BYTE_CODE:
+        case TypeDesc.CHAR_CODE:
+        case TypeDesc.SHORT_CODE:
+        case TypeDesc.INT_CODE: {
+            int opcode;
+            if(choice.equals("!="))
+                opcode = Opcodes.IF_ICMPNE; 
+            else if(choice.equals("=="))
+                opcode = Opcodes.IF_ICMPEQ;
+            else if(choice.equals("<"))
+                opcode = Opcodes.IF_ICMPLT;
+            else if(choice.equals(">"))
+                opcode = Opcodes.IF_ICMPGT;
+            else if(choice.equals("<="))
+                opcode = Opcodes.IF_ICMPLE;
+            else if(choice.equals(">="))
+                opcode = Opcodes.IF_ICMPGE;
+            else
+                throw new IllegalArgumentException("Invalid choice \"" + choice + "\".");
+            methodVisitor.visitJumpInsn(opcode, location);
+        } break;     
+        case TypeDesc.FLOAT_CODE:
+            methodVisitor.visitInsn(Opcodes.FCMPL);
+            ifZeroComparisonBranch(location, choice);
+            break;     
+        case TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitInsn(Opcodes.DCMPL);
+            ifZeroComparisonBranch(location, choice);
+            break;     
+        case TypeDesc.LONG_CODE:
+            methodVisitor.visitInsn(Opcodes.LCMP);
+            ifZeroComparisonBranch(location, choice);
+            break;     
+        case TypeDesc.OBJECT_CODE: {
+            int opcode;
+            if(choice.equals("!="))
+                opcode = Opcodes.IF_ACMPNE; 
+            else if(choice.equals("=="))
+                opcode = Opcodes.IF_ACMPEQ;
+            else
+                throw new IllegalArgumentException("Invalid choice \"" + choice + "\".");
+            methodVisitor.visitJumpInsn(opcode, location);
+        } break;     
+        default: throw new IllegalArgumentException();
+        }
+    }
+
+    public void ifNullBranch(Label location, boolean choice) {
+        methodVisitor.visitJumpInsn(choice ? Opcodes.IFNULL : Opcodes.IFNONNULL, location);
+    }
+    
+    public void branch(Label location) {
+        methodVisitor.visitJumpInsn(Opcodes.GOTO, location);
+    }
+
+    public Label createLabel() {
+        return new Label();
+    }
+    
+    public void setLocation(Label label) {
+        methodVisitor.visitLabel(label);
+    }
+
+    public void loadLocal(LocalVariable local) {
+        switch(local.type.getTypeCode()) {
+        case TypeDesc.BOOLEAN_CODE:
+        case TypeDesc.BYTE_CODE:
+        case TypeDesc.CHAR_CODE:
+        case TypeDesc.SHORT_CODE:
+        case TypeDesc.INT_CODE:
+            methodVisitor.visitVarInsn(Opcodes.ILOAD, local.index);
+            break;     
+        case TypeDesc.FLOAT_CODE:
+            methodVisitor.visitVarInsn(Opcodes.FLOAD, local.index);
+            break;     
+        case TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitVarInsn(Opcodes.DLOAD, local.index);
+            break;     
+        case TypeDesc.LONG_CODE:
+            methodVisitor.visitVarInsn(Opcodes.LLOAD, local.index);
+            break;     
+        case TypeDesc.OBJECT_CODE:
+            methodVisitor.visitVarInsn(Opcodes.ALOAD, local.index);
+            break;     
+        default: throw new IllegalArgumentException();
+        }
+    }
+
+    public void loadNull() {
+        methodVisitor.visitInsn(Opcodes.ACONST_NULL);
+    }
+
+    public void loadFromArray(TypeDesc type) {
+        switch(type.getTypeCode()) {
+        case TypeDesc.BOOLEAN_CODE:
+            methodVisitor.visitInsn(Opcodes.BALOAD);
+            break;
+        case TypeDesc.BYTE_CODE:
+            methodVisitor.visitInsn(Opcodes.BALOAD);
+            break;
+        case TypeDesc.CHAR_CODE:
+            methodVisitor.visitInsn(Opcodes.CALOAD);
+            break;
+        case TypeDesc.SHORT_CODE:
+            methodVisitor.visitInsn(Opcodes.SALOAD);
+            break;
+        case TypeDesc.INT_CODE:
+            methodVisitor.visitInsn(Opcodes.IALOAD);
+            break;     
+        case TypeDesc.FLOAT_CODE:
+            methodVisitor.visitInsn(Opcodes.FALOAD);
+            break;     
+        case TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitInsn(Opcodes.DALOAD);
+            break;     
+        case TypeDesc.LONG_CODE:
+            methodVisitor.visitInsn(Opcodes.LALOAD);
+            break;     
+        case TypeDesc.OBJECT_CODE:
+            methodVisitor.visitInsn(Opcodes.AALOAD);
+            break;     
+        default: throw new IllegalArgumentException();
+        }
+    }
+
+    public void invokeInterface(String className, String methodName,
+            TypeDesc ret, TypeDesc[] params) {
+        checkClassName(className);
+        methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, className, methodName,
+                MethodDesc.forArguments(ret, params).getDescriptor(), true);
+    }
+
+    public void invokeInterface(TypeDesc className, String methodName,
+            TypeDesc ret, TypeDesc[] params) {
+        invokeInterface(getClassName(className), methodName, ret, params);
+    }
+
+    public void invokeVirtual(String className, String methodName,
+            TypeDesc ret, TypeDesc[] params) {
+        checkClassName(className);
+        methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, methodName,
+                MethodDesc.forArguments(ret, params).getDescriptor(), false);
+    }
+
+    public void invokeVirtual(TypeDesc className, String methodName, TypeDesc ret,
+            TypeDesc[] params) {
+        invokeVirtual(getClassName(className), methodName, ret, params);
+    }
+
+    public void invokeConstructor(String className, TypeDesc[] params) {
+        checkClassName(className);
+        methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "<init>",
+                MethodDesc.forArguments(TypeDesc.VOID, params).getDescriptor(), false);
+    }
+
+    public void invokeConstructor(TypeDesc className, TypeDesc[] params) {
+        invokeConstructor(getClassName(className), params);
+    }
+
+    public void invokeSuperConstructor(TypeDesc[] params) {
+        invokeConstructor(classBuilder.getSuperClassName(), params);
+    }
+
+    public void invokeStatic(String className, String methodName, TypeDesc ret,
+            TypeDesc[] params) {
+        checkClassName(className);
+        methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, methodName,
+                MethodDesc.forArguments(ret, params).getDescriptor(), false);
+    }
+
+    public void invokeStatic(TypeDesc className, String methodName, TypeDesc ret,
+            TypeDesc[] params) {
+        invokeStatic(getClassName(className), methodName, ret, params);
+    }
+
+    public void newObject(TypeDesc type) {
+        methodVisitor.visitTypeInsn(Opcodes.NEW, getClassName(type));
+    }
+
+    public void newObject(TypeDesc type, int dimensions) {
+        methodVisitor.visitMultiANewArrayInsn(type.getDescriptor(), dimensions);
+    }
+
+    public void loadStaticField(String className, String fieldName, TypeDesc type) {
+        checkClassName(className);
+        methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, className, fieldName, type.getDescriptor());
+    }
+
+    public void loadStaticField(TypeDesc className, String fieldName,
+            TypeDesc type) {
+        loadStaticField(getClassName(className), fieldName, type);
+    }
+
+    public void loadField(String className, String fieldName, TypeDesc type) {
+        checkClassName(className);
+        methodVisitor.visitFieldInsn(Opcodes.GETFIELD, className, fieldName, type.getDescriptor());
+    }
+
+    public void storeStaticField(String className, String fieldName,
+            TypeDesc type) {
+        checkClassName(className);
+        methodVisitor.visitFieldInsn(Opcodes.PUTSTATIC, className, fieldName, type.getDescriptor());
+    }
+
+    public void storeField(String className, String fieldName, TypeDesc type) {
+        checkClassName(className);
+        methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, className, fieldName, type.getDescriptor());
+    }
+
+    public void storeToArray(TypeDesc type) {
+        switch(type.getTypeCode()) {
+        case TypeDesc.BOOLEAN_CODE:
+            methodVisitor.visitInsn(Opcodes.BASTORE);
+            break;
+        case TypeDesc.BYTE_CODE:
+            methodVisitor.visitInsn(Opcodes.BASTORE);
+            break;
+        case TypeDesc.CHAR_CODE:
+            methodVisitor.visitInsn(Opcodes.CASTORE);
+            break;
+        case TypeDesc.SHORT_CODE:
+            methodVisitor.visitInsn(Opcodes.SASTORE);
+            break;
+        case TypeDesc.INT_CODE:
+            methodVisitor.visitInsn(Opcodes.IASTORE);
+            break;     
+        case TypeDesc.FLOAT_CODE:
+            methodVisitor.visitInsn(Opcodes.FASTORE);
+            break;     
+        case TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitInsn(Opcodes.DASTORE);
+            break;     
+        case TypeDesc.LONG_CODE:
+            methodVisitor.visitInsn(Opcodes.LASTORE);
+            break;     
+        case TypeDesc.OBJECT_CODE:
+            methodVisitor.visitInsn(Opcodes.AASTORE);
+            break;     
+        default: throw new IllegalArgumentException();
+        }
+    }
+
+    public void math(int opcode) {
+        methodVisitor.visitInsn(opcode);
+    }
+
+    public void throwObject() {
+        methodVisitor.visitInsn(Opcodes.ATHROW);
+    }
+
+    public void checkCast(TypeDesc type) {
+        methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, getClassName(type));
+    }
+
+    public void instanceOf(TypeDesc type) {
+        methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, getClassName(type));
+    }
+
+    public void arrayLength() {
+        methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
+    }
+
+    public void loadThis() {
+        methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+    }
+
+    public LocalVariable getParameter(int index) {
+        return parameters[index];
+    }
+
+    public void returnVoid() {
+        methodVisitor.visitInsn(Opcodes.RETURN);
+    }
+
+    public void returnValue(TypeDesc type) {
+        switch(type.getTypeCode()) {
+        case TypeDesc.VOID_CODE:
+            methodVisitor.visitInsn(Opcodes.RETURN);
+            break;     
+        case TypeDesc.BOOLEAN_CODE:
+        case TypeDesc.BYTE_CODE:
+        case TypeDesc.CHAR_CODE:
+        case TypeDesc.SHORT_CODE:
+        case TypeDesc.INT_CODE:
+            methodVisitor.visitInsn(Opcodes.IRETURN);
+            break;     
+        case TypeDesc.FLOAT_CODE:
+            methodVisitor.visitInsn(Opcodes.FRETURN);
+            break;     
+        case TypeDesc.DOUBLE_CODE:
+            methodVisitor.visitInsn(Opcodes.DRETURN);
+            break;     
+        case TypeDesc.LONG_CODE:
+            methodVisitor.visitInsn(Opcodes.LRETURN);
+            break;     
+        case TypeDesc.OBJECT_CODE:
+            methodVisitor.visitInsn(Opcodes.ARETURN);
+            break;     
+        default: throw new IllegalArgumentException();
+        }
+    }
+    
+    public void finish() {
+        methodVisitor.visitMaxs(0, 0);
+        methodVisitor.visitEnd();
+    }
+
+    public String getClassName() {
+        return classBuilder.className;
+    }
+    
+    public static String getClassName(TypeDesc typeDesc) {
+        if(typeDesc.isArray())
+            return typeDesc.getDescriptor();
+        else
+            return typeDesc.getFullName().replace('.', '/');
+    }
+    
+    private static void checkClassName(String className) {
+        ClassBuilder.checkClassName(className);
+    }
+
+    public static String getClassName(Class<?> clazz) {
+        return clazz.getName().replace('.', '/');
+    }
+}