com.feilong.lib.javassist.expr.NewArray Maven / Gradle / Ivy
Show all versions of feilong Show documentation
/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- 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,
* or the Apache License Version 2.0.
*
* 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 com.feilong.lib.javassist.expr;
import com.feilong.lib.javassist.CannotCompileException;
import com.feilong.lib.javassist.CtBehavior;
import com.feilong.lib.javassist.CtClass;
import com.feilong.lib.javassist.CtPrimitiveType;
import com.feilong.lib.javassist.NotFoundException;
import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.Bytecode;
import com.feilong.lib.javassist.bytecode.CodeAttribute;
import com.feilong.lib.javassist.bytecode.CodeIterator;
import com.feilong.lib.javassist.bytecode.ConstPool;
import com.feilong.lib.javassist.bytecode.Descriptor;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.javassist.bytecode.Opcode;
import com.feilong.lib.javassist.compiler.CompileError;
import com.feilong.lib.javassist.compiler.Javac;
import com.feilong.lib.javassist.compiler.JvstCodeGen;
import com.feilong.lib.javassist.compiler.JvstTypeChecker;
import com.feilong.lib.javassist.compiler.ProceedHandler;
import com.feilong.lib.javassist.compiler.ast.ASTList;
/**
* Array creation.
*
*
* This class does not provide methods for obtaining the initial
* values of array elements.
*/
public class NewArray extends Expr{
int opcode;
protected NewArray(int pos, CodeIterator i, CtClass declaring, MethodInfo m, int op){
super(pos, i, declaring, m);
opcode = op;
}
/**
* Returns the method or constructor containing the array creation
* represented by this object.
*/
@Override
public CtBehavior where(){
return super.where();
}
/**
* Returns the line number of the source line containing the
* array creation.
*
* @return -1 if this information is not available.
*/
@Override
public int getLineNumber(){
return super.getLineNumber();
}
/**
* Returns the source file containing the array creation.
*
* @return null if this information is not available.
*/
@Override
public String getFileName(){
return super.getFileName();
}
/**
* Returns the list of exceptions that the expression may throw.
* This list includes both the exceptions that the try-catch statements
* including the expression can catch and the exceptions that
* the throws declaration allows the method to throw.
*/
@Override
public CtClass[] mayThrow(){
return super.mayThrow();
}
/**
* Returns the type of array components. If the created array is
* a two-dimensional array of int
,
* the type returned by this method is
* not int[]
but int
.
*/
public CtClass getComponentType() throws NotFoundException{
if (opcode == Opcode.NEWARRAY){
int atype = iterator.byteAt(currentPos + 1);
return getPrimitiveType(atype);
}else if (opcode == Opcode.ANEWARRAY || opcode == Opcode.MULTIANEWARRAY){
int index = iterator.u16bitAt(currentPos + 1);
String desc = getConstPool().getClassInfo(index);
int dim = Descriptor.arrayDimension(desc);
desc = Descriptor.toArrayComponent(desc, dim);
return Descriptor.toCtClass(desc, thisClass.getClassPool());
}else{
throw new RuntimeException("bad opcode: " + opcode);
}
}
CtClass getPrimitiveType(int atype){
switch (atype) {
case Opcode.T_BOOLEAN:
return CtClass.booleanType;
case Opcode.T_CHAR:
return CtClass.charType;
case Opcode.T_FLOAT:
return CtClass.floatType;
case Opcode.T_DOUBLE:
return CtClass.doubleType;
case Opcode.T_BYTE:
return CtClass.byteType;
case Opcode.T_SHORT:
return CtClass.shortType;
case Opcode.T_INT:
return CtClass.intType;
case Opcode.T_LONG:
return CtClass.longType;
default:
throw new RuntimeException("bad atype: " + atype);
}
}
/**
* Returns the dimension of the created array.
*/
public int getDimension(){
if (opcode == Opcode.NEWARRAY){
return 1;
}else if (opcode == Opcode.ANEWARRAY || opcode == Opcode.MULTIANEWARRAY){
int index = iterator.u16bitAt(currentPos + 1);
String desc = getConstPool().getClassInfo(index);
return Descriptor.arrayDimension(desc) + (opcode == Opcode.ANEWARRAY ? 1 : 0);
}else{
throw new RuntimeException("bad opcode: " + opcode);
}
}
/**
* Returns the number of dimensions of arrays to be created.
* If the opcode is multianewarray, this method returns the second
* operand. Otherwise, it returns 1.
*/
public int getCreatedDimensions(){
if (opcode == Opcode.MULTIANEWARRAY){
return iterator.byteAt(currentPos + 3);
}
return 1;
}
/**
* Replaces the array creation with the bytecode derived from
* the given source text.
*
*
* $0 is available even if the called method is static.
* If the field access is writing, $_ is available but the value
* of $_ is ignored.
*
* @param statement
* a Java statement except try-catch.
*/
@Override
public void replace(String statement) throws CannotCompileException{
try{
replace2(statement);
}catch (CompileError e){
throw new CannotCompileException(e);
}catch (NotFoundException e){
throw new CannotCompileException(e);
}catch (BadBytecode e){
throw new CannotCompileException("broken method");
}
}
private void replace2(String statement) throws CompileError,NotFoundException,BadBytecode,CannotCompileException{
thisClass.getClassFile(); // to call checkModify().
ConstPool constPool = getConstPool();
int pos = currentPos;
CtClass retType;
int codeLength;
int index = 0;
int dim = 1;
String desc;
if (opcode == Opcode.NEWARRAY){
index = iterator.byteAt(currentPos + 1); // atype
CtPrimitiveType cpt = (CtPrimitiveType) getPrimitiveType(index);
desc = "[" + cpt.getDescriptor();
codeLength = 2;
}else if (opcode == Opcode.ANEWARRAY){
index = iterator.u16bitAt(pos + 1);
desc = constPool.getClassInfo(index);
if (desc.startsWith("[")){
desc = "[" + desc;
}else{
desc = "[L" + desc + ";";
}
codeLength = 3;
}else if (opcode == Opcode.MULTIANEWARRAY){
index = iterator.u16bitAt(currentPos + 1);
desc = constPool.getClassInfo(index);
dim = iterator.byteAt(currentPos + 3);
codeLength = 4;
}else{
throw new RuntimeException("bad opcode: " + opcode);
}
retType = Descriptor.toCtClass(desc, thisClass.getClassPool());
Javac jc = new Javac(thisClass);
CodeAttribute ca = iterator.get();
CtClass[] params = new CtClass[dim];
for (int i = 0; i < dim; ++i){
params[i] = CtClass.intType;
}
int paramVar = ca.getMaxLocals();
jc.recordParams(javaLangObject, params, true, paramVar, withinStatic());
/*
* Is $_ included in the source code?
*/
checkResultValue(retType, statement);
int retVar = jc.recordReturnType(retType, true);
jc.recordProceed(new ProceedForArray(retType, opcode, index, dim));
Bytecode bytecode = jc.getBytecode();
storeStack(params, true, paramVar, bytecode);
jc.recordLocalVariables(ca, pos);
bytecode.addOpcode(ACONST_NULL); // initialize $_
bytecode.addAstore(retVar);
jc.compileStmnt(statement);
bytecode.addAload(retVar);
replace0(pos, bytecode, codeLength);
}
/*
* $proceed( ..)
*/
static class ProceedForArray implements ProceedHandler{
CtClass arrayType;
int opcode;
int index, dimension;
ProceedForArray(CtClass type, int op, int i, int dim){
arrayType = type;
opcode = op;
index = i;
dimension = dim;
}
@Override
public void doit(JvstCodeGen gen,Bytecode bytecode,ASTList args) throws CompileError{
int num = gen.getMethodArgsLength(args);
if (num != dimension){
throw new CompileError(Javac.proceedName + "() with a wrong number of parameters");
}
gen.atMethodArgs(args, new int[num], new int[num], new String[num]);
bytecode.addOpcode(opcode);
if (opcode == Opcode.ANEWARRAY){
bytecode.addIndex(index);
}else if (opcode == Opcode.NEWARRAY){
bytecode.add(index);
}else /* if (opcode == Opcode.MULTIANEWARRAY) */ {
bytecode.addIndex(index);
bytecode.add(dimension);
bytecode.growStack(1 - dimension);
}
gen.setType(arrayType);
}
@Override
public void setReturnType(JvstTypeChecker c,ASTList args) throws CompileError{
c.setType(arrayType);
}
}
}