summaryrefslogtreecommitdiff
path: root/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
diff options
context:
space:
mode:
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.java281
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;
+ }
+}