bytecodehelper.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 709 行 · 第 1/2 页

JAVA
709
字号
            cv.visitTypeInsn(
                    CHECKCAST,
                    type.isArray() ? getTypeDescription(type) : getClassInternalName(type));
        }
    }

    public void load(ClassNode type, int idx) {
        if (type==ClassHelper.double_TYPE) {
            cv.visitVarInsn(DLOAD, idx);
        }
        else if (type==ClassHelper.float_TYPE) {
            cv.visitVarInsn(FLOAD, idx);
        }
        else if (type==ClassHelper.long_TYPE) {
            cv.visitVarInsn(LLOAD, idx);
        }
        else if (
            type==ClassHelper.boolean_TYPE
                || type==ClassHelper.char_TYPE
                || type==ClassHelper.byte_TYPE
                || type==ClassHelper.int_TYPE
                || type==ClassHelper.short_TYPE)
        {    
            cv.visitVarInsn(ILOAD, idx);
        }
        else {
            cv.visitVarInsn(ALOAD, idx);
        }
    }

    public void load(Variable v) {
    	load(v.getType(), v.getIndex());
    }

    public void store(Variable v, boolean markStart) {
        ClassNode type = v.getType();
        unbox(type);
        int idx = v.getIndex();

        if (type==ClassHelper.double_TYPE) {
            cv.visitVarInsn(DSTORE, idx);
        }
        else if (type==ClassHelper.float_TYPE) {
            cv.visitVarInsn(FSTORE, idx);
        }
        else if (type==ClassHelper.long_TYPE) {
            cv.visitVarInsn(LSTORE, idx);
        }
        else if (
                type==ClassHelper.boolean_TYPE
                || type==ClassHelper.char_TYPE
                || type==ClassHelper.byte_TYPE
                || type==ClassHelper.int_TYPE
                || type==ClassHelper.short_TYPE) {
            cv.visitVarInsn(ISTORE, idx);
        }
        else {
            cv.visitVarInsn(ASTORE, idx);
        }
    }

    public void store(Variable v) {
        store(v, false);
    }

    /**
     * load the constant on the operand stack. primitives auto-boxed.
     */
    void loadConstant (Object value) {
        if (value == null) {
            cv.visitInsn(ACONST_NULL);
        }
        else if (value instanceof String) {
            cv.visitLdcInsn(value);
        }
        else if (value instanceof Character) {
            String className = "java/lang/Character";
            cv.visitTypeInsn(NEW, className);
            cv.visitInsn(DUP);
            cv.visitLdcInsn(value);
            String methodType = "(C)V";
            cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
        }
        else if (value instanceof Number) {
            /** todo it would be more efficient to generate class constants */
            Number n = (Number) value;
            String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
            cv.visitTypeInsn(NEW, className);
            cv.visitInsn(DUP);
            String methodType;
            if (n instanceof Integer) {
            	//pushConstant(n.intValue());
            	cv.visitLdcInsn(n);
            	methodType = "(I)V";
        	}
            else if (n instanceof Double) {
            	cv.visitLdcInsn(n);
            	methodType = "(D)V";
            }
            else if (n instanceof Float) {
            	cv.visitLdcInsn(n);
            	methodType = "(F)V";
            }
            else if (n instanceof Long) {
            	cv.visitLdcInsn(n);
            	methodType = "(J)V";
            }
            else if (n instanceof BigDecimal) {
            	cv.visitLdcInsn(n.toString());
            	methodType = "(Ljava/lang/String;)V";
            }
            else if (n instanceof BigInteger) {
            	cv.visitLdcInsn(n.toString());
            	methodType = "(Ljava/lang/String;)V";
            }
            else if (n instanceof Short) {
            	cv.visitLdcInsn(n);
            	methodType = "(S)V";
            }
            else if (n instanceof Byte) {
            	cv.visitLdcInsn(n);
            	methodType = "(B)V";
            }
            else {
        	throw new ClassGeneratorException(
                               "Cannot generate bytecode for constant: " + value
                             + " of type: " + value.getClass().getName()
                             + ".  Numeric constant type not supported.");
            }
            cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
        }
        else if (value instanceof Boolean) {
            Boolean bool = (Boolean) value;
            String text = (bool.booleanValue()) ? "TRUE" : "FALSE";
            cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
        }
        else if (value instanceof Class) {
            Class vc = (Class) value;
            if (vc.getName().equals("java.lang.Void")) {
                // load nothing here for void
            } else {
                throw new ClassGeneratorException(
                "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
            }
        }
        else {
            throw new ClassGeneratorException(
                "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
        }
    }


    /**
     * load the value of the variable on the operand stack. unbox it if it's a reference
     * @param variable
     */
    public void loadVar(Variable variable) {
		int index = variable.getIndex();
		if (variable.isHolder()) {
			cv.visitVarInsn(ALOAD, index);
			cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
		} else {
            load(variable);
            if (variable!=Variable.THIS_VARIABLE && variable!=Variable.SUPER_VARIABLE) {
                box(variable.getType());
            }
		}
	}
    
    public void storeVar(Variable variable) {
        String  type   = variable.getTypeName();
        int     index  = variable.getIndex();
        
    	if (variable.isHolder()) {
            cv.visitVarInsn(ALOAD, index);
            cv.visitInsn(SWAP);  
            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
        }
        else {
            store(variable,false);
        }
    }

    public void putField(FieldNode fld) {
    	putField(fld, getClassInternalName(fld.getOwner()));
    }

    public void putField(FieldNode fld, String ownerName) {
    	cv.visitFieldInsn(PUTFIELD, ownerName, fld.getName(), getTypeDescription(fld.getType()));
    }
    
    public void swapObjectWith(ClassNode type) {
        if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
            cv.visitInsn(DUP_X2);
            cv.visitInsn(POP);
        } else {
            cv.visitInsn(SWAP);
        }
    }
    
    public void swapWithObject(ClassNode type) {
        if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
            cv.visitInsn(DUP2_X1);
            cv.visitInsn(POP2);
        } else {
            cv.visitInsn(SWAP);
        }
    }

    public static ClassNode boxOnPrimitive(ClassNode type) {
        if (!type.isArray()) return ClassHelper.getWrapper(type);
        return boxOnPrimitive(type.getComponentType()).makeArray();
    }

    /**
     * convert boolean to Boolean
     */
    public void boxBoolean() {
        Label l0 = new Label();
        cv.visitJumpInsn(IFEQ, l0);
        cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
        Label l1 = new Label();
        cv.visitJumpInsn(GOTO, l1);
        cv.visitLabel(l0);
        cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
        cv.visitLabel(l1);
    }

    /**
     * negate a boolean on stack. true->false, false->true
     */
    public void negateBoolean(){
        // code to negate the primitive boolean
        Label endLabel = new Label();
        Label falseLabel = new Label();
        cv.visitJumpInsn(IFNE,falseLabel);
        cv.visitInsn(ICONST_1);
        cv.visitJumpInsn(GOTO,endLabel);
        cv.visitLabel(falseLabel);
        cv.visitInsn(ICONST_0);
        cv.visitLabel(endLabel);
    }

    /**
     * load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
     * @param msg
     */
    public void mark(String msg) {
        cv.visitLdcInsn(msg);
        cv.visitInsn(POP);
    }
    
    /**
     * returns a name that Class.forName() can take. Notablely for arrays:
     * [I, [Ljava.lang.String; etc
     * Regular object type:  java.lang.String
     * @param name
     */
    public static String formatNameForClassLoading(String name) {
        if (name.equals("int")
        		|| name.equals("long")
				|| name.equals("short")
				|| name.equals("float")
				|| name.equals("double")
				|| name.equals("byte")
				|| name.equals("char")
				|| name.equals("boolean")
				|| name.equals("void")
        	) {
            return name;
        }

        if (name == null) {
            return "java.lang.Object;";
        }

        if (name.startsWith("[")) {
            return name.replace('/', '.');
        }
        
        if (name.startsWith("L")) {
        	name = name.substring(1);
        	if (name.endsWith(";")) {
        		name = name.substring(0, name.length() - 1);
        	}
        	return name.replace('/', '.');
        }

        String prefix = "";
        if (name.endsWith("[]")) { // todo need process multi
            prefix = "[";
            name = name.substring(0, name.length() - 2);
            if (name.equals("int")) {
                return prefix + "I";
            }
            else if (name.equals("long")) {
                return prefix + "J";
            }
            else if (name.equals("short")) {
                return prefix + "S";
            }
            else if (name.equals("float")) {
                return prefix + "F";
            }
            else if (name.equals("double")) {
                return prefix + "D";
            }
            else if (name.equals("byte")) {
                return prefix + "B";
            }
            else if (name.equals("char")) {
                return prefix + "C";
            }
            else if (name.equals("boolean")) {
                return prefix + "Z";
            }
            else {
            	return prefix + "L" + name.replace('/', '.') + ";";
            }
        }
        return name.replace('/', '.');

    }

    public void dup() {
        cv.visitInsn(DUP);
    }

    public void doReturn(ClassNode returnType) {
        if (returnType==ClassHelper.double_TYPE) {
            cv.visitInsn(DRETURN);
        } else if (returnType==ClassHelper.float_TYPE) {
            cv.visitInsn(FRETURN);
        } else if (returnType==ClassHelper.long_TYPE) {
            cv.visitInsn(LRETURN);
        } else if (
                   returnType==ClassHelper.boolean_TYPE
                || returnType==ClassHelper.char_TYPE
                || returnType==ClassHelper.byte_TYPE
                || returnType==ClassHelper.int_TYPE
                || returnType==ClassHelper.short_TYPE) 
        { 
            //byte,short,boolean,int are all IRETURN
            cv.visitInsn(IRETURN);
        } else if (returnType==ClassHelper.VOID_TYPE){
            cv.visitInsn(RETURN);
        } else {
            cv.visitInsn(ARETURN);
        }
        
    }
    
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?