您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Javac.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2004 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.Modifier;
  25. import javassist.bytecode.Bytecode;
  26. import javassist.bytecode.CodeAttribute;
  27. import javassist.bytecode.LocalVariableAttribute;
  28. import javassist.bytecode.Opcode;
  29. import javassist.NotFoundException;
  30. import javassist.compiler.ast.*;
  31. public class Javac {
  32. JvstCodeGen gen;
  33. SymbolTable stable;
  34. private Bytecode bytecode;
  35. public static final String param0Name = "$0";
  36. public static final String resultVarName = "$_";
  37. public static final String proceedName = "$proceed";
  38. /**
  39. * Constructs a compiler.
  40. *
  41. * @param thisClass the class that a compiled method/field
  42. * belongs to.
  43. */
  44. public Javac(CtClass thisClass) {
  45. this(new Bytecode(thisClass.getClassFile2().getConstPool(), 0, 0),
  46. thisClass);
  47. }
  48. /**
  49. * Constructs a compiler.
  50. * The produced bytecode is stored in the <code>Bytecode</code> object
  51. * specified by <code>b</code>.
  52. *
  53. * @param thisClass the class that a compiled method/field
  54. * belongs to.
  55. */
  56. public Javac(Bytecode b, CtClass thisClass) {
  57. gen = new JvstCodeGen(b, thisClass, thisClass.getClassPool());
  58. stable = new SymbolTable();
  59. bytecode = b;
  60. }
  61. /**
  62. * Returns the produced bytecode.
  63. */
  64. public Bytecode getBytecode() { return bytecode; }
  65. /**
  66. * Compiles a method, constructor, or field declaration
  67. * to a class.
  68. * A field declaration can declare only one field.
  69. *
  70. * <p>In a method or constructor body, $0, $1, ... and $_
  71. * are not available.
  72. *
  73. * @return a <code>CtMethod</code>, <code>CtConstructor</code>,
  74. * or <code>CtField</code> object.
  75. * @see #recordProceed(String,String)
  76. */
  77. public CtMember compile(String src) throws CompileError {
  78. Parser p = new Parser(new Lex(src));
  79. ASTList mem = p.parseMember1(stable);
  80. try {
  81. if (mem instanceof FieldDecl)
  82. return compileField((FieldDecl)mem);
  83. else
  84. return compileMethod(p, (MethodDecl)mem);
  85. }
  86. catch (CannotCompileException e) {
  87. throw new CompileError(e.getMessage());
  88. }
  89. }
  90. public static class CtFieldWithInit extends CtField {
  91. private ASTree init;
  92. CtFieldWithInit(CtClass type, String name, CtClass declaring)
  93. throws CannotCompileException
  94. {
  95. super(type, name, declaring);
  96. init = null;
  97. }
  98. protected void setInit(ASTree i) { init = i; }
  99. protected ASTree getInitAST() {
  100. return init;
  101. }
  102. }
  103. private CtField compileField(FieldDecl fd)
  104. throws CompileError, CannotCompileException
  105. {
  106. CtFieldWithInit f;
  107. Declarator d = fd.getDeclarator();
  108. f = new CtFieldWithInit(gen.resolver.lookupClass(d),
  109. d.getVariable().get(), gen.getThisClass());
  110. f.setModifiers(MemberResolver.getModifiers(fd.getModifiers()));
  111. if (fd.getInit() != null)
  112. f.setInit(fd.getInit());
  113. return f;
  114. }
  115. private CtMember compileMethod(Parser p, MethodDecl md)
  116. throws CompileError
  117. {
  118. int mod = MemberResolver.getModifiers(md.getModifiers());
  119. CtClass[] plist = gen.makeParamList(md);
  120. CtClass[] tlist = gen.makeThrowsList(md);
  121. recordParams(plist, Modifier.isStatic(mod));
  122. md = p.parseMethod2(stable, md);
  123. try {
  124. if (md.isConstructor()) {
  125. CtConstructor cons = new CtConstructor(plist,
  126. gen.getThisClass());
  127. cons.setModifiers(mod);
  128. md.accept(gen);
  129. cons.getMethodInfo().setCodeAttribute(
  130. bytecode.toCodeAttribute());
  131. cons.setExceptionTypes(tlist);
  132. return cons;
  133. }
  134. else {
  135. Declarator r = md.getReturn();
  136. CtClass rtype = gen.resolver.lookupClass(r);
  137. recordReturnType(rtype, false);
  138. CtMethod method = new CtMethod(rtype, r.getVariable().get(),
  139. plist, gen.getThisClass());
  140. method.setModifiers(mod);
  141. gen.setThisMethod(method);
  142. md.accept(gen);
  143. if (md.getBody() != null)
  144. method.getMethodInfo().setCodeAttribute(
  145. bytecode.toCodeAttribute());
  146. else
  147. method.setModifiers(mod | Modifier.ABSTRACT);
  148. method.setExceptionTypes(tlist);
  149. return method;
  150. }
  151. }
  152. catch (NotFoundException e) {
  153. throw new CompileError(e.toString());
  154. }
  155. }
  156. /**
  157. * Compiles a method (or constructor) body.
  158. *
  159. * @src a single statement or a block.
  160. * If null, this method produces a body returning zero or null.
  161. */
  162. public Bytecode compileBody(CtBehavior method, String src)
  163. throws CompileError
  164. {
  165. try {
  166. int mod = method.getModifiers();
  167. recordParams(method.getParameterTypes(), Modifier.isStatic(mod));
  168. CtClass rtype;
  169. if (method instanceof CtMethod) {
  170. gen.setThisMethod((CtMethod)method);
  171. rtype = ((CtMethod)method).getReturnType();
  172. }
  173. else
  174. rtype = CtClass.voidType;
  175. recordReturnType(rtype, false);
  176. boolean isVoid = rtype == CtClass.voidType;
  177. if (src == null)
  178. makeDefaultBody(bytecode, rtype);
  179. else {
  180. Parser p = new Parser(new Lex(src));
  181. SymbolTable stb = new SymbolTable(stable);
  182. Stmnt s = p.parseStatement(stb);
  183. boolean callSuper = false;
  184. if (method instanceof CtConstructor)
  185. callSuper = !((CtConstructor)method).isClassInitializer();
  186. gen.atMethodBody(s, callSuper, isVoid);
  187. }
  188. return bytecode;
  189. }
  190. catch (NotFoundException e) {
  191. throw new CompileError(e.toString());
  192. }
  193. }
  194. private static void makeDefaultBody(Bytecode b, CtClass type) {
  195. int op;
  196. int value;
  197. if (type instanceof CtPrimitiveType) {
  198. CtPrimitiveType pt = (CtPrimitiveType)type;
  199. op = pt.getReturnOp();
  200. if (op == Opcode.DRETURN)
  201. value = Opcode.DCONST_0;
  202. else if (op == Opcode.FRETURN)
  203. value = Opcode.FCONST_0;
  204. else if (op == Opcode.LRETURN)
  205. value = Opcode.LCONST_0;
  206. else if (op == Opcode.RETURN)
  207. value = Opcode.NOP;
  208. else
  209. value = Opcode.ICONST_0;
  210. }
  211. else {
  212. op = Opcode.ARETURN;
  213. value = Opcode.ACONST_NULL;
  214. }
  215. if (value != Opcode.NOP)
  216. b.addOpcode(value);
  217. b.addOpcode(op);
  218. }
  219. /**
  220. * Records local variables available at the specified program counter.
  221. * If the LocalVariableAttribute is not available, this method does not
  222. * record any local variable. It only returns false.
  223. *
  224. * @param pc program counter (&gt;= 0)
  225. * @return false if the CodeAttribute does not include a
  226. * LocalVariableAttribute.
  227. */
  228. public boolean recordLocalVariables(CodeAttribute ca, int pc)
  229. throws CompileError
  230. {
  231. LocalVariableAttribute va
  232. = (LocalVariableAttribute)
  233. ca.getAttribute(LocalVariableAttribute.tag);
  234. if (va == null)
  235. return false;
  236. int n = va.tableLength();
  237. for (int i = 0; i < n; ++i) {
  238. int start = va.startPc(i);
  239. int len = va.codeLength(i);
  240. if (start <= pc && pc < start + len)
  241. gen.recordVariable(va.descriptor(i), va.variableName(i),
  242. va.index(i), stable);
  243. }
  244. return true;
  245. }
  246. /**
  247. * Records parameter names if the LocalVariableAttribute is available.
  248. * It returns false unless the LocalVariableAttribute is available.
  249. *
  250. * @param numOfLocalVars the number of local variables used
  251. * for storing the parameters.
  252. * @return false if the CodeAttribute does not include a
  253. * LocalVariableAttribute.
  254. */
  255. public boolean recordParamNames(CodeAttribute ca, int numOfLocalVars)
  256. throws CompileError
  257. {
  258. LocalVariableAttribute va
  259. = (LocalVariableAttribute)
  260. ca.getAttribute(LocalVariableAttribute.tag);
  261. if (va == null)
  262. return false;
  263. int n = va.tableLength();
  264. for (int i = 0; i < n; ++i) {
  265. int index = va.index(i);
  266. if (index < numOfLocalVars)
  267. gen.recordVariable(va.descriptor(i), va.variableName(i),
  268. index, stable);
  269. }
  270. return true;
  271. }
  272. /**
  273. * Makes variables $0 (this), $1, $2, ..., and $args represent method
  274. * parameters. $args represents an array of all the parameters.
  275. * It also makes $$ available as a parameter list of method call.
  276. *
  277. * <p>This must be called before calling <code>compileStmnt()</code> and
  278. * <code>compileExpr()</code>. The correct value of
  279. * <code>isStatic</code> must be recorded before compilation.
  280. */
  281. public int recordParams(CtClass[] params, boolean isStatic)
  282. throws CompileError
  283. {
  284. return gen.recordParams(params, isStatic, "$", "$args", "$$", stable);
  285. }
  286. /**
  287. * Makes variables $0, $1, $2, ..., and $args represent method
  288. * parameters. $args represents an array of all the parameters.
  289. * It also makes $$ available as a parameter list of method call.
  290. * $0 can represent a local variable other than THIS (variable 0).
  291. * $class is also made available.
  292. *
  293. * <p>This must be called before calling <code>compileStmnt()</code> and
  294. * <code>compileExpr()</code>. The correct value of
  295. * <code>isStatic</code> must be recorded before compilation.
  296. *
  297. * @paaram use0 true if $0 is used.
  298. * @param varNo the register number of $0 (use0 is true)
  299. * or $1 (otherwise).
  300. * @param target the type of $0 (it can be null if use0 is false).
  301. * It is used as the name of the type represented
  302. * by $class.
  303. * @param isStatic true if the method in which the compiled bytecode
  304. * is embedded is static.
  305. */
  306. public int recordParams(String target, CtClass[] params,
  307. boolean use0, int varNo, boolean isStatic)
  308. throws CompileError
  309. {
  310. return gen.recordParams(params, isStatic, "$", "$args", "$$",
  311. use0, varNo, target, stable);
  312. }
  313. /**
  314. * Prepares to use cast $r, $w, $_, and $type.
  315. * $type is made to represent the specified return type.
  316. * It also enables to write a return statement with a return value
  317. * for void method.
  318. *
  319. * <p>If the return type is void, ($r) does nothing.
  320. * The type of $_ is java.lang.Object.
  321. *
  322. * @param type the return type.
  323. * @param useResultVar true if $_ is used.
  324. * @return -1 or the variable index assigned to $_.
  325. * @see #recordType(CtClass)
  326. */
  327. public int recordReturnType(CtClass type, boolean useResultVar)
  328. throws CompileError
  329. {
  330. gen.recordType(type);
  331. return gen.recordReturnType(type, "$r",
  332. (useResultVar ? resultVarName : null), stable);
  333. }
  334. /**
  335. * Prepares to use $type. Note that recordReturnType() overwrites
  336. * the value of $type.
  337. *
  338. * @param t the type represented by $type.
  339. */
  340. public void recordType(CtClass t) {
  341. gen.recordType(t);
  342. }
  343. /**
  344. * Makes the given variable available.
  345. *
  346. * @param type variable type
  347. * @param name variable name
  348. */
  349. public int recordVariable(CtClass type, String name)
  350. throws CompileError
  351. {
  352. return gen.recordVariable(type, name, stable);
  353. }
  354. /**
  355. * Prepares to use $proceed().
  356. * If the return type of $proceed() is void, null is pushed on the
  357. * stack.
  358. *
  359. * @param target an expression specifying the target object.
  360. * if null, "this" is the target.
  361. * @param method the method name.
  362. */
  363. public void recordProceed(String target, String method)
  364. throws CompileError
  365. {
  366. Parser p = new Parser(new Lex(target));
  367. final ASTree texpr = p.parseExpression(stable);
  368. final String m = method;
  369. ProceedHandler h = new ProceedHandler() {
  370. public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
  371. throws CompileError
  372. {
  373. ASTree expr = new Member(m);
  374. if (texpr != null)
  375. expr = Expr.make('.', texpr, expr);
  376. expr = CallExpr.makeCall(expr, args);
  377. gen.compileExpr(expr);
  378. gen.addNullIfVoid();
  379. }
  380. public void setReturnType(JvstTypeChecker check, ASTList args)
  381. throws CompileError
  382. {
  383. ASTree expr = new Member(m);
  384. if (texpr != null)
  385. expr = Expr.make('.', texpr, expr);
  386. expr = CallExpr.makeCall(expr, args);
  387. expr.accept(check);
  388. check.addNullIfVoid();
  389. }
  390. };
  391. gen.setProceedHandler(h, proceedName);
  392. }
  393. /**
  394. * Prepares to use $proceed() representing a static method.
  395. * If the return type of $proceed() is void, null is pushed on the
  396. * stack.
  397. *
  398. * @param targetClass the fully-qualified dot-separated name
  399. * of the class declaring the method.
  400. * @param method the method name.
  401. */
  402. public void recordStaticProceed(String targetClass, String method)
  403. throws CompileError
  404. {
  405. final String c = targetClass;
  406. final String m = method;
  407. ProceedHandler h = new ProceedHandler() {
  408. public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
  409. throws CompileError
  410. {
  411. Expr expr = Expr.make(TokenId.MEMBER,
  412. new Symbol(c), new Member(m));
  413. expr = CallExpr.makeCall(expr, args);
  414. gen.compileExpr(expr);
  415. gen.addNullIfVoid();
  416. }
  417. public void setReturnType(JvstTypeChecker check, ASTList args)
  418. throws CompileError
  419. {
  420. Expr expr = Expr.make(TokenId.MEMBER,
  421. new Symbol(c), new Member(m));
  422. expr = CallExpr.makeCall(expr, args);
  423. expr.accept(check);
  424. check.addNullIfVoid();
  425. }
  426. };
  427. gen.setProceedHandler(h, proceedName);
  428. }
  429. /**
  430. * Prepares to use $proceed() representing a private/super's method.
  431. * If the return type of $proceed() is void, null is pushed on the
  432. * stack. This method is for methods invoked by INVOKESPECIAL.
  433. *
  434. * @param target an expression specifying the target object.
  435. * if null, "this" is the target.
  436. * @param classname the class name declaring the method.
  437. * @param methodname the method name.
  438. * @param descriptor the method descriptor.
  439. */
  440. public void recordSpecialProceed(String target, String classname,
  441. String methodname, String descriptor)
  442. throws CompileError
  443. {
  444. Parser p = new Parser(new Lex(target));
  445. final ASTree texpr = p.parseExpression(stable);
  446. final String cname = classname;
  447. final String method = methodname;
  448. final String desc = descriptor;
  449. ProceedHandler h = new ProceedHandler() {
  450. public void doit(JvstCodeGen gen, Bytecode b, ASTList args)
  451. throws CompileError
  452. {
  453. gen.compileInvokeSpecial(texpr, cname, method, desc, args);
  454. }
  455. public void setReturnType(JvstTypeChecker c, ASTList args)
  456. throws CompileError
  457. {
  458. c.compileInvokeSpecial(texpr, cname, method, desc, args);
  459. }
  460. };
  461. gen.setProceedHandler(h, proceedName);
  462. }
  463. /**
  464. * Prepares to use $proceed().
  465. */
  466. public void recordProceed(ProceedHandler h) {
  467. gen.setProceedHandler(h, proceedName);
  468. }
  469. /**
  470. * Compiles a statement (or a block).
  471. * <code>recordParams()</code> must be called before invoking
  472. * this method.
  473. *
  474. * <p>Local variables that are not declared
  475. * in the compiled source text might not be accessible within that
  476. * source text. Fields and method parameters ($0, $1, ..) are available.
  477. */
  478. public void compileStmnt(String src) throws CompileError {
  479. Parser p = new Parser(new Lex(src));
  480. SymbolTable stb = new SymbolTable(stable);
  481. while (p.hasMore()) {
  482. Stmnt s = p.parseStatement(stb);
  483. if (s != null)
  484. s.accept(gen);
  485. }
  486. }
  487. /**
  488. * Compiles an exression. <code>recordParams()</code> must be
  489. * called before invoking this method.
  490. *
  491. * <p>Local variables are not accessible
  492. * within the compiled source text. Fields and method parameters
  493. * ($0, $1, ..) are available if <code>recordParams()</code>
  494. * have been invoked.
  495. */
  496. public void compileExpr(String src) throws CompileError {
  497. Parser p = new Parser(new Lex(src));
  498. ASTree e = p.parseExpression(stable);
  499. compileExpr(e);
  500. }
  501. /**
  502. * Compiles an exression. <code>recordParams()</code> must be
  503. * called before invoking this method.
  504. *
  505. * <p>Local variables are not accessible
  506. * within the compiled source text. Fields and method parameters
  507. * ($0, $1, ..) are available if <code>recordParams()</code>
  508. * have been invoked.
  509. */
  510. public void compileExpr(ASTree e) throws CompileError {
  511. if (e != null)
  512. e.accept(gen);
  513. }
  514. }