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.

Javac.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2003 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. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.compiler;
  16. import javassist.CtClass;
  17. import javassist.CtPrimitiveType;
  18. import javassist.CtMember;
  19. import javassist.CtField;
  20. import javassist.CtBehavior;
  21. import javassist.CtMethod;
  22. import javassist.CtConstructor;
  23. import javassist.CannotCompileException;
  24. import javassist.ClassPool;
  25. import javassist.Modifier;
  26. import javassist.bytecode.Bytecode;
  27. import javassist.bytecode.Opcode;
  28. import javassist.NotFoundException;
  29. import javassist.compiler.ast.*;
  30. public class Javac {
  31. JvstCodeGen gen;
  32. SymbolTable stable;
  33. private Bytecode bytecode;
  34. public static final String param0Name = "$0";
  35. public static final String resultVarName = "$_";
  36. public static final String proceedName = "$proceed";
  37. /**
  38. * Constructs a compiler.
  39. *
  40. * @param thisClass the class that a compiled method/field
  41. * belongs to.
  42. */
  43. public Javac(CtClass thisClass) {
  44. this(new Bytecode(thisClass.getClassFile2().getConstPool(), 0, 0),
  45. thisClass);
  46. }
  47. /**
  48. * Constructs a compiler.
  49. * The produced bytecode is stored in the <code>Bytecode</code> object
  50. * specified by <code>b</code>.
  51. *
  52. * @param thisClass the class that a compiled method/field
  53. * belongs to.
  54. */
  55. public Javac(Bytecode b, CtClass thisClass) {
  56. gen = new JvstCodeGen(b, thisClass, thisClass.getClassPool());
  57. stable = new SymbolTable();
  58. bytecode = b;
  59. }
  60. /**
  61. * Returns the produced bytecode.
  62. */
  63. public Bytecode getBytecode() { return bytecode; }
  64. /**
  65. * Compiles a method, constructor, or field declaration
  66. * to a class.
  67. * A field declaration can declare only one field.
  68. *
  69. * <p>In a method or constructor body, $0, $1, ... and $_
  70. * are not available.
  71. *
  72. * @return a <code>CtMethod</code>, <code>CtConstructor</code>,
  73. * or <code>CtField</code> object.
  74. * @see #recordProceed(String,String)
  75. */
  76. public CtMember compile(String src) throws CompileError {
  77. Parser p = new Parser(new Lex(src));
  78. ASTList mem = p.parseMember1(stable);
  79. try {
  80. if (mem instanceof FieldDecl)
  81. return compileField((FieldDecl)mem);
  82. else
  83. return compileMethod(p, (MethodDecl)mem);
  84. }
  85. catch (CannotCompileException e) {
  86. throw new CompileError(e.getMessage());
  87. }
  88. }
  89. public static class CtFieldWithInit extends CtField {
  90. private ASTree init;
  91. CtFieldWithInit(CtClass type, String name, CtClass declaring)
  92. throws CannotCompileException
  93. {
  94. super(type, name, declaring);
  95. init = null;
  96. }
  97. protected void setInit(ASTree i) { init = i; }
  98. protected ASTree getInitAST() {
  99. return init;
  100. }
  101. }
  102. private CtField compileField(FieldDecl fd)
  103. throws CompileError, CannotCompileException
  104. {
  105. CtFieldWithInit f;
  106. Declarator d = fd.getDeclarator();
  107. f = new CtFieldWithInit(gen.lookupClass(d), d.getVariable().get(),
  108. gen.getThisClass());
  109. f.setModifiers(gen.getModifiers(fd.getModifiers()));
  110. if (fd.getInit() != null)
  111. f.setInit(fd.getInit());
  112. return f;
  113. }
  114. private CtMember compileMethod(Parser p, MethodDecl md)
  115. throws CompileError
  116. {
  117. int mod = gen.getModifiers(md.getModifiers());
  118. CtClass[] plist = gen.makeParamList(md);
  119. CtClass[] tlist = gen.makeThrowsList(md);
  120. recordParams(plist, Modifier.isStatic(mod));
  121. md = p.parseMethod2(stable, md);
  122. try {
  123. if (md.isConstructor()) {
  124. CtConstructor cons = new CtConstructor(plist,
  125. gen.getThisClass());
  126. cons.setModifiers(mod);
  127. md.accept(gen);
  128. cons.getMethodInfo().setCodeAttribute(
  129. bytecode.toCodeAttribute());
  130. cons.setExceptionTypes(tlist);
  131. return cons;
  132. }
  133. else {
  134. Declarator r = md.getReturn();
  135. CtClass rtype = gen.lookupClass(r);
  136. recordReturnType(rtype, false);
  137. CtMethod method = new CtMethod(rtype, r.getVariable().get(),
  138. plist, gen.getThisClass());
  139. method.setModifiers(mod);
  140. gen.setThisMethod(method);
  141. md.accept(gen);
  142. if (md.getBody() != null)
  143. method.getMethodInfo().setCodeAttribute(
  144. bytecode.toCodeAttribute());
  145. else
  146. method.setModifiers(mod | Modifier.ABSTRACT);
  147. method.setExceptionTypes(tlist);
  148. return method;
  149. }
  150. }
  151. catch (NotFoundException e) {
  152. throw new CompileError(e.toString());
  153. }
  154. }
  155. /**
  156. * Compiles a method (or constructor) body.
  157. *
  158. * @src a single statement or a block.
  159. * If null, this method produces a body returning zero or null.
  160. */
  161. public Bytecode compileBody(CtBehavior method, String src)
  162. throws CompileError
  163. {
  164. try {
  165. int mod = method.getModifiers();
  166. recordParams(method.getParameterTypes(), Modifier.isStatic(mod));
  167. CtClass rtype;
  168. if (method instanceof CtMethod) {
  169. gen.setThisMethod((CtMethod)method);
  170. rtype = ((CtMethod)method).getReturnType();
  171. }
  172. else
  173. rtype = CtClass.voidType;
  174. recordReturnType(rtype, false);
  175. boolean isVoid = rtype == CtClass.voidType;
  176. if (src == null)
  177. makeDefaultBody(bytecode, rtype);
  178. else {
  179. Parser p = new Parser(new Lex(src));
  180. SymbolTable stb = new SymbolTable(stable);
  181. Stmnt s = p.parseStatement(stb);
  182. gen.atMethodBody(s, method instanceof CtConstructor, isVoid);
  183. }
  184. return bytecode;
  185. }
  186. catch (NotFoundException e) {
  187. throw new CompileError(e.toString());
  188. }
  189. }
  190. private static void makeDefaultBody(Bytecode b, CtClass type) {
  191. int op;
  192. int value;
  193. if (type instanceof CtPrimitiveType) {
  194. CtPrimitiveType pt = (CtPrimitiveType)type;
  195. op = pt.getReturnOp();
  196. if (op == Opcode.DRETURN)
  197. value = Opcode.DCONST_0;
  198. else if (op == Opcode.FRETURN)
  199. value = Opcode.FCONST_0;
  200. else if (op == Opcode.LRETURN)
  201. value = Opcode.LCONST_0;
  202. else if (op == Opcode.RETURN)
  203. value = Opcode.NOP;
  204. else
  205. value = Opcode.ICONST_0;
  206. }
  207. else {
  208. op = Opcode.ARETURN;
  209. value = Opcode.ACONST_NULL;
  210. }
  211. if (value != Opcode.NOP)
  212. b.addOpcode(value);
  213. b.addOpcode(op);
  214. }
  215. /**
  216. * Makes variables $0 (this), $1, $2, ..., and $args represent method
  217. * parameters. $args represents an array of all the parameters.
  218. * It also makes $$ available as a parameter list of method call.
  219. *
  220. * <p>This must be called before calling <code>compileStmnt()</code> and
  221. * <code>compileExpr()</code>. The correct value of
  222. * <code>isStatic</code> must be recorded before compilation.
  223. */
  224. public void recordParams(CtClass[] params, boolean isStatic)
  225. throws CompileError
  226. {
  227. gen.recordParams(params, isStatic, "$", "$args", "$$", stable);
  228. }
  229. /**
  230. * Makes variables $0, $1, $2, ..., and $args represent method
  231. * parameters. $args represents an array of all the parameters.
  232. * It also makes $$ available as a parameter list of method call.
  233. * $0 can represent a local variable other than THIS (variable 0).
  234. *
  235. * <p>This must be called before calling <code>compileStmnt()</code> and
  236. * <code>compileExpr()</code>. The correct value of
  237. * <code>isStatic</code> must be recorded before compilation.
  238. *
  239. * @paaram use0 true if $0 is used.
  240. * @param varNo the register number of $0 (use0 is true)
  241. * or $1 (otherwise).
  242. * @param target the type of $0 (it can be null if use0 is false).
  243. * @param isStatic true if the method in which the compiled bytecode
  244. * is embedded is static.
  245. */
  246. public void recordParams(String target, CtClass[] params,
  247. boolean use0, int varNo, boolean isStatic)
  248. throws CompileError
  249. {
  250. gen.recordParams(params, isStatic, "$", "$args", "$$",
  251. use0, varNo, target, stable);
  252. }
  253. /**
  254. * Prepares to use cast $r, $w, $_, and $type.
  255. * It also enables to write a return statement with a return value
  256. * for void method.
  257. *
  258. * <p>If the return type is void, ($r) does nothing.
  259. * The type of $_ is java.lang.Object.
  260. *
  261. * @param useResultVar true if $_ is used.
  262. * @return -1 or the variable index assigned to $_.
  263. */
  264. public int recordReturnType(CtClass type, boolean useResultVar)
  265. throws CompileError
  266. {
  267. gen.recordType(type);
  268. return gen.recordReturnType(type, "$r",
  269. (useResultVar ? resultVarName : null), stable);
  270. }
  271. /**
  272. * Prepares to use $type. Note that recordReturnType() overwrites
  273. * the value of $type.
  274. */
  275. public void recordType(CtClass t) {
  276. gen.recordType(t);
  277. }
  278. /**
  279. * Makes the given variable available.
  280. *
  281. * @param type variable type
  282. * @param name variable name
  283. */
  284. public int recordVariable(CtClass type, String name)
  285. throws CompileError
  286. {
  287. return gen.recordVariable(type, name, stable);
  288. }
  289. /**
  290. * Prepares to use $proceed().
  291. * If the return type of $proceed() is void, null is pushed on the
  292. * stack.
  293. *
  294. * @param target an expression specifying the target object.
  295. * if null, "this" is the target.
  296. * @param method the method name.
  297. */
  298. public void recordProceed(String target, String method)
  299. throws CompileError
  300. {
  301. Parser p = new Parser(new Lex(target));
  302. final ASTree texpr = p.parseExpression(stable);
  303. final String m = method;
  304. ProceedHandler h = new ProceedHandler() {
  305. public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
  306. throws CompileError
  307. {
  308. ASTree expr = new Member(m);
  309. if (texpr != null)
  310. expr = Expr.make('.', texpr, expr);
  311. expr = Expr.make(TokenId.CALL, expr, args);
  312. expr.accept(gen);
  313. gen.addNullIfVoid();
  314. }
  315. };
  316. gen.setProceedHandler(h, proceedName);
  317. }
  318. /**
  319. * Prepares to use $proceed().
  320. */
  321. public void recordProceed(ProceedHandler h) {
  322. gen.setProceedHandler(h, proceedName);
  323. }
  324. /**
  325. * Compiles a statement (or a block).
  326. * <code>recordParams()</code> must be called before invoking
  327. * this method.
  328. *
  329. * <p>Local variables that are not declared
  330. * in the compiled source text are not accessible within that
  331. * source text. Fields and method parameters
  332. * ($0, $1, ..) are available.
  333. */
  334. public void compileStmnt(String src) throws CompileError {
  335. Parser p = new Parser(new Lex(src));
  336. SymbolTable stb = new SymbolTable(stable);
  337. // while (p.hasMore()) {
  338. Stmnt s = p.parseStatement(stb);
  339. if (s != null)
  340. s.accept(gen);
  341. // }
  342. }
  343. /**
  344. * Compiles an exression. <code>recordParams()</code> must be
  345. * called before invoking this method.
  346. *
  347. * <p>Local variables are not accessible
  348. * within the compiled source text. Fields and method parameters
  349. * ($0, $1, ..) are available if <code>recordParams()</code>
  350. * have been invoked.
  351. */
  352. public void compileExpr(String src) throws CompileError {
  353. Parser p = new Parser(new Lex(src));
  354. ASTree e = p.parseExpression(stable);
  355. compileExpr(e);
  356. }
  357. /**
  358. * Compiles an exression. <code>recordParams()</code> must be
  359. * called before invoking this method.
  360. *
  361. * <p>Local variables are not accessible
  362. * within the compiled source text. Fields and method parameters
  363. * ($0, $1, ..) are available if <code>recordParams()</code>
  364. * have been invoked.
  365. */
  366. public void compileExpr(ASTree e) throws CompileError {
  367. if (e != null)
  368. e.accept(gen);
  369. }
  370. }