📄 javac.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.CtClass;import javassist.CtPrimitiveType;import javassist.CtMember;import javassist.CtField;import javassist.CtBehavior;import javassist.CtMethod;import javassist.CtConstructor;import javassist.CannotCompileException;import javassist.Modifier;import javassist.bytecode.Bytecode;import javassist.bytecode.CodeAttribute;import javassist.bytecode.LocalVariableAttribute;import javassist.bytecode.Opcode;import javassist.NotFoundException;import javassist.compiler.ast.*;public class Javac { JvstCodeGen gen; SymbolTable stable; private Bytecode bytecode; public static final String param0Name = "$0"; public static final String resultVarName = "$_"; public static final String proceedName = "$proceed"; /** * Constructs a compiler. * * @param thisClass the class that a compiled method/field * belongs to. */ public Javac(CtClass thisClass) { this(new Bytecode(thisClass.getClassFile2().getConstPool(), 0, 0), thisClass); } /** * Constructs a compiler. * The produced bytecode is stored in the <code>Bytecode</code> object * specified by <code>b</code>. * * @param thisClass the class that a compiled method/field * belongs to. */ public Javac(Bytecode b, CtClass thisClass) { gen = new JvstCodeGen(b, thisClass, thisClass.getClassPool()); stable = new SymbolTable(); bytecode = b; } /** * Returns the produced bytecode. */ public Bytecode getBytecode() { return bytecode; } /** * Compiles a method, constructor, or field declaration * to a class. * A field declaration can declare only one field. * * <p>In a method or constructor body, $0, $1, ... and $_ * are not available. * * @return a <code>CtMethod</code>, <code>CtConstructor</code>, * or <code>CtField</code> object. * @see #recordProceed(String,String) */ public CtMember compile(String src) throws CompileError { Parser p = new Parser(new Lex(src)); ASTList mem = p.parseMember1(stable); try { if (mem instanceof FieldDecl) return compileField((FieldDecl)mem); else return compileMethod(p, (MethodDecl)mem); } catch (CannotCompileException e) { throw new CompileError(e.getMessage()); } } public static class CtFieldWithInit extends CtField { private ASTree init; CtFieldWithInit(CtClass type, String name, CtClass declaring) throws CannotCompileException { super(type, name, declaring); init = null; } protected void setInit(ASTree i) { init = i; } protected ASTree getInitAST() { return init; } } private CtField compileField(FieldDecl fd) throws CompileError, CannotCompileException { CtFieldWithInit f; Declarator d = fd.getDeclarator(); f = new CtFieldWithInit(gen.resolver.lookupClass(d), d.getVariable().get(), gen.getThisClass()); f.setModifiers(MemberResolver.getModifiers(fd.getModifiers())); if (fd.getInit() != null) f.setInit(fd.getInit()); return f; } private CtMember compileMethod(Parser p, MethodDecl md) throws CompileError { int mod = MemberResolver.getModifiers(md.getModifiers()); CtClass[] plist = gen.makeParamList(md); CtClass[] tlist = gen.makeThrowsList(md); recordParams(plist, Modifier.isStatic(mod)); md = p.parseMethod2(stable, md); try { if (md.isConstructor()) { CtConstructor cons = new CtConstructor(plist, gen.getThisClass()); cons.setModifiers(mod); md.accept(gen); cons.getMethodInfo().setCodeAttribute( bytecode.toCodeAttribute()); cons.setExceptionTypes(tlist); return cons; } else { Declarator r = md.getReturn(); CtClass rtype = gen.resolver.lookupClass(r); recordReturnType(rtype, false); CtMethod method = new CtMethod(rtype, r.getVariable().get(), plist, gen.getThisClass()); method.setModifiers(mod); gen.setThisMethod(method); md.accept(gen); if (md.getBody() != null) method.getMethodInfo().setCodeAttribute( bytecode.toCodeAttribute()); else method.setModifiers(mod | Modifier.ABSTRACT); method.setExceptionTypes(tlist); return method; } } catch (NotFoundException e) { throw new CompileError(e.toString()); } } /** * Compiles a method (or constructor) body. * * @src a single statement or a block. * If null, this method produces a body returning zero or null. */ public Bytecode compileBody(CtBehavior method, String src) throws CompileError { try { int mod = method.getModifiers(); recordParams(method.getParameterTypes(), Modifier.isStatic(mod)); CtClass rtype; if (method instanceof CtMethod) { gen.setThisMethod((CtMethod)method); rtype = ((CtMethod)method).getReturnType(); } else rtype = CtClass.voidType; recordReturnType(rtype, false); boolean isVoid = rtype == CtClass.voidType; if (src == null) makeDefaultBody(bytecode, rtype); else { Parser p = new Parser(new Lex(src)); SymbolTable stb = new SymbolTable(stable); Stmnt s = p.parseStatement(stb); if (p.hasMore()) throw new CompileError( "the method/constructor body must be surrounded by {}"); boolean callSuper = false; if (method instanceof CtConstructor) callSuper = !((CtConstructor)method).isClassInitializer(); gen.atMethodBody(s, callSuper, isVoid); } return bytecode; } catch (NotFoundException e) { throw new CompileError(e.toString()); } } private static void makeDefaultBody(Bytecode b, CtClass type) { int op; int value; if (type instanceof CtPrimitiveType) { CtPrimitiveType pt = (CtPrimitiveType)type; op = pt.getReturnOp(); if (op == Opcode.DRETURN) value = Opcode.DCONST_0; else if (op == Opcode.FRETURN) value = Opcode.FCONST_0; else if (op == Opcode.LRETURN) value = Opcode.LCONST_0; else if (op == Opcode.RETURN) value = Opcode.NOP; else value = Opcode.ICONST_0; } else { op = Opcode.ARETURN; value = Opcode.ACONST_NULL; } if (value != Opcode.NOP) b.addOpcode(value); b.addOpcode(op); } /** * Records local variables available at the specified program counter. * If the LocalVariableAttribute is not available, this method does not * record any local variable. It only returns false. * * @param pc program counter (>= 0) * @return false if the CodeAttribute does not include a * LocalVariableAttribute. */ public boolean recordLocalVariables(CodeAttribute ca, int pc) throws CompileError { LocalVariableAttribute va = (LocalVariableAttribute) ca.getAttribute(LocalVariableAttribute.tag); if (va == null) return false; int n = va.tableLength(); for (int i = 0; i < n; ++i) { int start = va.startPc(i); int len = va.codeLength(i); if (start <= pc && pc < start + len) gen.recordVariable(va.descriptor(i), va.variableName(i), va.index(i), stable); } return true; } /** * Records parameter names if the LocalVariableAttribute is available. * It returns false unless the LocalVariableAttribute is available. * * @param numOfLocalVars the number of local variables used * for storing the parameters. * @return false if the CodeAttribute does not include a * LocalVariableAttribute. */ public boolean recordParamNames(CodeAttribute ca, int numOfLocalVars) throws CompileError { LocalVariableAttribute va = (LocalVariableAttribute) ca.getAttribute(LocalVariableAttribute.tag); if (va == null) return false; int n = va.tableLength(); for (int i = 0; i < n; ++i) { int index = va.index(i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -