📄 jvstcodegen.java
字号:
/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved. * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. Alternatively, the contents of this file may be used under * the terms of the GNU Lesser General Public License Version 2.1 or later. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. */package javassist.compiler;import javassist.*;import javassist.bytecode.*;import javassist.compiler.ast.*;/* Code generator accepting extended Java syntax for Javassist. */public class JvstCodeGen extends MemberCodeGen { String paramArrayName = null; String paramListName = null; CtClass[] paramTypeList = null; private int paramVarBase = 0; // variable index for $0 or $1. private boolean useParam0 = false; // true if $0 is used. private String param0Type = null; // JVM name public static final String sigName = "$sig"; public static final String dollarTypeName = "$type"; public static final String clazzName = "$class"; private CtClass dollarType = null; CtClass returnType = null; String returnCastName = null; private String returnVarName = null; // null if $_ is not used. public static final String wrapperCastName = "$w"; String proceedName = null; public static final String cflowName = "$cflow"; ProceedHandler procHandler = null; // null if not used. public JvstCodeGen(Bytecode b, CtClass cc, ClassPool cp) { super(b, cc, cp); setTypeChecker(new JvstTypeChecker(cc, cp, this)); } /* Index of $1. */ private int indexOfParam1() { return paramVarBase + (useParam0 ? 1 : 0); } /* Records a ProceedHandler obejct. * * @param name the name of the special method call. * it is usually $proceed. */ public void setProceedHandler(ProceedHandler h, String name) { proceedName = name; procHandler = h; } /* If the type of the expression compiled last is void, * add ACONST_NULL and change exprType, arrayDim, className. */ public void addNullIfVoid() { if (exprType == VOID) { bytecode.addOpcode(ACONST_NULL); exprType = CLASS; arrayDim = 0; className = jvmJavaLangObject; } } /* To support $args, $sig, and $type. * $args is an array of parameter list. */ public void atMember(Member mem) throws CompileError { String name = mem.get(); if (name.equals(paramArrayName)) { compileParameterList(bytecode, paramTypeList, indexOfParam1()); exprType = CLASS; arrayDim = 1; className = jvmJavaLangObject; } else if (name.equals(sigName)) { bytecode.addLdc(Descriptor.ofMethod(returnType, paramTypeList)); bytecode.addInvokestatic("javassist/runtime/Desc", "getParams", "(Ljava/lang/String;)[Ljava/lang/Class;"); exprType = CLASS; arrayDim = 1; className = "java/lang/Class"; } else if (name.equals(dollarTypeName)) { if (dollarType == null) throw new CompileError(dollarType + " is not available"); bytecode.addLdc(Descriptor.of(dollarType)); callGetType("getType"); } else if (name.equals(clazzName)) { if (param0Type == null) throw new CompileError(clazzName + " is not available"); bytecode.addLdc(param0Type); callGetType("getClazz"); } else super.atMember(mem); } private void callGetType(String method) { bytecode.addInvokestatic("javassist/runtime/Desc", method, "(Ljava/lang/String;)Ljava/lang/Class;"); exprType = CLASS; arrayDim = 0; className = "java/lang/Class"; } protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right, boolean doDup) throws CompileError { if (left instanceof Member && ((Member)left).get().equals(paramArrayName)) { if (op != '=') throw new CompileError("bad operator for " + paramArrayName); right.accept(this); if (arrayDim != 1 || exprType != CLASS) throw new CompileError("invalid type for " + paramArrayName); atAssignParamList(paramTypeList, bytecode); if (!doDup) bytecode.addOpcode(POP); } else super.atFieldAssign(expr, op, left, right, doDup); } protected void atAssignParamList(CtClass[] params, Bytecode code) throws CompileError { if (params == null) return; int varNo = indexOfParam1(); int n = params.length; for (int i = 0; i < n; ++i) { code.addOpcode(DUP); code.addIconst(i); code.addOpcode(AALOAD); compileUnwrapValue(params[i], code); code.addStore(varNo, params[i]); varNo += is2word(exprType, arrayDim) ? 2 : 1; } } public void atCastExpr(CastExpr expr) throws CompileError { ASTList classname = expr.getClassName(); if (classname != null && expr.getArrayDim() == 0) { ASTree p = classname.head(); if (p instanceof Symbol && classname.tail() == null) { String typename = ((Symbol)p).get(); if (typename.equals(returnCastName)) { atCastToRtype(expr); return; } else if (typename.equals(wrapperCastName)) { atCastToWrapper(expr); return; } } } super.atCastExpr(expr); } /** * Inserts a cast operator to the return type. * If the return type is void, this does nothing. */ protected void atCastToRtype(CastExpr expr) throws CompileError { expr.getOprand().accept(this); if (exprType == VOID || isRefType(exprType) || arrayDim > 0) compileUnwrapValue(returnType, bytecode); else if (returnType instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)returnType; int destType = MemberResolver.descToType(pt.getDescriptor()); atNumCastExpr(exprType, destType); exprType = destType; arrayDim = 0; className = null; } else throw new CompileError("invalid cast"); } protected void atCastToWrapper(CastExpr expr) throws CompileError { expr.getOprand().accept(this); if (isRefType(exprType) || arrayDim > 0) return; // Object type. do nothing. CtClass clazz = resolver.lookupClass(exprType, arrayDim, className); if (clazz instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)clazz; String wrapper = pt.getWrapperName(); bytecode.addNew(wrapper); // new <wrapper> bytecode.addOpcode(DUP); // dup if (pt.getDataSize() > 1) bytecode.addOpcode(DUP2_X2); // dup2_x2 else bytecode.addOpcode(DUP2_X1); // dup2_x1 bytecode.addOpcode(POP2); // pop2 bytecode.addInvokespecial(wrapper, "<init>", "(" + pt.getDescriptor() + ")V"); // invokespecial exprType = CLASS; arrayDim = 0; className = jvmJavaLangObject; } } /* Delegates to a ProcHandler object if the method call is * $proceed(). It may process $cflow(). */ public void atCallExpr(CallExpr expr) throws CompileError { ASTree method = expr.oprand1(); if (method instanceof Member) { String name = ((Member)method).get(); if (procHandler != null && name.equals(proceedName)) { procHandler.doit(this, bytecode, (ASTList)expr.oprand2()); return; } else if (name.equals(cflowName)) { atCflow((ASTList)expr.oprand2()); return; } } super.atCallExpr(expr); } /* To support $cflow(). */ protected void atCflow(ASTList cname) throws CompileError { StringBuffer sbuf = new StringBuffer(); if (cname == null || cname.tail() != null) throw new CompileError("bad " + cflowName); makeCflowName(sbuf, cname.head()); String name = sbuf.toString(); Object[] names = resolver.getClassPool().lookupCflow(name); if (names == null) throw new CompileError("no such a " + cflowName + ": " + name); bytecode.addGetstatic((String)names[0], (String)names[1], "Ljavassist/runtime/Cflow;"); bytecode.addInvokevirtual("javassist.runtime.Cflow", "value", "()I"); exprType = INT; arrayDim = 0; className = null; } /* Syntax: * * <cflow> : $cflow '(' <cflow name> ')' * <cflow name> : <identifier> ('.' <identifier>)* */ private static void makeCflowName(StringBuffer sbuf, ASTree name) throws CompileError { if (name instanceof Symbol) { sbuf.append(((Symbol)name).get()); return; } else if (name instanceof Expr) { Expr expr = (Expr)name; if (expr.getOperator() == '.') { makeCflowName(sbuf, expr.oprand1()); sbuf.append('.'); makeCflowName(sbuf, expr.oprand2()); return; } } throw new CompileError("bad " + cflowName); } /* To support $$. ($$) is equivalent to ($1, ..., $n). * It can be used only as a parameter list of method call. */ public boolean isParamListName(ASTList args) { if (paramTypeList != null && args != null && args.tail() == null) { ASTree left = args.head(); return (left instanceof Member && ((Member)left).get().equals(paramListName)); } else return false; } /* public int getMethodArgsLength(ASTList args) { if (!isParamListName(args)) return super.getMethodArgsLength(args); return paramTypeList.length; } */ public int getMethodArgsLength(ASTList args) { String pname = paramListName; int n = 0; while (args != null) { ASTree a = args.head(); if (a instanceof Member && ((Member)a).get().equals(pname)) { if (paramTypeList != null) n += paramTypeList.length; } else ++n; args = args.tail(); } return n; } public void atMethodArgs(ASTList args, int[] types, int[] dims, String[] cnames) throws CompileError { CtClass[] params = paramTypeList; String pname = paramListName; int i = 0; while (args != null) { ASTree a = args.head(); if (a instanceof Member && ((Member)a).get().equals(pname)) { if (params != null) { int n = params.length; int regno = indexOfParam1(); for (int k = 0; k < n; ++k) { CtClass p = params[k]; regno += bytecode.addLoad(regno, p); setType(p); types[i] = exprType; dims[i] = arrayDim; cnames[i] = className; ++i; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -