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.

JvstCodeGen.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  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.bytecode.Bytecode;
  22. import javassist.bytecode.Descriptor;
  23. import javassist.compiler.ast.ASTList;
  24. import javassist.compiler.ast.ASTree;
  25. import javassist.compiler.ast.CallExpr;
  26. import javassist.compiler.ast.CastExpr;
  27. import javassist.compiler.ast.Declarator;
  28. import javassist.compiler.ast.Expr;
  29. import javassist.compiler.ast.Member;
  30. import javassist.compiler.ast.Stmnt;
  31. import javassist.compiler.ast.Symbol;
  32. /* Code generator accepting extended Java syntax for Javassist.
  33. */
  34. public class JvstCodeGen extends MemberCodeGen {
  35. String paramArrayName = null;
  36. String paramListName = null;
  37. CtClass[] paramTypeList = null;
  38. private int paramVarBase = 0; // variable index for $0 or $1.
  39. private boolean useParam0 = false; // true if $0 is used.
  40. private String param0Type = null; // JVM name
  41. public static final String sigName = "$sig";
  42. public static final String dollarTypeName = "$type";
  43. public static final String clazzName = "$class";
  44. private CtClass dollarType = null;
  45. CtClass returnType = null;
  46. String returnCastName = null;
  47. @SuppressWarnings("unused")
  48. private String returnVarName = null; // null if $_ is not used.
  49. public static final String wrapperCastName = "$w";
  50. String proceedName = null;
  51. public static final String cflowName = "$cflow";
  52. ProceedHandler procHandler = null; // null if not used.
  53. public JvstCodeGen(Bytecode b, CtClass cc, ClassPool cp) {
  54. super(b, cc, cp);
  55. setTypeChecker(new JvstTypeChecker(cc, cp, this));
  56. }
  57. /* Index of $1.
  58. */
  59. private int indexOfParam1() {
  60. return paramVarBase + (useParam0 ? 1 : 0);
  61. }
  62. /* Records a ProceedHandler obejct.
  63. *
  64. * @param name the name of the special method call.
  65. * it is usually $proceed.
  66. */
  67. public void setProceedHandler(ProceedHandler h, String name) {
  68. proceedName = name;
  69. procHandler = h;
  70. }
  71. /* If the type of the expression compiled last is void,
  72. * add ACONST_NULL and change exprType, arrayDim, className.
  73. */
  74. public void addNullIfVoid() {
  75. if (exprType == VOID) {
  76. bytecode.addOpcode(ACONST_NULL);
  77. exprType = CLASS;
  78. arrayDim = 0;
  79. className = jvmJavaLangObject;
  80. }
  81. }
  82. /* To support $args, $sig, and $type.
  83. * $args is an array of parameter list.
  84. */
  85. @Override
  86. public void atMember(Member mem) throws CompileError {
  87. String name = mem.get();
  88. if (name.equals(paramArrayName)) {
  89. compileParameterList(bytecode, paramTypeList, indexOfParam1());
  90. exprType = CLASS;
  91. arrayDim = 1;
  92. className = jvmJavaLangObject;
  93. }
  94. else if (name.equals(sigName)) {
  95. bytecode.addLdc(Descriptor.ofMethod(returnType, paramTypeList));
  96. bytecode.addInvokestatic("javassist/runtime/Desc", "getParams",
  97. "(Ljava/lang/String;)[Ljava/lang/Class;");
  98. exprType = CLASS;
  99. arrayDim = 1;
  100. className = "java/lang/Class";
  101. }
  102. else if (name.equals(dollarTypeName)) {
  103. if (dollarType == null)
  104. throw new CompileError(dollarTypeName + " is not available", mem.getLineNumber());
  105. bytecode.addLdc(Descriptor.of(dollarType));
  106. callGetType("getType");
  107. }
  108. else if (name.equals(clazzName)) {
  109. if (param0Type == null)
  110. throw new CompileError(clazzName + " is not available", mem.getLineNumber());
  111. bytecode.addLdc(param0Type);
  112. callGetType("getClazz");
  113. }
  114. else
  115. super.atMember(mem);
  116. }
  117. private void callGetType(String method) {
  118. bytecode.addInvokestatic("javassist/runtime/Desc", method,
  119. "(Ljava/lang/String;)Ljava/lang/Class;");
  120. exprType = CLASS;
  121. arrayDim = 0;
  122. className = "java/lang/Class";
  123. }
  124. @Override
  125. protected void atFieldAssign(Expr expr, int op, ASTree left,
  126. ASTree right, boolean doDup) throws CompileError
  127. {
  128. if (left instanceof Member
  129. && ((Member)left).get().equals(paramArrayName)) {
  130. if (op != '=')
  131. throw new CompileError("bad operator for " + paramArrayName, expr.getLineNumber());
  132. right.accept(this);
  133. if (arrayDim != 1 || exprType != CLASS)
  134. throw new CompileError("invalid type for " + paramArrayName, expr.getLineNumber());
  135. atAssignParamList(paramTypeList, bytecode, expr.getLineNumber());
  136. if (!doDup)
  137. bytecode.addOpcode(POP);
  138. }
  139. else
  140. super.atFieldAssign(expr, op, left, right, doDup);
  141. }
  142. protected void atAssignParamList(CtClass[] params, Bytecode code, int lineNumber)
  143. throws CompileError
  144. {
  145. if (params == null)
  146. return;
  147. int varNo = indexOfParam1();
  148. int n = params.length;
  149. for (int i = 0; i < n; ++i) {
  150. code.addOpcode(DUP);
  151. code.addIconst(i);
  152. code.addOpcode(AALOAD);
  153. compileUnwrapValue(params[i], code, lineNumber);
  154. code.addStore(varNo, params[i]);
  155. varNo += is2word(exprType, arrayDim) ? 2 : 1;
  156. }
  157. }
  158. @Override
  159. public void atCastExpr(CastExpr expr) throws CompileError {
  160. ASTList classname = expr.getClassName();
  161. if (classname != null && expr.getArrayDim() == 0) {
  162. ASTree p = classname.head();
  163. if (p instanceof Symbol && classname.tail() == null) {
  164. String typename = ((Symbol)p).get();
  165. if (typename.equals(returnCastName)) {
  166. atCastToRtype(expr);
  167. return;
  168. }
  169. else if (typename.equals(wrapperCastName)) {
  170. atCastToWrapper(expr);
  171. return;
  172. }
  173. }
  174. }
  175. super.atCastExpr(expr);
  176. }
  177. /**
  178. * Inserts a cast operator to the return type.
  179. * If the return type is void, this does nothing.
  180. */
  181. protected void atCastToRtype(CastExpr expr) throws CompileError {
  182. expr.getOprand().accept(this);
  183. if (exprType == VOID || isRefType(exprType) || arrayDim > 0)
  184. compileUnwrapValue(returnType, bytecode, expr.getLineNumber());
  185. else if (returnType instanceof CtPrimitiveType) {
  186. CtPrimitiveType pt = (CtPrimitiveType)returnType;
  187. int destType = MemberResolver.descToType(pt.getDescriptor(), expr.getLineNumber());
  188. atNumCastExpr(exprType, destType);
  189. exprType = destType;
  190. arrayDim = 0;
  191. className = null;
  192. }
  193. else
  194. throw new CompileError("invalid cast", expr.getLineNumber());
  195. }
  196. protected void atCastToWrapper(CastExpr expr) throws CompileError {
  197. expr.getOprand().accept(this);
  198. if (isRefType(exprType) || arrayDim > 0)
  199. return; // Object type. do nothing.
  200. CtClass clazz = resolver.lookupClass(exprType, arrayDim, className, expr.getLineNumber());
  201. if (clazz instanceof CtPrimitiveType) {
  202. CtPrimitiveType pt = (CtPrimitiveType)clazz;
  203. String wrapper = pt.getWrapperName();
  204. bytecode.addNew(wrapper); // new <wrapper>
  205. bytecode.addOpcode(DUP); // dup
  206. if (pt.getDataSize() > 1)
  207. bytecode.addOpcode(DUP2_X2); // dup2_x2
  208. else
  209. bytecode.addOpcode(DUP2_X1); // dup2_x1
  210. bytecode.addOpcode(POP2); // pop2
  211. bytecode.addInvokespecial(wrapper, "<init>",
  212. "(" + pt.getDescriptor() + ")V");
  213. // invokespecial
  214. exprType = CLASS;
  215. arrayDim = 0;
  216. className = jvmJavaLangObject;
  217. }
  218. }
  219. /* Delegates to a ProcHandler object if the method call is
  220. * $proceed(). It may process $cflow().
  221. */
  222. @Override
  223. public void atCallExpr(CallExpr expr) throws CompileError {
  224. ASTree method = expr.oprand1();
  225. if (method instanceof Member) {
  226. String name = ((Member)method).get();
  227. if (procHandler != null && name.equals(proceedName)) {
  228. procHandler.doit(this, bytecode, (ASTList)expr.oprand2(), expr.getLineNumber());
  229. return;
  230. }
  231. else if (name.equals(cflowName)) {
  232. atCflow((ASTList)expr.oprand2(), expr.getLineNumber());
  233. return;
  234. }
  235. }
  236. super.atCallExpr(expr);
  237. }
  238. /* To support $cflow().
  239. */
  240. protected void atCflow(ASTList cname, int lineNumber) throws CompileError {
  241. StringBuilder sbuf = new StringBuilder();
  242. if (cname == null || cname.tail() != null)
  243. throw new CompileError("bad " + cflowName, lineNumber);
  244. makeCflowName(sbuf, cname.head());
  245. String name = sbuf.toString();
  246. Object[] names = resolver.getClassPool().lookupCflow(name);
  247. if (names == null)
  248. throw new CompileError("no such " + cflowName + ": " + name, lineNumber);
  249. bytecode.addGetstatic((String)names[0], (String)names[1],
  250. "Ljavassist/runtime/Cflow;");
  251. bytecode.addInvokevirtual("javassist.runtime.Cflow",
  252. "value", "()I");
  253. exprType = INT;
  254. arrayDim = 0;
  255. className = null;
  256. }
  257. /* Syntax:
  258. *
  259. * <cflow> : $cflow '(' <cflow name> ')'
  260. * <cflow name> : <identifier> ('.' <identifier>)*
  261. */
  262. private static void makeCflowName(StringBuilder sbuf, ASTree name)
  263. throws CompileError
  264. {
  265. if (name instanceof Symbol) {
  266. sbuf.append(((Symbol)name).get());
  267. return;
  268. }
  269. else if (name instanceof Expr) {
  270. Expr expr = (Expr)name;
  271. if (expr.getOperator() == '.') {
  272. makeCflowName(sbuf, expr.oprand1());
  273. sbuf.append('.');
  274. makeCflowName(sbuf, expr.oprand2());
  275. return;
  276. }
  277. }
  278. throw new CompileError("bad " + cflowName, name.getLineNumber());
  279. }
  280. /* To support $$. ($$) is equivalent to ($1, ..., $n).
  281. * It can be used only as a parameter list of method call.
  282. */
  283. public boolean isParamListName(ASTList args) {
  284. if (paramTypeList != null
  285. && args != null && args.tail() == null) {
  286. ASTree left = args.head();
  287. return (left instanceof Member
  288. && ((Member)left).get().equals(paramListName));
  289. }
  290. return false;
  291. }
  292. /*
  293. public int getMethodArgsLength(ASTList args) {
  294. if (!isParamListName(args))
  295. return super.getMethodArgsLength(args);
  296. return paramTypeList.length;
  297. }
  298. */
  299. @Override
  300. public int getMethodArgsLength(ASTList args) {
  301. String pname = paramListName;
  302. int n = 0;
  303. while (args != null) {
  304. ASTree a = args.head();
  305. if (a instanceof Member && ((Member)a).get().equals(pname)) {
  306. if (paramTypeList != null)
  307. n += paramTypeList.length;
  308. }
  309. else
  310. ++n;
  311. args = args.tail();
  312. }
  313. return n;
  314. }
  315. @Override
  316. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  317. String[] cnames) throws CompileError {
  318. CtClass[] params = paramTypeList;
  319. String pname = paramListName;
  320. int i = 0;
  321. while (args != null) {
  322. ASTree a = args.head();
  323. if (a instanceof Member && ((Member)a).get().equals(pname)) {
  324. if (params != null) {
  325. int n = params.length;
  326. int regno = indexOfParam1();
  327. for (int k = 0; k < n; ++k) {
  328. CtClass p = params[k];
  329. regno += bytecode.addLoad(regno, p);
  330. setType(p, a.getLineNumber());
  331. types[i] = exprType;
  332. dims[i] = arrayDim;
  333. cnames[i] = className;
  334. ++i;
  335. }
  336. }
  337. }
  338. else {
  339. a.accept(this);
  340. types[i] = exprType;
  341. dims[i] = arrayDim;
  342. cnames[i] = className;
  343. ++i;
  344. }
  345. args = args.tail();
  346. }
  347. }
  348. /*
  349. public void atMethodArgs(ASTList args, int[] types, int[] dims,
  350. String[] cnames) throws CompileError {
  351. if (!isParamListName(args)) {
  352. super.atMethodArgs(args, types, dims, cnames);
  353. return;
  354. }
  355. CtClass[] params = paramTypeList;
  356. if (params == null)
  357. return;
  358. int n = params.length;
  359. int regno = indexOfParam1();
  360. for (int i = 0; i < n; ++i) {
  361. CtClass p = params[i];
  362. regno += bytecode.addLoad(regno, p);
  363. setType(p);
  364. types[i] = exprType;
  365. dims[i] = arrayDim;
  366. cnames[i] = className;
  367. }
  368. }
  369. */
  370. /* called by Javac#recordSpecialProceed().
  371. */
  372. void compileInvokeSpecial(ASTree target, int methodIndex,
  373. String descriptor, ASTList args)
  374. throws CompileError
  375. {
  376. target.accept(this);
  377. int nargs = getMethodArgsLength(args);
  378. atMethodArgs(args, new int[nargs], new int[nargs],
  379. new String[nargs]);
  380. bytecode.addInvokespecial(methodIndex, descriptor);
  381. setReturnType(descriptor, false, false, target.getLineNumber());
  382. addNullIfVoid();
  383. }
  384. /*
  385. * Makes it valid to write "return <expr>;" for a void method.
  386. */
  387. @Override
  388. protected void atReturnStmnt(Stmnt st) throws CompileError {
  389. ASTree result = st.getLeft();
  390. if (result != null && returnType == CtClass.voidType) {
  391. compileExpr(result);
  392. if (is2word(exprType, arrayDim))
  393. bytecode.addOpcode(POP2);
  394. else if (exprType != VOID)
  395. bytecode.addOpcode(POP);
  396. result = null;
  397. }
  398. atReturnStmnt2(result);
  399. }
  400. /**
  401. * Makes a cast to the return type ($r) available.
  402. * It also enables $_.
  403. *
  404. * <p>If the return type is void, ($r) does nothing.
  405. * The type of $_ is java.lang.Object.
  406. *
  407. * @param resultName null if $_ is not used.
  408. * @return -1 or the variable index assigned to $_.
  409. */
  410. public int recordReturnType(CtClass type, String castName,
  411. String resultName, SymbolTable tbl) throws CompileError
  412. {
  413. returnType = type;
  414. returnCastName = castName;
  415. returnVarName = resultName;
  416. if (resultName == null)
  417. return -1;
  418. int varNo = getMaxLocals();
  419. int locals = varNo + recordVar(type, resultName, varNo, tbl);
  420. setMaxLocals(locals);
  421. return varNo;
  422. }
  423. /**
  424. * Makes $type available.
  425. */
  426. public void recordType(CtClass t) {
  427. dollarType = t;
  428. }
  429. /**
  430. * Makes method parameters $0, $1, ..., $args, $$, and $class available.
  431. * $0 is equivalent to THIS if the method is not static. Otherwise,
  432. * if the method is static, then $0 is not available.
  433. */
  434. public int recordParams(CtClass[] params, boolean isStatic,
  435. String prefix, String paramVarName,
  436. String paramsName, SymbolTable tbl)
  437. throws CompileError
  438. {
  439. return recordParams(params, isStatic, prefix, paramVarName,
  440. paramsName, !isStatic, 0, getThisName(), tbl);
  441. }
  442. /**
  443. * Makes method parameters $0, $1, ..., $args, $$, and $class available.
  444. * $0 is available only if use0 is true. It might not be equivalent
  445. * to THIS.
  446. *
  447. * @param params the parameter types (the types of $1, $2, ..)
  448. * @param prefix it must be "$" (the first letter of $0, $1, ...)
  449. * @param paramVarName it must be "$args"
  450. * @param paramsName it must be "$$"
  451. * @param use0 true if $0 is used.
  452. * @param paramBase the register number of $0 (use0 is true)
  453. * or $1 (otherwise).
  454. * @param target the class of $0. If use0 is false, target
  455. * can be null. The value of "target" is also used
  456. * as the name of the type represented by $class.
  457. * @param isStatic true if the method in which the compiled bytecode
  458. * is embedded is static.
  459. */
  460. public int recordParams(CtClass[] params, boolean isStatic,
  461. String prefix, String paramVarName,
  462. String paramsName, boolean use0,
  463. int paramBase, String target,
  464. SymbolTable tbl)
  465. throws CompileError
  466. {
  467. int varNo;
  468. paramTypeList = params;
  469. paramArrayName = paramVarName;
  470. paramListName = paramsName;
  471. paramVarBase = paramBase;
  472. useParam0 = use0;
  473. if (target != null)
  474. param0Type = MemberResolver.jvmToJavaName(target);
  475. inStaticMethod = isStatic;
  476. varNo = paramBase;
  477. if (use0) {
  478. String varName = prefix + "0";
  479. Declarator decl
  480. = new Declarator(CLASS, MemberResolver.javaToJvmName(target),
  481. 0, varNo++, new Symbol(varName, 0), 0);
  482. tbl.append(varName, decl);
  483. }
  484. for (int i = 0; i < params.length; ++i)
  485. varNo += recordVar(params[i], prefix + (i + 1), varNo, tbl);
  486. if (getMaxLocals() < varNo)
  487. setMaxLocals(varNo);
  488. return varNo;
  489. }
  490. /**
  491. * Makes the given variable name available.
  492. *
  493. * @param type variable type
  494. * @param varName variable name
  495. */
  496. public int recordVariable(CtClass type, String varName, SymbolTable tbl)
  497. throws CompileError
  498. {
  499. if (varName == null)
  500. return -1;
  501. int varNo = getMaxLocals();
  502. int locals = varNo + recordVar(type, varName, varNo, tbl);
  503. setMaxLocals(locals);
  504. return varNo;
  505. }
  506. private int recordVar(CtClass cc, String varName, int varNo,
  507. SymbolTable tbl) throws CompileError
  508. {
  509. if (cc == CtClass.voidType) {
  510. exprType = CLASS;
  511. arrayDim = 0;
  512. className = jvmJavaLangObject;
  513. }
  514. else
  515. setType(cc, cc.getLinesCount());
  516. Declarator decl
  517. = new Declarator(exprType, className, arrayDim,
  518. varNo, new Symbol(varName, 0), 0);
  519. tbl.append(varName, decl);
  520. return is2word(exprType, arrayDim) ? 2 : 1;
  521. }
  522. /**
  523. * Makes the given variable name available.
  524. *
  525. * @param typeDesc the type descriptor of the variable
  526. * @param varName variable name
  527. * @param varNo an index into the local variable array
  528. */
  529. public void recordVariable(String typeDesc, String varName, int varNo,
  530. SymbolTable tbl) throws CompileError
  531. {
  532. char c;
  533. int dim = 0;
  534. while ((c = typeDesc.charAt(dim)) == '[')
  535. ++dim;
  536. int type = MemberResolver.descToType(c, -1);
  537. String cname = null;
  538. if (type == CLASS) {
  539. if (dim == 0)
  540. cname = typeDesc.substring(1, typeDesc.length() - 1);
  541. else
  542. cname = typeDesc.substring(dim + 1, typeDesc.length() - 1);
  543. }
  544. Declarator decl
  545. = new Declarator(type, cname, dim, varNo, new Symbol(varName, 0), 0);
  546. tbl.append(varName, decl);
  547. }
  548. /* compileParameterList() returns the stack size used
  549. * by the produced code.
  550. *
  551. * This method correctly computes the max_stack value.
  552. *
  553. * @param regno the index of the local variable in which
  554. * the first argument is received.
  555. * (0: static method, 1: regular method.)
  556. */
  557. public static int compileParameterList(Bytecode code,
  558. CtClass[] params, int regno) {
  559. if (params == null) {
  560. code.addIconst(0); // iconst_0
  561. code.addAnewarray(javaLangObject); // anewarray Object
  562. return 1;
  563. }
  564. CtClass[] args = new CtClass[1];
  565. int n = params.length;
  566. code.addIconst(n); // iconst_<n>
  567. code.addAnewarray(javaLangObject); // anewarray Object
  568. for (int i = 0; i < n; ++i) {
  569. code.addOpcode(Bytecode.DUP); // dup
  570. code.addIconst(i); // iconst_<i>
  571. if (params[i].isPrimitive()) {
  572. CtPrimitiveType pt = (CtPrimitiveType)params[i];
  573. String wrapper = pt.getWrapperName();
  574. code.addNew(wrapper); // new <wrapper>
  575. code.addOpcode(Bytecode.DUP); // dup
  576. int s = code.addLoad(regno, pt); // ?load <regno>
  577. regno += s;
  578. args[0] = pt;
  579. code.addInvokespecial(wrapper, "<init>",
  580. Descriptor.ofMethod(CtClass.voidType, args));
  581. // invokespecial
  582. }
  583. else {
  584. code.addAload(regno); // aload <regno>
  585. ++regno;
  586. }
  587. code.addOpcode(Bytecode.AASTORE); // aastore
  588. }
  589. return 8;
  590. }
  591. protected void compileUnwrapValue(CtClass type, Bytecode code, int lineNumber)
  592. throws CompileError
  593. {
  594. if (type == CtClass.voidType) {
  595. addNullIfVoid();
  596. return;
  597. }
  598. if (exprType == VOID)
  599. throw new CompileError("invalid type for " + returnCastName, lineNumber);
  600. if (type instanceof CtPrimitiveType) {
  601. CtPrimitiveType pt = (CtPrimitiveType)type;
  602. // pt is not voidType.
  603. String wrapper = pt.getWrapperName();
  604. code.addCheckcast(wrapper);
  605. code.addInvokevirtual(wrapper, pt.getGetMethodName(),
  606. pt.getGetMethodDescriptor());
  607. setType(type, lineNumber);
  608. }
  609. else {
  610. code.addCheckcast(type);
  611. setType(type, lineNumber);
  612. }
  613. }
  614. /* Sets exprType, arrayDim, and className;
  615. * If type is void, then this method does nothing.
  616. */
  617. public void setType(CtClass type, int lineNumber) throws CompileError {
  618. setType(type, 0, lineNumber);
  619. }
  620. private void setType(CtClass type, int dim, int lineNumber) throws CompileError {
  621. if (type.isPrimitive()) {
  622. CtPrimitiveType pt = (CtPrimitiveType)type;
  623. exprType = MemberResolver.descToType(pt.getDescriptor(), lineNumber);
  624. arrayDim = dim;
  625. className = null;
  626. }
  627. else if (type.isArray())
  628. try {
  629. setType(type.getComponentType(), dim + 1, lineNumber);
  630. }
  631. catch (NotFoundException e) {
  632. throw new CompileError("undefined type: " + type.getName(), lineNumber);
  633. }
  634. else {
  635. exprType = CLASS;
  636. arrayDim = dim;
  637. className = MemberResolver.javaToJvmName(type.getName());
  638. }
  639. }
  640. /* Performs implicit coercion from exprType to type.
  641. */
  642. public void doNumCast(CtClass type) throws CompileError {
  643. if (arrayDim == 0 && !isRefType(exprType))
  644. if (type instanceof CtPrimitiveType) {
  645. CtPrimitiveType pt = (CtPrimitiveType)type;
  646. atNumCastExpr(exprType,
  647. MemberResolver.descToType(pt.getDescriptor(), type.getLinesCount() - 1));
  648. }
  649. else
  650. throw new CompileError("type mismatch", type.getLinesCount() - 1);
  651. }
  652. }