diff options
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java')
-rw-r--r-- | plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java new file mode 100644 index 000000000000..d534e6df6d3c --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java @@ -0,0 +1,281 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.java.decompiler.struct.consts; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.main.DecompilerContext; +import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor; +import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; +import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; +import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.util.DataInputFullStream; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ConstantPool { + + public static final int FIELD = 1; + public static final int METHOD = 2; + + private List<PooledConstant> pool = new ArrayList<PooledConstant>(); + private PoolInterceptor interceptor; + + + public ConstantPool(DataInputStream in) throws IOException { + int size = in.readUnsignedShort(); + int[] pass = new int[size]; + + // first dummy constant + pool.add(null); + + // first pass: read the elements + for (int i = 1; i < size; i++) { + byte tag = (byte)in.readUnsignedByte(); + + switch (tag) { + case CodeConstants.CONSTANT_Utf8: + pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Utf8, in.readUTF())); + break; + case CodeConstants.CONSTANT_Integer: + pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Integer, new Integer(in.readInt()))); + break; + case CodeConstants.CONSTANT_Float: + pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Float, new Float(in.readFloat()))); + break; + case CodeConstants.CONSTANT_Long: + pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Long, new Long(in.readLong()))); + pool.add(null); + i++; + break; + case CodeConstants.CONSTANT_Double: + pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Double, new Double(in.readDouble()))); + pool.add(null); + i++; + break; + case CodeConstants.CONSTANT_Class: + case CodeConstants.CONSTANT_String: + case CodeConstants.CONSTANT_MethodType: + pool.add(new PrimitiveConstant(tag, in.readUnsignedShort())); + pass[i] = 1; + break; + case CodeConstants.CONSTANT_Fieldref: + case CodeConstants.CONSTANT_Methodref: + case CodeConstants.CONSTANT_InterfaceMethodref: + case CodeConstants.CONSTANT_NameAndType: + case CodeConstants.CONSTANT_InvokeDynamic: + pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort())); + if (tag == CodeConstants.CONSTANT_NameAndType) { + pass[i] = 1; + } + else { + pass[i] = 2; + } + break; + case CodeConstants.CONSTANT_MethodHandle: + pool.add(new LinkConstant(tag, in.readUnsignedByte(), in.readUnsignedShort())); + pass[i] = 3; + break; + } + } + + // resolving complex pool elements + for (int passIndex = 1; passIndex <= 3; passIndex++) { + for (int i = 1; i < size; i++) { + if (pass[i] == passIndex) { + pool.get(i).resolveConstant(this); + } + } + } + + // get global constant pool interceptor instance, if any available + interceptor = DecompilerContext.getPoolInterceptor(); + } + + public static void skipPool(DataInputFullStream in) throws IOException { + int size = in.readUnsignedShort(); + + for (int i = 1; i < size; i++) { + switch (in.readUnsignedByte()) { + case CodeConstants.CONSTANT_Utf8: + in.readUTF(); + break; + case CodeConstants.CONSTANT_Integer: + case CodeConstants.CONSTANT_Float: + case CodeConstants.CONSTANT_Fieldref: + case CodeConstants.CONSTANT_Methodref: + case CodeConstants.CONSTANT_InterfaceMethodref: + case CodeConstants.CONSTANT_NameAndType: + case CodeConstants.CONSTANT_InvokeDynamic: + in.discard(4); + break; + case CodeConstants.CONSTANT_Long: + case CodeConstants.CONSTANT_Double: + in.discard(8); + i++; + break; + case CodeConstants.CONSTANT_Class: + case CodeConstants.CONSTANT_String: + case CodeConstants.CONSTANT_MethodType: + in.discard(2); + break; + case CodeConstants.CONSTANT_MethodHandle: + in.discard(3); + } + } + } + + public int size() { + return pool.size(); + } + + public String[] getClassElement(int elementType, String className, int nameIndex, int descriptorIndex) { + String elementName = ((PrimitiveConstant)getConstant(nameIndex)).getString(); + String descriptor = ((PrimitiveConstant)getConstant(descriptorIndex)).getString(); + + if (interceptor != null) { + String newElement = interceptor.getName(className + " " + elementName + " " + descriptor); + if (newElement != null) { + elementName = newElement.split(" ")[1]; + } + + int type = elementType == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref; + String newDescriptor = buildNewDescriptor(type, descriptor); + if (newDescriptor != null) { + descriptor = newDescriptor; + } + } + + return new String[]{elementName, descriptor}; + } + + public PooledConstant getConstant(int index) { + return pool.get(index); + } + + public PrimitiveConstant getPrimitiveConstant(int index) { + PrimitiveConstant cn = (PrimitiveConstant)getConstant(index); + + if (cn != null && interceptor != null) { + if (cn.type == CodeConstants.CONSTANT_Class) { + String newName = buildNewClassname(cn.getString()); + if (newName != null) { + cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newName); + } + } + } + + return cn; + } + + public LinkConstant getLinkConstant(int index) { + LinkConstant ln = (LinkConstant)getConstant(index); + + if (ln != null && interceptor != null && + (ln.type == CodeConstants.CONSTANT_Fieldref || + ln.type == CodeConstants.CONSTANT_Methodref || + ln.type == CodeConstants.CONSTANT_InterfaceMethodref)) { + String newClassName = buildNewClassname(ln.classname); + String newElement = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor); + String newDescriptor = buildNewDescriptor(ln.type, ln.descriptor); + + if (newClassName != null || newElement != null || newDescriptor != null) { + String className = newClassName == null ? ln.classname : newClassName; + String elementName = newElement == null ? ln.elementname : newElement.split(" ")[1]; + String descriptor = newDescriptor == null ? ln.descriptor : newDescriptor; + ln = new LinkConstant(ln.type, className, elementName, descriptor); + } + } + + return ln; + } + + private String buildNewClassname(String className) { + VarType vt = new VarType(className, true); + + String newName = interceptor.getName(vt.value); + if (newName != null) { + StringBuilder buffer = new StringBuilder(); + + if (vt.arraydim > 0) { + for (int i = 0; i < vt.arraydim; i++) { + buffer.append("["); + } + + buffer.append("L").append(newName).append(";"); + } + else { + buffer.append(newName); + } + + return buffer.toString(); + } + + return null; + } + + private String buildNewDescriptor(int type, String descriptor) { + boolean updated = false; + + if (type == CodeConstants.CONSTANT_Fieldref) { + FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor); + + VarType fType = fd.type; + if (fType.type == CodeConstants.TYPE_OBJECT) { + String newClassName = buildNewClassname(fType.value); + if (newClassName != null) { + fType.value = newClassName; + updated = true; + } + } + + if (updated) { + return fd.getDescriptor(); + } + } + else { + MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor); + + // parameters + for (VarType paramType : md.params) { + if (paramType.type == CodeConstants.TYPE_OBJECT) { + String newClassName = buildNewClassname(paramType.value); + if (newClassName != null) { + paramType.value = newClassName; + updated = true; + } + } + } + + // return value + if (md.ret.type == CodeConstants.TYPE_OBJECT) { + String newClassName = buildNewClassname(md.ret.value); + if (newClassName != null) { + md.ret.value = newClassName; + updated = true; + } + } + + if (updated) { + return md.getDescriptor(); + } + } + + return null; + } +} |