You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

JvstTypeChecker.java 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later,
  9. * or the Apache License Version 2.0.
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. */
  16. package javassist.compiler;
  17. import javassist.ClassPool;
  18. import javassist.CtClass;
  19. import javassist.CtPrimitiveType;
  20. import javassist.NotFoundException;
  21. import javassist.compiler.ast.ASTList;
  22. import javassist.compiler.ast.ASTree;
  23. import javassist.compiler.ast.CallExpr;
  24. import javassist.compiler.ast.CastExpr;
  25. import javassist.compiler.ast.Expr;
  26. import javassist.compiler.ast.Member;
  27. import javassist.compiler.ast.Symbol;
  28. /* Type checker accepting extended Java syntax for Javassist.
  29. */
  30. public class JvstTypeChecker extends TypeChecker {
  31. private JvstCodeGen codeGen;
  32. public JvstTypeChecker(CtClass cc, ClassPool cp, JvstCodeGen gen) {
  33. super(cc, cp);
  34. codeGen = gen;
  35. }
  36. /* If the type of the expression compiled last is void,
  37. * add ACONST_NULL and change exprType, arrayDim, className.
  38. */
  39. public void addNullIfVoid() {
  40. if (exprType == VOID) {
  41. exprType = CLASS;
  42. arrayDim = 0;
  43. className = jvmJavaLangObject;
  44. }
  45. }
  46. /* To support $args, $sig, and $type.
  47. * $args is an array of parameter list.
  48. */
  49. @Override
  50. public void atMember(Member mem) throws CompileError {
  51. String name = mem.get();
  52. if (name.equals(codeGen.paramArrayName)) {
  53. exprType = CLASS;
  54. arrayDim = 1;
  55. className = jvmJavaLangObject;
  56. }
  57. else if (name.equals(JvstCodeGen.sigName)) {
  58. exprType = CLASS;
  59. arrayDim = 1;
  60. className = "java/lang/Class";
  61. }
  62. else if (name.equals(JvstCodeGen.dollarTypeName)
  63. || name.equals(JvstCodeGen.clazzName)) {
  64. exprType = CLASS;
  65. arrayDim = 0;
  66. className = "java/lang/Class";
  67. }
  68. else
  69. super.atMember(mem);
  70. }
  71. @Override
  72. protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
  73. throws CompileError
  74. {
  75. if (left instanceof Member
  76. && ((Member)left).get().equals(codeGen.paramArrayName)) {
  77. right.accept(this);
  78. CtClass[] params = codeGen.paramTypeList;
  79. if (params == null)
  80. return;
  81. int n = params.length;
  82. for (int i = 0; i < n; ++i)
  83. compileUnwrapValue(params[i], expr.getLineNumber());
  84. }
  85. else
  86. super.atFieldAssign(expr, op, left, right);
  87. }
  88. @Override
  89. public void atCastExpr(CastExpr expr) throws CompileError {
  90. ASTList classname = expr.getClassName();
  91. if (classname != null && expr.getArrayDim() == 0) {
  92. ASTree p = classname.head();
  93. if (p instanceof Symbol && classname.tail() == null) {
  94. String typename = ((Symbol)p).get();
  95. if (typename.equals(codeGen.returnCastName)) {
  96. atCastToRtype(expr);
  97. return;
  98. }
  99. else if (typename.equals(JvstCodeGen.wrapperCastName)) {
  100. atCastToWrapper(expr);
  101. return;
  102. }
  103. }
  104. }
  105. super.atCastExpr(expr);
  106. }
  107. /**
  108. * Inserts a cast operator to the return type.
  109. * If the return type is void, this does nothing.
  110. */
  111. protected void atCastToRtype(CastExpr expr) throws CompileError {
  112. CtClass returnType = codeGen.returnType;
  113. expr.getOprand().accept(this);
  114. if (exprType == VOID || CodeGen.isRefType(exprType) || arrayDim > 0)
  115. compileUnwrapValue(returnType, expr.getLineNumber());
  116. else if (returnType instanceof CtPrimitiveType) {
  117. CtPrimitiveType pt = (CtPrimitiveType)returnType;
  118. int destType = MemberResolver.descToType(pt.getDescriptor());
  119. exprType = destType;
  120. arrayDim = 0;
  121. className = null;
  122. }
  123. }
  124. protected void atCastToWrapper(CastExpr expr) throws CompileError {
  125. expr.getOprand().accept(this);
  126. if (CodeGen.isRefType(exprType) || arrayDim > 0)
  127. return; // Object type. do nothing.
  128. CtClass clazz = resolver.lookupClass(exprType, arrayDim, className);
  129. if (clazz instanceof CtPrimitiveType) {
  130. exprType = CLASS;
  131. arrayDim = 0;
  132. className = jvmJavaLangObject;
  133. }
  134. }
  135. /* Delegates to a ProcHandler object if the method call is
  136. * $proceed(). It may process $cflow().
  137. */
  138. @Override
  139. public void atCallExpr(CallExpr expr) throws CompileError {
  140. ASTree method = expr.oprand1();
  141. if (method instanceof Member) {
  142. String name = ((Member)method).get();
  143. if (codeGen.procHandler != null
  144. && name.equals(codeGen.proceedName)) {
  145. codeGen.procHandler.setReturnType(this,
  146. (ASTList)expr.oprand2());
  147. return;
  148. }
  149. else if (name.equals(JvstCodeGen.cflowName)) {
  150. atCflow((ASTList)expr.oprand2());
  151. return;
  152. }
  153. }
  154. super.atCallExpr(expr);
  155. }
  156. /* To support $cflow().
  157. */
  158. protected void atCflow(ASTList cname) throws CompileError {
  159. exprType = INT;
  160. arrayDim = 0;
  161. className = null;
  162. }
  163. /* To support $$. ($$) is equivalent to ($1, ..., $n).
  164. * It can be used only as a parameter list of method call.
  165. */
  166. public boolean isParamListName(ASTList args) {
  167. if (codeGen.paramTypeList != null
  168. && args != null && args.tail() == null) {
  169. ASTree left = args.head();
  170. return (left instanceof Member
  171. && ((Member)left).get().equals(codeGen.paramListName));
  172. }
  173. return false;
  174. }
  175. @Override
  176. public int getMethodArgsLength(ASTList args) {
  177. String pname = codeGen.paramListName;
  178. int n = 0;
  179. while (args != null) {
  180. ASTree a = args.head();
  181. if (a instanceof Member && ((Member)a).get().equals(pname)) {
  182. if (codeGen.paramTypeList != null)
  183. n += codeGen.paramTypeList.length;
  184. }
  185. else
  186. ++n;
  187. args = args.tail();
  188. }
  189. return n;
  190. }
  191. @Override
  192. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  193. String[] cnames) throws CompileError {
  194. CtClass[] params = codeGen.paramTypeList;
  195. String pname = codeGen.paramListName;
  196. int i = 0;
  197. while (args != null) {
  198. ASTree a = args.head();
  199. if (a instanceof Member && ((Member)a).get().equals(pname)) {
  200. if (params != null) {
  201. int n = params.length;
  202. for (int k = 0; k < n; ++k) {
  203. CtClass p = params[k];
  204. setType(p);
  205. types[i] = exprType;
  206. dims[i] = arrayDim;
  207. cnames[i] = className;
  208. ++i;
  209. }
  210. }
  211. }
  212. else {
  213. a.accept(this);
  214. types[i] = exprType;
  215. dims[i] = arrayDim;
  216. cnames[i] = className;
  217. ++i;
  218. }
  219. args = args.tail();
  220. }
  221. }
  222. /* called by Javac#recordSpecialProceed().
  223. */
  224. void compileInvokeSpecial(ASTree target, String classname,
  225. String methodname, String descriptor,
  226. ASTList args)
  227. throws CompileError
  228. {
  229. target.accept(this);
  230. int nargs = getMethodArgsLength(args);
  231. atMethodArgs(args, new int[nargs], new int[nargs],
  232. new String[nargs]);
  233. setReturnType(descriptor);
  234. addNullIfVoid();
  235. }
  236. protected void compileUnwrapValue(CtClass type, int lineNumber) throws CompileError
  237. {
  238. if (type == CtClass.voidType)
  239. addNullIfVoid();
  240. else
  241. setType(type);
  242. }
  243. /* Sets exprType, arrayDim, and className;
  244. * If type is void, then this method does nothing.
  245. */
  246. public void setType(CtClass type) throws CompileError {
  247. setType(type, 0);
  248. }
  249. private void setType(CtClass type, int dim) throws CompileError {
  250. if (type.isPrimitive()) {
  251. CtPrimitiveType pt = (CtPrimitiveType)type;
  252. exprType = MemberResolver.descToType(pt.getDescriptor());
  253. arrayDim = dim;
  254. className = null;
  255. }
  256. else if (type.isArray())
  257. try {
  258. setType(type.getComponentType(), dim + 1);
  259. }
  260. catch (NotFoundException e) {
  261. throw new CompileError("undefined type: " + type.getName());
  262. }
  263. else {
  264. exprType = CLASS;
  265. arrayDim = dim;
  266. className = MemberResolver.javaToJvmName(type.getName());
  267. }
  268. }
  269. }