java-decompiler: fixes and cleanups

- unified attribute loading code
- common methods for checking member flags
- verifying skip()
- correct resource closing
- typos
master
Roman Shevchenko 10 years ago
parent c0c83126a6
commit 2df49d32a7
  1. 11
      src/org/jetbrains/java/decompiler/main/AssertProcessor.java
  2. 62
      src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
  3. 62
      src/org/jetbrains/java/decompiler/main/ClassWriter.java
  4. 9
      src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
  5. 5
      src/org/jetbrains/java/decompiler/main/EnumProcessor.java
  6. 2
      src/org/jetbrains/java/decompiler/main/InitializerProcessor.java
  7. 2
      src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
  8. 10
      src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
  9. 53
      src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java
  10. 2
      src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java
  11. 47
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java
  12. 13
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
  13. 3
      src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java
  14. 3
      src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java
  15. 2
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
  16. 2
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java
  17. 2
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java
  18. 8
      src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java
  19. 11
      src/org/jetbrains/java/decompiler/struct/ContextUnit.java
  20. 298
      src/org/jetbrains/java/decompiler/struct/StructClass.java
  21. 15
      src/org/jetbrains/java/decompiler/struct/StructContext.java
  22. 92
      src/org/jetbrains/java/decompiler/struct/StructField.java
  23. 87
      src/org/jetbrains/java/decompiler/struct/StructMember.java
  24. 317
      src/org/jetbrains/java/decompiler/struct/StructMethod.java
  25. 27
      src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java
  26. 95
      src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
  27. 148
      src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
  28. 2
      src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java
  29. 155
      src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
  30. 17
      src/org/jetbrains/java/decompiler/util/DataInputFullStream.java
  31. 2
      test/org/jetbrains/java/decompiler/SingleClassesTest.java

@ -69,7 +69,7 @@ public class AssertProcessor {
ClassWrapper wrapper = node.wrapper; ClassWrapper wrapper = node.wrapper;
boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
for (StructField fd : wrapper.getClassStruct().getFields()) { for (StructField fd : wrapper.getClassStruct().getFields()) {
@ -78,12 +78,8 @@ public class AssertProcessor {
// initializer exists // initializer exists
if (wrapper.getStaticFieldInitializers().containsKey(keyField)) { if (wrapper.getStaticFieldInitializers().containsKey(keyField)) {
int flags = fd.access_flags;
boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic");
// access flags set // access flags set
if ((flags & CodeConstants.ACC_STATIC) != 0 && (flags & CodeConstants.ACC_FINAL) != 0 && if (fd.hasModifier(CodeConstants.ACC_STATIC) && fd.hasModifier(CodeConstants.ACC_FINAL) && (noSynthFlag || fd.isSynthetic())) {
(isSynthetic || nosynthflag)) {
// field type boolean // field type boolean
FieldDescriptor fdescr = FieldDescriptor.parseDescriptor(fd.getDescriptor()); FieldDescriptor fdescr = FieldDescriptor.parseDescriptor(fd.getDescriptor());
@ -100,8 +96,7 @@ public class AssertProcessor {
if (invexpr.getInstance() != null && if (invexpr.getInstance() != null &&
invexpr.getInstance().type == Exprent.EXPRENT_CONST && invexpr.getInstance().type == Exprent.EXPRENT_CONST &&
"desiredAssertionStatus".equals(invexpr.getName()) "desiredAssertionStatus".equals(invexpr.getName()) &&
&&
"java/lang/Class".equals(invexpr.getClassname()) && "java/lang/Class".equals(invexpr.getClassname()) &&
invexpr.getLstParameters().isEmpty()) { invexpr.getLstParameters().isEmpty()) {

@ -33,10 +33,7 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection; import org.jetbrains.java.decompiler.util.VBStyleCollection;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry; import java.util.Map.Entry;
public class ClassReference14Processor { public class ClassReference14Processor {
@ -105,7 +102,7 @@ public class ClassReference14Processor {
// find the synthetic method Class class$(String) if present // find the synthetic method Class class$(String) if present
HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>(); HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
findClassMethod(node, mapClassMeths); mapClassMethods(node, mapClassMeths);
if (mapClassMeths.isEmpty()) { if (mapClassMeths.isEmpty()) {
return; return;
@ -176,37 +173,33 @@ public class ClassReference14Processor {
} }
} }
private void findClassMethod(ClassNode node, HashMap<ClassWrapper, MethodWrapper> mapClassMeths) { private void mapClassMethods(ClassNode node, Map<ClassWrapper, MethodWrapper> map) {
boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
boolean nosynthflag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
ClassWrapper wrapper = node.wrapper; ClassWrapper wrapper = node.wrapper;
for (MethodWrapper meth : wrapper.getMethods()) { for (MethodWrapper method : wrapper.getMethods()) {
StructMethod mt = meth.methodStruct; StructMethod mt = method.methodStruct;
if (((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic") if ((noSynthFlag || mt.isSynthetic()) &&
|| nosynthflag) &&
mt.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") && mt.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") &&
(mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0) { mt.hasModifier(CodeConstants.ACC_STATIC)) {
RootStatement root = meth.root; RootStatement root = method.root;
if (root != null) { if (root != null && root.getFirst().type == Statement.TYPE_TRYCATCH) {
if (root.getFirst().type == Statement.TYPE_TRYCATCH) { CatchStatement cst = (CatchStatement)root.getFirst();
CatchStatement cst = (CatchStatement)root.getFirst(); if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK &&
if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK && cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK &&
cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK && cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) {
cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) {
BasicBlockStatement body = (BasicBlockStatement)cst.getFirst();
BasicBlockStatement body = (BasicBlockStatement)cst.getFirst(); BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) { if (bodyexprent.equals(body.getExprents().get(0)) &&
if (bodyexprent.equals(body.getExprents().get(0)) && handlerexprent.equals(handler.getExprents().get(0))) {
handlerexprent.equals(handler.getExprents().get(0))) { map.put(wrapper, method);
mapClassMeths.put(wrapper, meth); break;
break;
}
} }
} }
} }
@ -216,7 +209,7 @@ public class ClassReference14Processor {
// iterate nested classes // iterate nested classes
for (ClassNode nd : node.nested) { for (ClassNode nd : node.nested) {
findClassMethod(nd, mapClassMeths); mapClassMethods(nd, map);
} }
} }
@ -269,9 +262,8 @@ public class ClassReference14Processor {
StructField fd = StructField fd =
wrapper.getClassStruct().getField(field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why?? wrapper.getClassStruct().getField(field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why??
if (fd != null && (fd.access_flags & CodeConstants.ACC_STATIC) != 0 && if (fd != null && fd.hasModifier(CodeConstants.ACC_STATIC) &&
((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic") (fd.isSynthetic() || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) {
|| DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) {
if (fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) { if (fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) {
AssignmentExprent asexpr = (AssignmentExprent)fexpr.getLstOperands().get(1); AssignmentExprent asexpr = (AssignmentExprent)fexpr.getLstOperands().get(1);

@ -99,7 +99,7 @@ public class ClassWriter {
ref14processor.processClassReferences(node); ref14processor.processClassReferences(node);
} }
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (cl.access_flags & CodeConstants.ACC_ENUM) != 0) { if (cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM)) {
EnumProcessor.clearEnum(wrapper); EnumProcessor.clearEnum(wrapper);
} }
@ -234,11 +234,8 @@ public class ClassWriter {
boolean mthidden = false; boolean mthidden = false;
for (StructMethod mt : cl.getMethods()) { for (StructMethod mt : cl.getMethods()) {
boolean isSynthetic = mt.isSynthetic();
int flags = mt.getAccessFlags(); boolean isBridge = mt.hasModifier(CodeConstants.ACC_BRIDGE);
boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) && if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) &&
(!isBridge || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE)) && (!isBridge || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE)) &&
@ -262,12 +259,10 @@ public class ClassWriter {
// fields // fields
for (StructField fd : cl.getFields()) { for (StructField fd : cl.getFields()) {
int flags = fd.access_flags; boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic"); wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) if (!hide) {
&& !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) { boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
if (isEnum) { if (isEnum) {
if (enumfields) { if (enumfields) {
bufstrwriter1.write(","); bufstrwriter1.write(",");
@ -310,12 +305,11 @@ public class ClassWriter {
// member classes // member classes
for (ClassNode inner : node.nested) { for (ClassNode inner : node.nested) {
if (inner.type == ClassNode.CLASS_MEMBER) { if (inner.type == ClassNode.CLASS_MEMBER) {
StructClass innercl = inner.classStruct; StructClass innerCl = inner.classStruct;
boolean isSynthetic = (inner.access & CodeConstants.ACC_SYNTHETIC) != 0 || innerCl.isSynthetic();
boolean isSynthetic = boolean hide = isSynthetic && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
((inner.access | innercl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || innercl.getAttributes().containsKey("Synthetic"); wrapper.getHideMembers().contains(innerCl.qualifiedName);
if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) if (!hide) {
&& !wrapper.getHideMembers().contains(innercl.qualifiedName)) {
writer.write(DecompilerContext.getNewLineSeparator()); writer.write(DecompilerContext.getNewLineSeparator());
classToJava(inner, writer, indent + 1); classToJava(inner, writer, indent + 1);
} }
@ -347,7 +341,7 @@ public class ClassWriter {
ClassWrapper wrapper = node.wrapper; ClassWrapper wrapper = node.wrapper;
StructClass cl = wrapper.getClassStruct(); StructClass cl = wrapper.getClassStruct();
int flags = node.type == ClassNode.CLASS_ROOT ? cl.access_flags : node.access; int flags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0; boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0;
boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0; boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0;
boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0; boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
@ -486,8 +480,7 @@ public class ClassWriter {
String indstr = InterpreterUtil.getIndentString(indent); String indstr = InterpreterUtil.getIndentString(indent);
boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0; boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
int flags = fd.access_flags;
if (interceptor != null) { if (interceptor != null) {
String oldname = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor()); String oldname = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor());
@ -515,8 +508,8 @@ public class ClassWriter {
writer.write(DecompilerContext.getNewLineSeparator()); writer.write(DecompilerContext.getNewLineSeparator());
} }
boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic"); boolean isSynthetic = fd.isSynthetic();
boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0; boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
if (isSynthetic) { if (isSynthetic) {
writer.write(indstr); writer.write(indstr);
@ -529,7 +522,7 @@ public class ClassWriter {
if (!isEnum) { if (!isEnum) {
for (int i = 0; i < modval_field.length; i++) { for (int i = 0; i < modval_field.length; i++) {
if (!isInterface || !mod_notinterface_fields.contains(modval_field[i])) { if (!isInterface || !mod_notinterface_fields.contains(modval_field[i])) {
if ((flags & modval_field[i]) != 0) { if (fd.hasModifier(modval_field[i])) {
writer.write(modstr_field[i]); writer.write(modstr_field[i]);
} }
} }
@ -559,7 +552,7 @@ public class ClassWriter {
writer.write(fd.getName()); writer.write(fd.getName());
Exprent initializer; Exprent initializer;
if ((flags & CodeConstants.ACC_STATIC) != 0) { if (fd.hasModifier(CodeConstants.ACC_STATIC)) {
initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
} }
else { else {
@ -577,7 +570,7 @@ public class ClassWriter {
writer.write(initializer.toJava(indent)); writer.write(initializer.toJava(indent));
} }
} }
else if ((flags & CodeConstants.ACC_FINAL) != 0 && (flags & CodeConstants.ACC_STATIC) != 0) { else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) {
StructConstantValueAttribute attr = StructConstantValueAttribute attr =
(StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE); (StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);
if (attr != null) { if (attr != null) {
@ -704,9 +697,9 @@ public class ClassWriter {
MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth); DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth);
boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0; boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
boolean isAnnotation = (cl.access_flags & CodeConstants.ACC_ANNOTATION) != 0; boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);
boolean isEnum = (cl.access_flags & CodeConstants.ACC_ENUM) != 0 && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
boolean isDeprecated = mt.getAttributes().containsKey("Deprecated"); boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
String indstr = InterpreterUtil.getIndentString(indent); String indstr = InterpreterUtil.getIndentString(indent);
@ -721,9 +714,8 @@ public class ClassWriter {
if ((flags & CodeConstants.ACC_NATIVE) != 0) { if ((flags & CodeConstants.ACC_NATIVE) != 0) {
flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp
} }
if ("<clinit>".equals(mt.getName())) { if ("<clinit>".equals(mt.getName())) {
flags &= CodeConstants.ACC_STATIC; // ingnore all modifiers except 'static' in a static initializer flags &= CodeConstants.ACC_STATIC; // ignore all modifiers except 'static' in a static initializer
} }
if (interceptor != null) { if (interceptor != null) {
@ -816,7 +808,7 @@ public class ClassWriter {
if (!clinit && !dinit) { if (!clinit && !dinit) {
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
// formal type parameters // formal type parameters
if (descriptor != null && !descriptor.fparameters.isEmpty()) { if (descriptor != null && !descriptor.fparameters.isEmpty()) {
@ -900,8 +892,7 @@ public class ClassWriter {
if (descriptor != null) { if (descriptor != null) {
GenericType partype = descriptor.params.get(i); GenericType partype = descriptor.params.get(i);
boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0 boolean isVarArgs = (i == lastparam_index && mt.hasModifier(CodeConstants.ACC_VARARGS) && partype.arraydim > 0);
&& partype.arraydim > 0);
if (isVarArgs) { if (isVarArgs) {
partype.arraydim--; partype.arraydim--;
@ -922,8 +913,7 @@ public class ClassWriter {
else { else {
VarType partype = md.params[i].copy(); VarType partype = md.params[i].copy();
boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0 boolean isVarArgs = (i == lastparam_index && mt.hasModifier(CodeConstants.ACC_VARARGS) && partype.arraydim > 0);
&& partype.arraydim > 0);
if (isVarArgs) { if (isVarArgs) {
partype.decArrayDim(); partype.decArrayDim();

@ -139,7 +139,7 @@ public class ClassesProcessor {
} }
ClassNode node = new ClassNode(ClassNode.CLASS_ROOT, cl); ClassNode node = new ClassNode(ClassNode.CLASS_ROOT, cl);
node.access = cl.access_flags; node.access = cl.getAccessFlags();
mapRootClasses.put(cl.qualifiedName, node); mapRootClasses.put(cl.qualifiedName, node);
} }
} }
@ -394,12 +394,9 @@ public class ClassesProcessor {
anonimousClassType = new VarType(lambda_class_name, true); anonimousClassType = new VarType(lambda_class_name, true);
boolean is_method_reference = (content_class_name != classStruct.qualifiedName); boolean is_method_reference = (content_class_name != classStruct.qualifiedName);
StructMethod mt = null;
if (!is_method_reference) { // content method in the same class, check synthetic flag if (!is_method_reference) { // content method in the same class, check synthetic flag
mt = classStruct.getMethod(content_method_name, content_method_descriptor); StructMethod mt = classStruct.getMethod(content_method_name, content_method_descriptor);
is_method_reference = !((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) != 0 || is_method_reference = !mt.isSynthetic(); // if not synthetic -> method reference
mt.getAttributes().containsKey("Synthetic")); // if not synthetic -> method reference
} }
lambda_information.is_method_reference = is_method_reference; lambda_information.is_method_reference = is_method_reference;

@ -82,7 +82,7 @@ public class EnumProcessor {
// hide dummy synthetic fields of enum constants // hide dummy synthetic fields of enum constants
for (StructField fd : cl.getFields()) { for (StructField fd : cl.getFields()) {
if ((fd.access_flags & CodeConstants.ACC_ENUM) != 0) { if (fd.hasModifier(CodeConstants.ACC_ENUM)) {
Exprent initializer = Exprent initializer =
wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
if (initializer != null && initializer.type == Exprent.EXPRENT_NEW) { if (initializer != null && initializer.type == Exprent.EXPRENT_NEW) {
@ -97,10 +97,9 @@ public class EnumProcessor {
} }
private static void hideDummyFieldInConstant(ClassWrapper wrapper) { private static void hideDummyFieldInConstant(ClassWrapper wrapper) {
StructClass cl = wrapper.getClassStruct(); StructClass cl = wrapper.getClassStruct();
for (StructField fd : cl.getFields()) { for (StructField fd : cl.getFields()) {
if ((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0) { if (fd.isSynthetic()) {
FieldDescriptor descr = FieldDescriptor.parseDescriptor(fd.getDescriptor()); FieldDescriptor descr = FieldDescriptor.parseDescriptor(fd.getDescriptor());
VarType ret = descr.type; VarType ret = descr.type;

@ -76,7 +76,7 @@ public class InitializerProcessor {
FieldExprent fexpr = (FieldExprent)asexpr.getLeft(); FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
if (fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) { if (fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString); StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString);
if (structField != null && (structField.access_flags & CodeConstants.ACC_FINAL) != 0) { if (structField != null && structField.hasModifier(CodeConstants.ACC_FINAL)) {
action = 1; action = 1;
} }
} }

@ -123,7 +123,7 @@ public class ClassWrapper {
} }
} }
else { else {
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
int paramcount = 0; int paramcount = 0;

@ -71,7 +71,7 @@ public class NestedClassProcessor {
// ensure not-empty class name // ensure not-empty class name
if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) { if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) {
StructClass cl = child.classStruct; StructClass cl = child.classStruct;
if (((child.access | cl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic")) { if ((child.access & CodeConstants.ACC_SYNTHETIC) != 0 || cl.isSynthetic()) {
child.simpleName = "SyntheticClass_" + (++synthetics); child.simpleName = "SyntheticClass_" + (++synthetics);
} }
else { else {
@ -675,7 +675,7 @@ public class NestedClassProcessor {
return null; return null;
} }
boolean notsynth = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
// no loop at the begin // no loop at the begin
DirectNode firstnode = graph.first; DirectNode firstnode = graph.first;
@ -692,10 +692,8 @@ public class NestedClassProcessor {
if (fd != null) { // local (== not inherited) field if (fd != null) { // local (== not inherited) field
if (cl.qualifiedName.equals(left.getClassname()) && if (cl.qualifiedName.equals(left.getClassname()) &&
(fd.access_flags & CodeConstants.ACC_FINAL) != 0 && fd.hasModifier(CodeConstants.ACC_FINAL) &&
((fd.access_flags & CodeConstants.ACC_SYNTHETIC) != 0 || (fd.isSynthetic() || (noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE)))) {
fd.getAttributes().containsKey("Synthetic") ||
(notsynth && (fd.access_flags & CodeConstants.ACC_PRIVATE) != 0))) {
field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString); field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString);
break; break;
} }

@ -32,26 +32,25 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map;
public class NestedMemberAccess { public class NestedMemberAccess {
private static final int METHOD_ACCESS_NORMAL = 1; private static final int METHOD_ACCESS_NORMAL = 1;
private static final int METHOD_ACCESS_FIELDGET = 2; private static final int METHOD_ACCESS_FIELD_GET = 2;
private static final int METHOD_ACCESS_FIELDSET = 3; private static final int METHOD_ACCESS_FIELD_SET = 3;
private static final int METHOD_ACCESS_METHOD = 4; private static final int METHOD_ACCESS_METHOD = 4;
private boolean notSetSync; private boolean noSynthFlag;
private Map<MethodWrapper, Integer> mapMethodType = new HashMap<MethodWrapper, Integer>();
private HashMap<MethodWrapper, Integer> mapMethodType = new HashMap<MethodWrapper, Integer>();
public void propagateMemberAccess(ClassNode root) { public void propagateMemberAccess(ClassNode root) {
if (root.nested.isEmpty()) { if (root.nested.isEmpty()) {
return; return;
} }
notSetSync = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
computeMethodTypes(root); computeMethodTypes(root);
@ -60,7 +59,6 @@ public class NestedMemberAccess {
private void computeMethodTypes(ClassNode node) { private void computeMethodTypes(ClassNode node) {
if (node.type == ClassNode.CLASS_LAMBDA) { if (node.type == ClassNode.CLASS_LAMBDA) {
return; return;
} }
@ -69,27 +67,24 @@ public class NestedMemberAccess {
computeMethodTypes(nd); computeMethodTypes(nd);
} }
for (MethodWrapper meth : node.wrapper.getMethods()) { for (MethodWrapper method : node.wrapper.getMethods()) {
computeMethodType(node, meth); computeMethodType(node, method);
} }
} }
private void computeMethodType(ClassNode node, MethodWrapper meth) { private void computeMethodType(ClassNode node, MethodWrapper method) {
int type = METHOD_ACCESS_NORMAL; int type = METHOD_ACCESS_NORMAL;
if (meth.root != null) { if (method.root != null) {
DirectGraph graph = method.getOrBuildGraph();
DirectGraph graph = meth.getOrBuildGraph();
int flags = meth.methodStruct.getAccessFlags(); StructMethod mt = method.methodStruct;
if (((flags & CodeConstants.ACC_SYNTHETIC) != 0 || meth.methodStruct.getAttributes().containsKey("Synthetic") || notSetSync) && if ((noSynthFlag || mt.isSynthetic()) && mt.hasModifier(CodeConstants.ACC_STATIC)) {
(flags & CodeConstants.ACC_STATIC) != 0) {
if (graph.nodes.size() == 2) { // incl. dummy exit node if (graph.nodes.size() == 2) { // incl. dummy exit node
if (graph.first.exprents.size() == 1) { if (graph.first.exprents.size() == 1) {
Exprent exprent = graph.first.exprents.get(0); Exprent exprent = graph.first.exprents.get(0);
MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor()); MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(mt.getDescriptor());
int parcount = mtdesc.params.length; int parcount = mtdesc.params.length;
Exprent exprCore = exprent; Exprent exprCore = exprent;
@ -109,7 +104,7 @@ public class NestedMemberAccess {
if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
if (fexpr.isStatic() || if (fexpr.isStatic() ||
(fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) { (fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) {
type = METHOD_ACCESS_FIELDGET; type = METHOD_ACCESS_FIELD_GET;
} }
} }
} }
@ -118,7 +113,7 @@ public class NestedMemberAccess {
if (parcount == 1) { if (parcount == 1) {
// this or final variable // this or final variable
if (((VarExprent)exprCore).getIndex() != 0) { if (((VarExprent)exprCore).getIndex() != 0) {
type = METHOD_ACCESS_FIELDGET; type = METHOD_ACCESS_FIELD_GET;
} }
} }
@ -136,7 +131,7 @@ public class NestedMemberAccess {
if (fexpras.isStatic() || if (fexpras.isStatic() ||
(fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) { (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) { if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
type = METHOD_ACCESS_FIELDSET; type = METHOD_ACCESS_FIELD_SET;
} }
} }
} }
@ -179,7 +174,7 @@ public class NestedMemberAccess {
if (exprentFirst.type == Exprent.EXPRENT_ASSIGNMENT && if (exprentFirst.type == Exprent.EXPRENT_ASSIGNMENT &&
exprentSecond.type == Exprent.EXPRENT_EXIT) { exprentSecond.type == Exprent.EXPRENT_EXIT) {
MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor()); MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(mt.getDescriptor());
int parcount = mtdesc.params.length; int parcount = mtdesc.params.length;
AssignmentExprent asexpr = (AssignmentExprent)exprentFirst; AssignmentExprent asexpr = (AssignmentExprent)exprentFirst;
@ -196,7 +191,7 @@ public class NestedMemberAccess {
if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) { if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
if (exexpr.getValue().type == Exprent.EXPRENT_VAR && if (exexpr.getValue().type == Exprent.EXPRENT_VAR &&
((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) { ((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
type = METHOD_ACCESS_FIELDSET; type = METHOD_ACCESS_FIELD_SET;
} }
} }
} }
@ -211,10 +206,10 @@ public class NestedMemberAccess {
} }
if (type != METHOD_ACCESS_NORMAL) { if (type != METHOD_ACCESS_NORMAL) {
mapMethodType.put(meth, type); mapMethodType.put(method, type);
} }
else { else {
mapMethodType.remove(meth); mapMethodType.remove(method);
} }
} }
@ -365,7 +360,7 @@ public class NestedMemberAccess {
Exprent retexprent = null; Exprent retexprent = null;
switch (type) { switch (type) {
case METHOD_ACCESS_FIELDGET: case METHOD_ACCESS_FIELD_GET:
ExitExprent exsource = (ExitExprent)source; ExitExprent exsource = (ExitExprent)source;
if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
VarExprent var = (VarExprent)exsource.getValue(); VarExprent var = (VarExprent)exsource.getValue();
@ -393,7 +388,7 @@ public class NestedMemberAccess {
retexprent = ret; retexprent = ret;
} }
break; break;
case METHOD_ACCESS_FIELDSET: case METHOD_ACCESS_FIELD_SET:
AssignmentExprent ret; AssignmentExprent ret;
if (source.type == Exprent.EXPRENT_EXIT) { if (source.type == Exprent.EXPRENT_EXIT) {
ExitExprent extex = (ExitExprent)source; ExitExprent extex = (ExitExprent)source;
@ -440,7 +435,7 @@ public class NestedMemberAccess {
if (node.type == ClassNode.CLASS_ROOT || (node.access & CodeConstants.ACC_STATIC) != 0) { if (node.type == ClassNode.CLASS_ROOT || (node.access & CodeConstants.ACC_STATIC) != 0) {
StructMethod mt = methsource.methodStruct; StructMethod mt = methsource.methodStruct;
if ((mt.getAccessFlags() & CodeConstants.ACC_SYNTHETIC) == 0 && !mt.getAttributes().containsKey("Synthetic")) { if (!mt.isSynthetic()) {
hide = false; hide = false;
} }
} }

@ -82,7 +82,7 @@ public class IdeaNotNullHelper {
if (first_param.type == Exprent.EXPRENT_VAR) { if (first_param.type == Exprent.EXPRENT_VAR) {
VarExprent var = (VarExprent)first_param; VarExprent var = (VarExprent)first_param;
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes(); VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();

@ -109,43 +109,40 @@ public class AssignmentExprent extends Exprent {
VarType leftType = left.getExprType(); VarType leftType = left.getExprType();
VarType rightType = right.getExprType(); VarType rightType = right.getExprType();
String res = right.toJava(indent); boolean fieldInStatInit = false;
if (condtype == CONDITION_NONE &&
!leftType.isSuperset(rightType) &&
(rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) {
if (right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
res = "(" + res + ")";
}
res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res;
}
StringBuilder buffer = new StringBuilder();
boolean finstat_init = false;
if (left.type == Exprent.EXPRENT_FIELD) { // first assignment to a final field. Field name without "this" in front of it if (left.type == Exprent.EXPRENT_FIELD) { // first assignment to a final field. Field name without "this" in front of it
FieldExprent field = (FieldExprent)left; FieldExprent field = (FieldExprent)left;
if (field.isStatic()) { ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE));
ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)); if (node != null) {
if (node != null) { StructClass cl = node.classStruct;
StructClass cl = node.classStruct; StructField fd = cl.getField(field.getName(), field.getDescriptor().descriptorString);
StructField fd = cl.getField(field.getName(), field.getDescriptor().descriptorString); if (fd != null && field.isStatic() && fd.hasModifier(CodeConstants.ACC_FINAL)) {
fieldInStatInit = true;
if (fd != null && (fd.access_flags & CodeConstants.ACC_FINAL) != 0) {
finstat_init = true;
}
} }
} }
} }
if (finstat_init) { StringBuilder buffer = new StringBuilder();
if (fieldInStatInit) {
buffer.append(((FieldExprent)left).getName()); buffer.append(((FieldExprent)left).getName());
} }
else { else {
buffer.append(left.toJava(indent)); buffer.append(left.toJava(indent));
} }
String res = right.toJava(indent);
if (condtype == CONDITION_NONE &&
!leftType.isSuperset(rightType) &&
(rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) {
if (right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
res = "(" + res + ")";
}
res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res;
}
buffer.append(condtype == CONDITION_NONE ? " = " : funceq[condtype]).append(res); buffer.append(condtype == CONDITION_NONE ? " = " : funceq[condtype]).append(res);
return buffer.toString(); return buffer.toString();

@ -330,20 +330,19 @@ public class InvocationExprent extends Exprent {
List<VarVersionPaar> sigFields = null; List<VarVersionPaar> sigFields = null;
boolean isEnum = false; boolean isEnum = false;
if (functype == TYP_INIT) { if (functype == TYP_INIT) {
ClassNode newnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname); ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname);
if (newnode != null) { // own class if (newNode != null) { // own class
if (newnode.wrapper != null) { if (newNode.wrapper != null) {
sigFields = newnode.wrapper.getMethodWrapper("<init>", stringDescriptor).signatureFields; sigFields = newNode.wrapper.getMethodWrapper("<init>", stringDescriptor).signatureFields;
} }
else { else {
if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class
sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null)); sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null));
sigFields.set(0, new VarVersionPaar(-1, 0)); sigFields.set(0, new VarVersionPaar(-1, 0));
} }
} }
isEnum = (newnode.classStruct.access_flags & CodeConstants.ACC_ENUM) != 0 && isEnum = newNode.classStruct.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
} }
} }

@ -487,8 +487,7 @@ public class SSAConstructorSparseEx {
} }
private SFormsFastMapDirect createFirstMap(StructMethod mt) { private SFormsFastMapDirect createFirstMap(StructMethod mt) {
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());

@ -756,8 +756,7 @@ public class SSAUConstructorSparseEx {
} }
private SFormsFastMapDirect createFirstMap(StructMethod mt, RootStatement root) { private SFormsFastMapDirect createFirstMap(StructMethod mt, RootStatement root) {
boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0;
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());

@ -53,7 +53,7 @@ public class VarDefinitionHelper {
VarNamesCollector vc = DecompilerContext.getVarNamesCollector(); VarNamesCollector vc = DecompilerContext.getVarNamesCollector();
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());

@ -49,7 +49,7 @@ public class VarTypeProcessor {
StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD); StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD);
// method descriptor // method descriptor
boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
MethodDescriptor md = (MethodDescriptor)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR); MethodDescriptor md = (MethodDescriptor)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR);

@ -170,7 +170,7 @@ public class VarVersionsProcessor {
} }
} }
boolean is_method_static = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0; boolean is_method_static = mt.hasModifier(CodeConstants.ACC_STATIC);
final HashMap<VarVersionPaar, Integer> mapMergedVersions = new HashMap<VarVersionPaar, Integer>(); final HashMap<VarVersionPaar, Integer> mapMergedVersions = new HashMap<VarVersionPaar, Integer>();

@ -232,11 +232,10 @@ public class IdentifierConverter {
StructMethod mt = methods.get(i); StructMethod mt = methods.get(i);
String key = methods.getKey(i); String key = methods.getKey(i);
int access_flags = mt.getAccessFlags(); boolean isPrivate = mt.hasModifier(CodeConstants.ACC_PRIVATE);
boolean isPrivate = ((access_flags & CodeConstants.ACC_PRIVATE) != 0);
String name = mt.getName(); String name = mt.getName();
if (!cl.isOwn() || (access_flags & CodeConstants.ACC_NATIVE) != 0) { if (!cl.isOwn() || mt.hasModifier(CodeConstants.ACC_NATIVE)) {
// external and native methods must not be renamed // external and native methods must not be renamed
if (!isPrivate) { if (!isPrivate) {
names.put(key, name); names.put(key, name);
@ -426,8 +425,7 @@ public class IdentifierConverter {
break; break;
} }
else { else {
boolean isInterface = clstr.hasModifier(CodeConstants.ACC_INTERFACE);
boolean isInterface = ((clstr.access_flags & CodeConstants.ACC_INTERFACE) != 0);
boolean found_parent = false; boolean found_parent = false;
if (isInterface) { if (isInterface) {

@ -18,6 +18,7 @@ package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver; import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -98,7 +99,15 @@ public class ContextUnit {
List<StructClass> lstClasses = new ArrayList<StructClass>(); List<StructClass> lstClasses = new ArrayList<StructClass>();
for (StructClass cl : classes) { for (StructClass cl : classes) {
String oldname = cl.qualifiedName; String oldname = cl.qualifiedName;
StructClass newcl = new StructClass(loader.getClassStream(oldname), cl.isOwn(), loader);
StructClass newcl;
DataInputFullStream in = loader.getClassStream(oldname);
try {
newcl = new StructClass(in, cl.isOwn(), loader);
}
finally {
in.close();
}
lstClasses.add(newcl); lstClasses.add(newcl);

@ -16,7 +16,6 @@
package org.jetbrains.java.decompiler.struct; package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant; import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
@ -24,272 +23,127 @@ import org.jetbrains.java.decompiler.util.DataInputFullStream;
import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.VBStyleCollection; import org.jetbrains.java.decompiler.util.VBStyleCollection;
import java.io.*; import java.io.IOException;
import java.io.InputStream;
/* /*
ClassFile { class_file {
u4 magic; u4 magic;
u2 minor_version; u2 minor_version;
u2 major_version; u2 major_version;
u2 constant_pool_count; u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1]; cp_info constant_pool[constant_pool_count-1];
u2 access_flags; u2 access_flags;
u2 this_class; u2 this_class;
u2 super_class; u2 super_class;
u2 interfaces_count; u2 interfaces_count;
u2 interfaces[interfaces_count]; u2 interfaces[interfaces_count];
u2 fields_count; u2 fields_count;
field_info fields[fields_count]; field_info fields[fields_count];
u2 methods_count; u2 methods_count;
method_info methods[methods_count]; method_info methods[methods_count];
u2 attributes_count; u2 attributes_count;
attribute_info attributes[attributes_count]; attribute_info attributes[attributes_count];
} }
*/ */
public class StructClass extends StructMember {
public class StructClass { public final String qualifiedName;
public final PrimitiveConstant superClass;
// *****************************************************************************
// public fields
// *****************************************************************************
public int minor_version;
public int major_version;
public int access_flags;
public int this_class;
public int super_class; private final boolean own;
private final LazyLoader loader;
public PrimitiveConstant thisClass; private final int minorVersion;
private final int majorVersion;
public PrimitiveConstant superClass; private final int[] interfaces;
private final String[] interfaceNames;
public String qualifiedName; private final VBStyleCollection<StructField, String> fields;
private final VBStyleCollection<StructMethod, String> methods;
// *****************************************************************************
// private fields
// *****************************************************************************
private ConstantPool pool; private ConstantPool pool;
private int[] interfaces;
private String[] interfaceNames;
private VBStyleCollection<StructField, String> fields = new VBStyleCollection<StructField, String>();
private VBStyleCollection<StructMethod, String> methods = new VBStyleCollection<StructMethod, String>();
private VBStyleCollection<StructGeneralAttribute, String> attributes = new VBStyleCollection<StructGeneralAttribute, String>();
private boolean own = true;
private LazyLoader loader;
// *****************************************************************************
// constructors
// *****************************************************************************
public StructClass(String filename, boolean own, LazyLoader loader) throws IOException {
this(new FileInputStream(filename), own, loader);
}
public StructClass(InputStream inStream, boolean own, LazyLoader loader) throws IOException { public StructClass(InputStream inStream, boolean own, LazyLoader loader) throws IOException {
this(new DataInputFullStream(inStream), own, loader); this(new DataInputFullStream(inStream), own, loader);
} }
public StructClass(DataInputFullStream inStream, boolean own, LazyLoader loader) throws IOException { public StructClass(DataInputFullStream in, boolean own, LazyLoader loader) throws IOException {
this.own = own; this.own = own;
this.loader = loader; this.loader = loader;
initStruct(inStream); in.discard(4);
}
// *****************************************************************************
// public methods
// *****************************************************************************
public boolean hasField(String name, String descriptor) {
return getField(name, descriptor) != null;
}
public StructField getField(String name, String descriptor) {
return fields.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
}
public StructMethod getMethod(String key) {
return methods.getWithKey(key);
}
public StructMethod getMethod(String name, String descriptor) {
return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
}
public void writeToFile(File file) throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
writeToOutputStream(out);
out.close();
}
public void writeToOutputStream(DataOutputStream out) throws IOException {
out.writeInt(0xCAFEBABE);
out.writeShort(minor_version);
out.writeShort(major_version);
getPool().writeToOutputStream(out);
out.writeShort(access_flags);
out.writeShort(this_class);
out.writeShort(super_class);
out.writeShort(interfaces.length);
for (int i = 0; i < interfaces.length; i++) {
out.writeShort(interfaces[i]);
}
out.writeShort(fields.size());
for (int i = 0; i < fields.size(); i++) {
fields.get(i).writeToStream(out);
}
out.writeShort(methods.size());
for (int i = 0; i < methods.size(); i++) {
methods.get(i).writeToStream(out);
}
out.writeShort(attributes.size());
for (StructGeneralAttribute attr : attributes) {
attr.writeToStream(out);
}
}
public String getInterface(int i) {
return interfaceNames[i];
}
public void releaseResources() {
if (loader != null) {
pool = null;
}
}
// *****************************************************************************
// private methods
// *****************************************************************************
private void initStruct(DataInputFullStream in) throws IOException {
in.skip(4); minorVersion = in.readUnsignedShort();
majorVersion = in.readUnsignedShort();
this.minor_version = in.readUnsignedShort();
this.major_version = in.readUnsignedShort();
pool = new ConstantPool(in); pool = new ConstantPool(in);
this.access_flags = in.readUnsignedShort(); accessFlags = in.readUnsignedShort();
int thisClassIdx = in.readUnsignedShort();
this_class = in.readUnsignedShort(); int superClassIdx = in.readUnsignedShort();
thisClass = pool.getPrimitiveConstant(this_class); qualifiedName = pool.getPrimitiveConstant(thisClassIdx).getString();
qualifiedName = thisClass.getString(); superClass = pool.getPrimitiveConstant(superClassIdx);
super_class = in.readUnsignedShort();
superClass = pool.getPrimitiveConstant(super_class);
// interfaces // interfaces
int length = in.readUnsignedShort(); int length = in.readUnsignedShort();
int[] arrInterfaces = new int[length]; interfaces = new int[length];
String[] arrInterfaceNames = new String[length]; interfaceNames = new String[length];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
arrInterfaces[i] = in.readUnsignedShort(); interfaces[i] = in.readUnsignedShort();
arrInterfaceNames[i] = pool.getPrimitiveConstant(arrInterfaces[i]).getString(); interfaceNames[i] = pool.getPrimitiveConstant(interfaces[i]).getString();
} }
this.interfaces = arrInterfaces;
this.interfaceNames = arrInterfaceNames;
// fields // fields
VBStyleCollection<StructField, String> lstFields = new VBStyleCollection<StructField, String>();
length = in.readUnsignedShort(); length = in.readUnsignedShort();
fields = new VBStyleCollection<StructField, String>();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
StructField field = new StructField(); StructField field = new StructField(in, this);
field.access_flags = in.readUnsignedShort(); fields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
field.name_index = in.readUnsignedShort();
field.descriptor_index = in.readUnsignedShort();
field.initStrings(pool, this_class);
field.setAttributes(readAttributes(in));
lstFields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
} }
this.fields = lstFields;
// methods // methods
length = in.readUnsignedShort(); length = in.readUnsignedShort();
methods = new VBStyleCollection<StructMethod, String>();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
StructMethod meth = new StructMethod(in, own, this); StructMethod method = new StructMethod(in, this);
methods.addWithKey(method, InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor()));
//if(qualifiedName.endsWith("JUnitStatusLine") && !meth.getName().equals("onProcessStarted") && !meth.getName().startsWith("access")) {
//if(!meth.getName().equals("run")) {
// continue;
//}
methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(meth.getName(), meth.getDescriptor()));
} }
// attributes // attributes
this.attributes = readAttributes(in); attributes = readAttributes(in, pool);
// release memory releaseResources();
if (loader != null) {
pool = null;
}
} }
private VBStyleCollection<StructGeneralAttribute, String> readAttributes(DataInputFullStream in) throws IOException { public boolean hasField(String name, String descriptor) {
return getField(name, descriptor) != null;
}
VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>(); public StructField getField(String name, String descriptor) {
return fields.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
}
int length = in.readUnsignedShort(); public StructMethod getMethod(String key) {
for (int i = 0; i < length; i++) { return methods.getWithKey(key);
int attr_nameindex = in.readUnsignedShort(); }
String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
StructGeneralAttribute attr = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname);
if (attr != null) {
byte[] arr = new byte[in.readInt()];
in.readFull(arr);
attr.setInfo(arr);
attr.initContent(pool);
lstAttribute.addWithKey(attr, attr.getName());
}
else {
in.skip(in.readInt());
}
}
return lstAttribute; public StructMethod getMethod(String name, String descriptor) {
return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
} }
public String getInterface(int i) {
return interfaceNames[i];
}
// ***************************************************************************** public void releaseResources() {
// getter and setter methods if (loader != null) {
// ***************************************************************************** pool = null;
}
}
public ConstantPool getPool() { public ConstantPool getPool() {
if (pool == null && loader != null) { if (pool == null && loader != null) {
pool = loader.loadPool(qualifiedName); pool = loader.loadPool(qualifiedName);
} }
return pool; return pool;
} }
@ -309,10 +163,6 @@ public class StructClass {
return fields; return fields;
} }
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
return attributes;
}
public boolean isOwn() { public boolean isOwn() {
return own; return own;
} }
@ -322,15 +172,15 @@ public class StructClass {
} }
public boolean isVersionGE_1_5() { public boolean isVersionGE_1_5() {
return (major_version > 48 || (major_version == 48 && minor_version > 0)); // FIXME: check second condition return (majorVersion > 48 || (majorVersion == 48 && minorVersion > 0)); // FIXME: check second condition
} }
public boolean isVersionGE_1_7() { public boolean isVersionGE_1_7() {
return (major_version >= 51); return (majorVersion >= 51);
} }
public int getBytecodeVersion() { public int getBytecodeVersion() {
switch (major_version) { switch (majorVersion) {
case 52: case 52:
return CodeConstants.BYTECODE_JAVA_8; return CodeConstants.BYTECODE_JAVA_8;
case 51: case 51:

@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver; import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -136,7 +137,15 @@ public class StructContext {
if (filename.endsWith(".class")) { if (filename.endsWith(".class")) {
try { try {
StructClass cl = new StructClass(loader.getClassStream(file.getAbsolutePath(), null), isOwn, loader); StructClass cl;
DataInputFullStream in = loader.getClassStream(file.getAbsolutePath(), null);
try {
cl = new StructClass(in, isOwn, loader);
}
finally {
in.close();
}
classes.put(cl.qualifiedName, cl); classes.put(cl.qualifiedName, cl);
unit.addClass(cl, filename); unit.addClass(cl, filename);
@ -145,8 +154,8 @@ public class StructContext {
isClass = true; isClass = true;
} }
catch (IOException ex) { catch (IOException ex) {
DecompilerContext.getLogger() DecompilerContext.getLogger().writeMessage("Invalid class file: " + (path.length() > 0 ? path + "/" : "") + filename,
.writeMessage("Invalid class file: " + (path.length() > 0 ? path + "/" : "") + filename, IFernflowerLogger.ERROR); IFernflowerLogger.ERROR);
} }
} }

@ -15,96 +15,44 @@
*/ */
package org.jetbrains.java.decompiler.struct; package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.VBStyleCollection; import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
/* /*
field_info { field_info {
u2 access_flags; u2 access_flags;
u2 name_index; u2 name_index;
u2 descriptor_index; u2 descriptor_index;
u2 attributes_count; u2 attributes_count;
attribute_info attributes[attributes_count]; attribute_info attributes[attributes_count];
} }
*/ */
public class StructField extends StructMember {
public class StructField { private final String name;
private final String descriptor;
// *****************************************************************************
// public fields
// *****************************************************************************
public int access_flags; public StructField(DataInputFullStream in, StructClass clStruct) throws IOException {
public int name_index; accessFlags = in.readUnsignedShort();
public int descriptor_index; int nameIndex = in.readUnsignedShort();
int descriptorIndex = in.readUnsignedShort();
private String name; ConstantPool pool = clStruct.getPool();
private String descriptor; String[] values = pool.getClassElement(ConstantPool.FIELD, clStruct.qualifiedName, nameIndex, descriptorIndex);
// *****************************************************************************
// private fields
// *****************************************************************************
private VBStyleCollection<StructGeneralAttribute, String> attributes;
// *****************************************************************************
// constructors
// *****************************************************************************
public StructField() {
}
// *****************************************************************************
// public methods
// *****************************************************************************
public void writeToStream(DataOutputStream out) throws IOException {
out.writeShort(access_flags);
out.writeShort(name_index);
out.writeShort(descriptor_index);
out.writeShort(attributes.size());
for (StructGeneralAttribute attr : attributes) {
attr.writeToStream(out);
}
}
public void initStrings(ConstantPool pool, int class_index) {
String[] values = pool.getClassElement(ConstantPool.FIELD, class_index, name_index, descriptor_index);
name = values[0]; name = values[0];
descriptor = values[1]; descriptor = values[1];
}
// ***************************************************************************** attributes = readAttributes(in, pool);
// getter and setter methods
// *****************************************************************************
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
return attributes;
}
public void setAttributes(VBStyleCollection<StructGeneralAttribute, String> attributes) {
this.attributes = attributes;
}
public String getDescriptor() {
return descriptor;
}
public void setDescriptor(String descriptor) {
this.descriptor = descriptor;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) { public String getDescriptor() {
this.name = name; return descriptor;
} }
} }

@ -0,0 +1,87 @@
/*
* 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;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
import org.jetbrains.java.decompiler.util.VBStyleCollection;
import java.io.IOException;
public class StructMember {
protected int accessFlags;
protected VBStyleCollection<StructGeneralAttribute, String> attributes;
public int getAccessFlags() {
return accessFlags;
}
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
return attributes;
}
public boolean hasModifier(int modifier) {
return (accessFlags & modifier) == modifier;
}
public boolean isSynthetic() {
return hasModifier(CodeConstants.ACC_SYNTHETIC) || attributes.containsKey(StructGeneralAttribute.ATTRIBUTE_SYNTHETIC);
}
protected VBStyleCollection<StructGeneralAttribute, String> readAttributes(DataInputFullStream in, ConstantPool pool) throws IOException {
VBStyleCollection<StructGeneralAttribute, String> attributes = new VBStyleCollection<StructGeneralAttribute, String>();
int length = in.readUnsignedShort();
for (int i = 0; i < length; i++) {
int nameIndex = in.readUnsignedShort();
String name = pool.getPrimitiveConstant(nameIndex).getString();
StructGeneralAttribute attribute = readAttribute(in, pool, name);
if (attribute != null) {
if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(name)) {
// merge all variable tables
StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name);
table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
}
else {
attributes.addWithKey(attribute, attribute.getName());
}
}
}
return attributes;
}
protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name);
if (attribute == null) {
in.discard(in.readInt());
}
else {
byte[] data = new byte[in.readInt()];
in.readFull(data);
attribute.setInfo(data);
attribute.initContent(pool);
}
return attribute;
}
}

@ -17,267 +17,106 @@ package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.code.*; import org.jetbrains.java.decompiler.code.*;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
import org.jetbrains.java.decompiler.util.DataInputFullStream; import org.jetbrains.java.decompiler.util.DataInputFullStream;
import org.jetbrains.java.decompiler.util.VBStyleCollection; import org.jetbrains.java.decompiler.util.VBStyleCollection;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.jetbrains.java.decompiler.code.CodeConstants.*;
/* /*
method_info { method_info {
u2 access_flags; u2 access_flags;
u2 name_index; u2 name_index;
u2 descriptor_index; u2 descriptor_index;
u2 attributes_count; u2 attributes_count;
attribute_info attributes[attributes_count]; attribute_info attributes[attributes_count];
} }
*/ */
public class StructMethod extends StructMember {
public class StructMethod implements CodeConstants { private static final int[] opr_iconst = {-1, 0, 1, 2, 3, 4, 5};
private static final int[] opr_loadstore = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3};
// ***************************************************************************** private static final int[] opcs_load = {opc_iload, opc_lload, opc_fload, opc_dload, opc_aload};
// public fields private static final int[] opcs_store = {opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
// *****************************************************************************
public int name_index;
public int descriptor_index;
// *****************************************************************************
// private fields
// *****************************************************************************
private static final int[] opr_iconst = new int[]{-1, 0, 1, 2, 3, 4, 5};
private static final int[] opr_loadstore = new int[]{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3};
private static final int[] opcs_load = new int[]{opc_iload, opc_lload, opc_fload, opc_dload, opc_aload};
private static final int[] opcs_store = new int[]{opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
private int accessFlags;
private VBStyleCollection<StructGeneralAttribute, String> attributes; private final StructClass classStruct;
private final String name;
private int localVariables; private final String descriptor;
private int maxStack;
private String name;
private String descriptor;
private InstructionSequence seq;
private boolean containsCode = false; private boolean containsCode = false;
private int localVariables = 0;
private int codeLength = 0;
private int codeFullLength = 0;
private InstructionSequence seq;
private boolean expanded = false;
private StructClass classStruct;
// lazy properties
private boolean lazy;
private boolean expanded;
private byte[] code_content;
private int code_length = 0;
private int code_fulllength = 0;
// *****************************************************************************
// constructors
// *****************************************************************************
public StructMethod(DataInputFullStream in, boolean own, StructClass clstruct) throws IOException {
this(in, true, own, clstruct);
}
public StructMethod(DataInputFullStream in, boolean lazy, boolean own, StructClass clstruct) throws IOException {
this.lazy = lazy; public StructMethod(DataInputFullStream in, StructClass clStruct) throws IOException {
this.expanded = !lazy; classStruct = clStruct;
this.classStruct = clstruct;
accessFlags = in.readUnsignedShort(); accessFlags = in.readUnsignedShort();
name_index = in.readUnsignedShort(); int nameIndex = in.readUnsignedShort();
descriptor_index = in.readUnsignedShort(); int descriptorIndex = in.readUnsignedShort();
ConstantPool pool = clstruct.getPool();
initStrings(pool, clstruct.this_class);
VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>();
int len = in.readUnsignedShort();
for (int i = 0; i < len; i++) {
int attr_nameindex = in.readUnsignedShort();
String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) {
if (!own) {
// skip code in foreign classes
in.skip(8);
in.skip(in.readInt());
in.skip(8 * in.readUnsignedShort());
}
else {
containsCode = true;
in.skip(4);
maxStack = in.readUnsignedShort();
localVariables = in.readUnsignedShort();
if (lazy) {
code_length = in.readInt();
in.skip(code_length); ConstantPool pool = clStruct.getPool();
String[] values = pool.getClassElement(ConstantPool.METHOD, clStruct.qualifiedName, nameIndex, descriptorIndex);
int exc_length = in.readUnsignedShort(); name = values[0];
code_fulllength = code_length + exc_length * 8 + 2; descriptor = values[1];
in.skip(exc_length * 8);
}
else {
seq = parseBytecode(in, in.readInt(), pool);
}
}
// code attributes
int length = in.readUnsignedShort();
for (int j = 0; j < length; j++) {
int codeattr_nameindex = in.readUnsignedShort();
String codeattrname = pool.getPrimitiveConstant(codeattr_nameindex).getString();
readAttribute(in, pool, lstAttribute, codeattr_nameindex, codeattrname);
}
}
else {
readAttribute(in, pool, lstAttribute, attr_nameindex, attrname);
}
}
attributes = lstAttribute; attributes = readAttributes(in, pool);
} }
@Override
// ***************************************************************************** protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
// public methods if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(name)) {
// ***************************************************************************** if (!classStruct.isOwn()) {
// skip code in foreign classes
public void writeToStream(DataOutputStream out) throws IOException { in.discard(8);
in.discard(in.readInt());
out.writeShort(accessFlags); in.discard(8 * in.readUnsignedShort());
out.writeShort(name_index);
out.writeShort(descriptor_index);
out.writeShort(attributes.size());
for (StructGeneralAttribute attr : attributes) {
if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attr.getName())) {
out.writeShort(attr.getAttribute_name_index());
if (lazy && !expanded) {
out.writeInt(10 + code_content.length);
out.writeShort(maxStack);
out.writeShort(localVariables);
out.writeInt(code_length);
out.write(code_content);
}
else {
ByteArrayOutputStream codeout = new ByteArrayOutputStream();
seq.writeCodeToStream(new DataOutputStream(codeout));
ByteArrayOutputStream excout = new ByteArrayOutputStream();
seq.writeExceptionsToStream(new DataOutputStream(excout));
out.writeInt(10 + codeout.size() + excout.size());
out.writeShort(maxStack);
out.writeShort(localVariables);
out.writeInt(codeout.size());
codeout.writeTo(out);
excout.writeTo(out);
}
// no attributes
out.writeShort(0);
} }
else { else {
attr.writeToStream(out); containsCode = true;
in.discard(6);
localVariables = in.readUnsignedShort();
codeLength = in.readInt();
in.discard(codeLength);
int exc_length = in.readUnsignedShort();
in.discard(exc_length * 8);
codeFullLength = codeLength + exc_length * 8 + 2;
} }
}
}
private static void readAttribute(DataInputFullStream in,
ConstantPool pool,
VBStyleCollection<StructGeneralAttribute, String> lstAttribute,
int attr_nameindex,
String attrname) throws IOException {
StructGeneralAttribute attribute = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname); LazyLoader.skipAttributes(in);
if (attribute != null) { return null;
attrname = attribute.getName();
byte[] arr = new byte[in.readInt()];
in.readFull(arr);
attribute.setInfo(arr);
attribute.initContent(pool);
if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname) &&
lstAttribute.containsKey(attrname)) {
// merge all variable tables
StructLocalVariableTableAttribute oldattr = (StructLocalVariableTableAttribute)lstAttribute.getWithKey(attrname);
oldattr.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
}
else {
lstAttribute.addWithKey(attribute, attribute.getName());
}
}
else {
in.skip(in.readInt());
} }
}
private void initStrings(ConstantPool pool, int class_index) { return super.readAttribute(in, pool, name);
String[] values = pool.getClassElement(ConstantPool.METHOD, class_index, name_index, descriptor_index);
name = values[0];
descriptor = values[1];
} }
public void expandData() throws IOException { public void expandData() throws IOException {
if (containsCode && lazy && !expanded) { if (containsCode && !expanded) {
byte[] code = classStruct.getLoader().loadBytecode(this, codeFullLength);
byte[] codearr = classStruct.getLoader().loadBytecode(this, code_fulllength); seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(code)), codeLength, classStruct.getPool());
seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(codearr)), code_length, classStruct.getPool());
expanded = true; expanded = true;
} }
} }
public void releaseResources() throws IOException { public void releaseResources() throws IOException {
if (containsCode && lazy && expanded) { if (containsCode && expanded) {
seq = null; seq = null;
expanded = false; expanded = false;
} }
} }
// *****************************************************************************
// private methods
// *****************************************************************************
private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException { private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException {
VBStyleCollection<Instruction, Integer> instructions = new VBStyleCollection<Instruction, Integer>();
VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
int bytecode_version = classStruct.getBytecodeVersion(); int bytecode_version = classStruct.getBytecodeVersion();
@ -370,7 +209,7 @@ public class StructMethod implements CodeConstants {
case opc_invokedynamic: case opc_invokedynamic:
if (classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before if (classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before
operands.add(new Integer(in.readUnsignedShort())); operands.add(new Integer(in.readUnsignedShort()));
in.skip(2); in.discard(2);
group = GROUP_INVOCATION; group = GROUP_INVOCATION;
i += 4; i += 4;
} }
@ -420,7 +259,7 @@ public class StructMethod implements CodeConstants {
case opc_invokeinterface: case opc_invokeinterface:
operands.add(new Integer(in.readUnsignedShort())); operands.add(new Integer(in.readUnsignedShort()));
operands.add(new Integer(in.readUnsignedByte())); operands.add(new Integer(in.readUnsignedByte()));
in.skip(1); in.discard(1);
group = GROUP_INVOCATION; group = GROUP_INVOCATION;
i += 4; i += 4;
break; break;
@ -430,7 +269,7 @@ public class StructMethod implements CodeConstants {
i += 3; i += 3;
break; break;
case opc_tableswitch: case opc_tableswitch:
in.skip((4 - (i + 1) % 4) % 4); in.discard((4 - (i + 1) % 4) % 4);
i += ((4 - (i + 1) % 4) % 4); // padding i += ((4 - (i + 1) % 4) % 4); // padding
operands.add(new Integer(in.readInt())); operands.add(new Integer(in.readInt()));
i += 4; i += 4;
@ -449,7 +288,7 @@ public class StructMethod implements CodeConstants {
break; break;
case opc_lookupswitch: case opc_lookupswitch:
in.skip((4 - (i + 1) % 4) % 4); in.discard((4 - (i + 1) % 4) % 4);
i += ((4 - (i + 1) % 4) % 4); // padding i += ((4 - (i + 1) % 4) % 4); // padding
operands.add(new Integer(in.readInt())); operands.add(new Integer(in.readInt()));
i += 4; i += 4;
@ -483,7 +322,7 @@ public class StructMethod implements CodeConstants {
Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops); Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops);
collinstr.addWithKey(instr, new Integer(offset)); instructions.addWithKey(instr, new Integer(offset));
i++; i++;
} }
@ -507,7 +346,7 @@ public class StructMethod implements CodeConstants {
lstHandlers.add(handler); lstHandlers.add(handler);
} }
InstructionSequence seq = new FullInstructionSequence(collinstr, new ExceptionTable(lstHandlers)); InstructionSequence seq = new FullInstructionSequence(instructions, new ExceptionTable(lstHandlers));
// initialize instructions // initialize instructions
int i = seq.length() - 1; int i = seq.length() - 1;
@ -524,41 +363,27 @@ public class StructMethod implements CodeConstants {
return seq; return seq;
} }
// ***************************************************************************** public StructClass getClassStruct() {
// getter and setter methods return classStruct;
// ***************************************************************************** }
public InstructionSequence getInstructionSequence() { public String getName() {
return seq; return name;
} }
public String getDescriptor() { public String getDescriptor() {
return descriptor; return descriptor;
} }
public String getName() { public boolean containsCode() {
return name; return containsCode;
}
public int getAccessFlags() {
return accessFlags;
} }
public int getLocalVariables() { public int getLocalVariables() {
return localVariables; return localVariables;
} }
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() { public InstructionSequence getInstructionSequence() {
return attributes; return seq;
}
public StructClass getClassStruct() {
return classStruct;
}
public boolean containsCode() {
return containsCode;
} }
} }

@ -17,9 +17,6 @@ package org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -38,30 +35,6 @@ public class StructExceptionsAttribute extends StructGeneralAttribute {
} }
} }
public void writeToStream(DataOutputStream out) throws IOException {
out.writeShort(attribute_name_index);
ByteArrayOutputStream codeout = new ByteArrayOutputStream();
DataOutputStream dataout = new DataOutputStream(codeout);
int len = throwsExceptions.size();
dataout.writeShort(len);
if (len > 0) {
info = new byte[len * 2];
for (int i = 0, j = 0; i < len; i++, j += 2) {
int index = throwsExceptions.get(i).intValue();
info[j] = (byte)(index >> 8);
info[j + 1] = (byte)(index & 0xFF);
}
dataout.write(info);
}
out.writeInt(codeout.size());
out.write(codeout.toByteArray());
}
public String getExcClassname(int index, ConstantPool pool) { public String getExcClassname(int index, ConstantPool pool) {
return pool.getPrimitiveConstant(throwsExceptions.get(index).intValue()).getString(); return pool.getPrimitiveConstant(throwsExceptions.get(index).intValue()).getString();
} }

@ -17,17 +17,13 @@ package org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import java.io.DataOutputStream;
import java.io.IOException;
/* /*
attribute_info { attribute_info {
u2 attribute_name_index; u2 attribute_name_index;
u4 attribute_length; u4 attribute_length;
u1 info[attribute_length]; u1 info[attribute_length];
} }
*/ */
public class StructGeneralAttribute { public class StructGeneralAttribute {
public static final String ATTRIBUTE_CODE = "Code"; public static final String ATTRIBUTE_CODE = "Code";
@ -48,74 +44,51 @@ public class StructGeneralAttribute {
public static final String ATTRIBUTE_SYNTHETIC = "Synthetic"; public static final String ATTRIBUTE_SYNTHETIC = "Synthetic";
public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; public static final String ATTRIBUTE_DEPRECATED = "Deprecated";
// *****************************************************************************
// private fields
// *****************************************************************************
protected int attribute_name_index;
protected byte[] info;
protected String name; protected String name;
protected byte[] info;
// *****************************************************************************
// public methods
// *****************************************************************************
public void writeToStream(DataOutputStream out) throws IOException {
out.writeShort(attribute_name_index);
out.writeInt(info.length);
if (info.length > 0) {
out.write(info);
}
}
public void initContent(ConstantPool pool) {
name = pool.getPrimitiveConstant(attribute_name_index).getString();
}
public static StructGeneralAttribute getMatchingAttributeInstance(int nameindex, String attrname) {
public static StructGeneralAttribute createAttribute(String name) {
StructGeneralAttribute attr; StructGeneralAttribute attr;
if (ATTRIBUTE_INNER_CLASSES.equals(attrname)) { if (ATTRIBUTE_INNER_CLASSES.equals(name)) {
attr = new StructInnerClassesAttribute(); attr = new StructInnerClassesAttribute();
} }
else if (ATTRIBUTE_CONSTANT_VALUE.equals(attrname)) { else if (ATTRIBUTE_CONSTANT_VALUE.equals(name)) {
attr = new StructConstantValueAttribute(); attr = new StructConstantValueAttribute();
} }
else if (ATTRIBUTE_SIGNATURE.equals(attrname)) { else if (ATTRIBUTE_SIGNATURE.equals(name)) {
attr = new StructGenericSignatureAttribute(); attr = new StructGenericSignatureAttribute();
} }
else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(attrname)) { else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(name)) {
attr = new StructAnnDefaultAttribute(); attr = new StructAnnDefaultAttribute();
} }
else if (ATTRIBUTE_EXCEPTIONS.equals(attrname)) { else if (ATTRIBUTE_EXCEPTIONS.equals(name)) {
attr = new StructExceptionsAttribute(); attr = new StructExceptionsAttribute();
} }
else if (ATTRIBUTE_ENCLOSING_METHOD.equals(attrname)) { else if (ATTRIBUTE_ENCLOSING_METHOD.equals(name)) {
attr = new StructEnclosingMethodAttribute(); attr = new StructEnclosingMethodAttribute();
} }
else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(attrname) || else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(name) ||
ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(attrname)) { ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(name)) {
attr = new StructAnnotationAttribute(); attr = new StructAnnotationAttribute();
} }
else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attrname) || else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(name) ||
ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attrname)) { ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(name)) {
attr = new StructAnnotationParameterAttribute(); attr = new StructAnnotationParameterAttribute();
} }
else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attrname) || else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(name) ||
ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attrname)) { ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(name)) {
attr = new StructAnnotationTypeAttribute(); attr = new StructAnnotationTypeAttribute();
} }
else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname)) { else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name)) {
attr = new StructLocalVariableTableAttribute(); attr = new StructLocalVariableTableAttribute();
} }
else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(attrname)) { else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(name)) {
attr = new StructBootstrapMethodsAttribute(); attr = new StructBootstrapMethodsAttribute();
} }
else if (ATTRIBUTE_SYNTHETIC.equals(attrname) || ATTRIBUTE_DEPRECATED.equals(attrname)) { else if (ATTRIBUTE_SYNTHETIC.equals(name) ||
ATTRIBUTE_DEPRECATED.equals(name)) {
attr = new StructGeneralAttribute(); attr = new StructGeneralAttribute();
} }
else { else {
@ -123,17 +96,11 @@ public class StructGeneralAttribute {
return null; return null;
} }
attr.setAttribute_name_index(nameindex); attr.name = name;
return attr; return attr;
} }
// ***************************************************************************** public void initContent(ConstantPool pool) { }
// getter and setter methods
// *****************************************************************************
public byte[] getInfo() {
return info;
}
public void setInfo(byte[] info) { public void setInfo(byte[] info) {
this.info = info; this.info = info;
@ -142,16 +109,4 @@ public class StructGeneralAttribute {
public String getName() { public String getName() {
return name; return name;
} }
public void setName(String name) {
this.name = name;
}
public int getAttribute_name_index() {
return attribute_name_index;
}
public void setAttribute_name_index(int attribute_name_index) {
this.attribute_name_index = attribute_name_index;
}
} }

@ -21,9 +21,9 @@ import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType; import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -31,25 +31,14 @@ import java.util.List;
public class ConstantPool { public class ConstantPool {
public static final int FIELD = 1; public static final int FIELD = 1;
public static final int METHOD = 2; public static final int METHOD = 2;
// *****************************************************************************
// private fields
// *****************************************************************************
private List<PooledConstant> pool = new ArrayList<PooledConstant>(); private List<PooledConstant> pool = new ArrayList<PooledConstant>();
private PoolInterceptor interceptor; private PoolInterceptor interceptor;
// *****************************************************************************
// constructors
// *****************************************************************************
public ConstantPool(DataInputStream in) throws IOException { public ConstantPool(DataInputStream in) throws IOException {
int size = in.readUnsignedShort(); int size = in.readUnsignedShort();
int[] pass = new int[size]; int[] pass = new int[size];
// first dummy constant // first dummy constant
@ -57,7 +46,6 @@ public class ConstantPool {
// first pass: read the elements // first pass: read the elements
for (int i = 1; i < size; i++) { for (int i = 1; i < size; i++) {
byte tag = (byte)in.readUnsignedByte(); byte tag = (byte)in.readUnsignedByte();
switch (tag) { switch (tag) {
@ -106,11 +94,10 @@ public class ConstantPool {
} }
} }
// resolving complex pool elements // resolving complex pool elements
for (int pass_index = 1; pass_index <= 3; pass_index++) { for (int passIndex = 1; passIndex <= 3; passIndex++) {
for (int i = 1; i < size; i++) { for (int i = 1; i < size; i++) {
if (pass[i] == pass_index) { if (pass[i] == passIndex) {
pool.get(i).resolveConstant(this); pool.get(i).resolveConstant(this);
} }
} }
@ -120,23 +107,7 @@ public class ConstantPool {
interceptor = DecompilerContext.getPoolInterceptor(); interceptor = DecompilerContext.getPoolInterceptor();
} }
// ***************************************************************************** public static void skipPool(DataInputFullStream in) throws IOException {
// public methods
// *****************************************************************************
public void writeToOutputStream(DataOutputStream out) throws IOException {
out.writeShort(pool.size());
for (int i = 1; i < pool.size(); i++) {
PooledConstant cnst = pool.get(i);
if (cnst != null) {
cnst.writeToStream(out);
}
}
}
public static void skipPool(DataInputStream in) throws IOException {
int size = in.readUnsignedShort(); int size = in.readUnsignedShort();
for (int i = 1; i < size; i++) { for (int i = 1; i < size; i++) {
@ -151,20 +122,20 @@ public class ConstantPool {
case CodeConstants.CONSTANT_InterfaceMethodref: case CodeConstants.CONSTANT_InterfaceMethodref:
case CodeConstants.CONSTANT_NameAndType: case CodeConstants.CONSTANT_NameAndType:
case CodeConstants.CONSTANT_InvokeDynamic: case CodeConstants.CONSTANT_InvokeDynamic:
in.skip(4); in.discard(4);
break; break;
case CodeConstants.CONSTANT_Long: case CodeConstants.CONSTANT_Long:
case CodeConstants.CONSTANT_Double: case CodeConstants.CONSTANT_Double:
in.skip(8); in.discard(8);
i++; i++;
break; break;
case CodeConstants.CONSTANT_Class: case CodeConstants.CONSTANT_Class:
case CodeConstants.CONSTANT_String: case CodeConstants.CONSTANT_String:
case CodeConstants.CONSTANT_MethodType: case CodeConstants.CONSTANT_MethodType:
in.skip(2); in.discard(2);
break; break;
case CodeConstants.CONSTANT_MethodHandle: case CodeConstants.CONSTANT_MethodHandle:
in.skip(3); in.discard(3);
} }
} }
} }
@ -173,27 +144,24 @@ public class ConstantPool {
return pool.size(); return pool.size();
} }
public String[] getClassElement(int element_type, int class_index, int name_index, int descriptor_index) { public String[] getClassElement(int elementType, String className, int nameIndex, int descriptorIndex) {
String elementName = ((PrimitiveConstant)getConstant(nameIndex)).getString();
String classname = ((PrimitiveConstant)getConstant(class_index)).getString(); String descriptor = ((PrimitiveConstant)getConstant(descriptorIndex)).getString();
String elementname = ((PrimitiveConstant)getConstant(name_index)).getString();
String descriptor = ((PrimitiveConstant)getConstant(descriptor_index)).getString();
if (interceptor != null) { if (interceptor != null) {
String new_element = interceptor.getName(classname + " " + elementname + " " + descriptor); String newElement = interceptor.getName(className + " " + elementName + " " + descriptor);
if (newElement != null) {
if (new_element != null) { elementName = newElement.split(" ")[1];
elementname = new_element.split(" ")[1];
} }
String new_descriptor = buildNewDescriptor(element_type == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref, int type = elementType == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref;
descriptor); String newDescriptor = buildNewDescriptor(type, descriptor);
if (new_descriptor != null) { if (newDescriptor != null) {
descriptor = new_descriptor; descriptor = newDescriptor;
} }
} }
return new String[]{elementname, descriptor}; return new String[]{elementName, descriptor};
} }
public PooledConstant getConstant(int index) { public PooledConstant getConstant(int index) {
@ -205,9 +173,9 @@ public class ConstantPool {
if (cn != null && interceptor != null) { if (cn != null && interceptor != null) {
if (cn.type == CodeConstants.CONSTANT_Class) { if (cn.type == CodeConstants.CONSTANT_Class) {
String newname = buildNewClassname(cn.getString()); String newName = buildNewClassname(cn.getString());
if (newname != null) { if (newName != null) {
cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newname); cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newName);
} }
} }
} }
@ -218,33 +186,30 @@ public class ConstantPool {
public LinkConstant getLinkConstant(int index) { public LinkConstant getLinkConstant(int index) {
LinkConstant ln = (LinkConstant)getConstant(index); LinkConstant ln = (LinkConstant)getConstant(index);
if (ln != null && interceptor != null) { if (ln != null && interceptor != null &&
if (ln.type == CodeConstants.CONSTANT_Fieldref || (ln.type == CodeConstants.CONSTANT_Fieldref ||
ln.type == CodeConstants.CONSTANT_Methodref || ln.type == CodeConstants.CONSTANT_Methodref ||
ln.type == CodeConstants.CONSTANT_InterfaceMethodref) { ln.type == CodeConstants.CONSTANT_InterfaceMethodref)) {
String newClassName = buildNewClassname(ln.classname);
String new_classname = buildNewClassname(ln.classname); String newElement = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor);
String new_element = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor); String newDescriptor = buildNewDescriptor(ln.type, ln.descriptor);
String new_descriptor = buildNewDescriptor(ln.type, ln.descriptor);
if (newClassName != null || newElement != null || newDescriptor != null) {
if (new_classname != null || new_element != null || new_descriptor != null) { String className = newClassName == null ? ln.classname : newClassName;
String elementName = newElement == null ? ln.elementname : newElement.split(" ")[1];
ln = new LinkConstant(ln.type, new_classname == null ? ln.classname : new_classname, String descriptor = newDescriptor == null ? ln.descriptor : newDescriptor;
new_element == null ? ln.elementname : new_element.split(" ")[1], ln = new LinkConstant(ln.type, className, elementName, descriptor);
new_descriptor == null ? ln.descriptor : new_descriptor);
}
} }
} }
return ln; return ln;
} }
private String buildNewClassname(String classname) { private String buildNewClassname(String className) {
VarType vt = new VarType(className, true);
VarType vt = new VarType(classname, true);
String newname = interceptor.getName(vt.value); String newName = interceptor.getName(vt.value);
if (newname != null) { if (newName != null) {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
if (vt.arraydim > 0) { if (vt.arraydim > 0) {
@ -252,10 +217,10 @@ public class ConstantPool {
buffer.append("["); buffer.append("[");
} }
buffer.append("L").append(newname).append(";"); buffer.append("L").append(newName).append(";");
} }
else { else {
buffer.append(newname); buffer.append(newName);
} }
return buffer.toString(); return buffer.toString();
@ -265,17 +230,16 @@ public class ConstantPool {
} }
private String buildNewDescriptor(int type, String descriptor) { private String buildNewDescriptor(int type, String descriptor) {
boolean updated = false; boolean updated = false;
if (type == CodeConstants.CONSTANT_Fieldref) { if (type == CodeConstants.CONSTANT_Fieldref) {
FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor); FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor);
VarType ftype = fd.type; VarType fType = fd.type;
if (ftype.type == CodeConstants.TYPE_OBJECT) { if (fType.type == CodeConstants.TYPE_OBJECT) {
String newclname = buildNewClassname(ftype.value); String newClassName = buildNewClassname(fType.value);
if (newclname != null) { if (newClassName != null) {
ftype.value = newclname; fType.value = newClassName;
updated = true; updated = true;
} }
} }
@ -285,14 +249,14 @@ public class ConstantPool {
} }
} }
else { else {
MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor); MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
// params
for (VarType partype : md.params) { // parameters
if (partype.type == CodeConstants.TYPE_OBJECT) { for (VarType paramType : md.params) {
String newclname = buildNewClassname(partype.value); if (paramType.type == CodeConstants.TYPE_OBJECT) {
if (newclname != null) { String newClassName = buildNewClassname(paramType.value);
partype.value = newclname; if (newClassName != null) {
paramType.value = newClassName;
updated = true; updated = true;
} }
} }
@ -300,9 +264,9 @@ public class ConstantPool {
// return value // return value
if (md.ret.type == CodeConstants.TYPE_OBJECT) { if (md.ret.type == CodeConstants.TYPE_OBJECT) {
String newclname = buildNewClassname(md.ret.value); String newClassName = buildNewClassname(md.ret.value);
if (newclname != null) { if (newClassName != null) {
md.ret.value = newclname; md.ret.value = newClassName;
updated = true; updated = true;
} }
} }

@ -65,7 +65,7 @@ public class DataPoint {
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
int k = 0; int k = 0;
if ((mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0) { if (!mt.hasModifier(CodeConstants.ACC_STATIC)) {
point.setVariable(k++, new VarType(CodeConstants.TYPE_OBJECT, 0, null)); point.setVariable(k++, new VarType(CodeConstants.TYPE_OBJECT, 0, null));
} }

@ -24,11 +24,11 @@ import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
public class LazyLoader { public class LazyLoader {
private HashMap<String, Link> mapClassLinks = new HashMap<String, Link>(); private Map<String, Link> mapClassLinks = new HashMap<String, Link>();
private IBytecodeProvider provider; private IBytecodeProvider provider;
public LazyLoader(IBytecodeProvider provider) { public LazyLoader(IBytecodeProvider provider) {
@ -47,98 +47,88 @@ public class LazyLoader {
return mapClassLinks.get(classname); return mapClassLinks.get(classname);
} }
public ConstantPool loadPool(String classname) { public ConstantPool loadPool(String classname) {
try { try {
DataInputFullStream in = getClassStream(classname); DataInputFullStream in = getClassStream(classname);
if (in == null) { if (in == null) return null;
return null;
}
in.skip(8);
return new ConstantPool(in); try {
in.discard(8);
return new ConstantPool(in);
}
finally {
in.close();
}
} }
catch (IOException ex) { catch (IOException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
} }
public byte[] loadBytecode(StructMethod mt, int code_fulllength) { public byte[] loadBytecode(StructMethod mt, int codeFullLength) {
String className = mt.getClassStruct().qualifiedName;
try { try {
DataInputFullStream in = getClassStream(className);
if (in == null) return null;
DataInputFullStream in = getClassStream(mt.getClassStruct().qualifiedName); try {
if (in == null) { in.discard(8);
return null;
}
byte[] res = null;
in.skip(8);
ConstantPool pool = mt.getClassStruct().getPool();
if (pool == null) {
pool = new ConstantPool(in);
}
else {
ConstantPool.skipPool(in);
}
in.skip(2); ConstantPool pool = mt.getClassStruct().getPool();
int this_class = in.readUnsignedShort(); if (pool == null) {
in.skip(2); pool = new ConstantPool(in);
}
// interfaces else {
in.skip(in.readUnsignedShort() * 2); ConstantPool.skipPool(in);
}
// fields
int size = in.readUnsignedShort();
for (int i = 0; i < size; i++) {
in.skip(6);
skipAttributes(in);
}
// methods
size = in.readUnsignedShort();
for (int i = 0; i < size; i++) {
in.skip(2);
int name_index = in.readUnsignedShort(); in.discard(6);
int descriptor_index = in.readUnsignedShort();
String[] elem_arr = pool.getClassElement(ConstantPool.METHOD, this_class, name_index, descriptor_index); // interfaces
String name = elem_arr[0]; in.discard(in.readUnsignedShort() * 2);
if (mt.getName().equals(name)) { // fields
String descriptor = elem_arr[1]; int size = in.readUnsignedShort();
if (mt.getDescriptor().equals(descriptor)) { for (int i = 0; i < size; i++) {
in.discard(6);
skipAttributes(in);
}
int len = in.readUnsignedShort(); // methods
for (int j = 0; j < len; j++) { size = in.readUnsignedShort();
for (int i = 0; i < size; i++) {
in.discard(2);
int attr_nameindex = in.readUnsignedShort(); int nameIndex = in.readUnsignedShort();
String attrname = pool.getPrimitiveConstant(attr_nameindex).getString(); int descriptorIndex = in.readUnsignedShort();
if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) { String[] values = pool.getClassElement(ConstantPool.METHOD, className, nameIndex, descriptorIndex);
in.skip(12); if (!mt.getName().equals(values[0]) || !mt.getDescriptor().equals(values[1])) {
skipAttributes(in);
continue;
}
res = new byte[code_fulllength]; int attrSize = in.readUnsignedShort();
in.readFull(res); for (int j = 0; j < attrSize; j++) {
return res; int attrNameIndex = in.readUnsignedShort();
} String attrName = pool.getPrimitiveConstant(attrNameIndex).getString();
else { if (!StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrName)) {
in.skip(in.readInt()); in.discard(in.readInt());
} continue;
} }
return null; in.discard(12);
byte[] code = new byte[codeFullLength];
in.readFull(code);
return code;
} }
}
skipAttributes(in); break;
}
}
finally {
in.close();
} }
return null; return null;
@ -148,39 +138,38 @@ public class LazyLoader {
} }
} }
public DataInputFullStream getClassStream(String externPath, String internPath) throws IOException { @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
InputStream instream = provider.getBytecodeStream(externPath, internPath); public DataInputFullStream getClassStream(String externalPath, String internalPath) throws IOException {
return instream == null ? null : new DataInputFullStream(instream); InputStream stream = provider.getBytecodeStream(externalPath, internalPath);
return stream == null ? null : new DataInputFullStream(stream);
} }
public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException { public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException {
Link link = mapClassLinks.get(qualifiedClassName); Link link = mapClassLinks.get(qualifiedClassName);
return link == null ? null : getClassStream(link.externPath, link.internPath); return link == null ? null : getClassStream(link.externalPath, link.internalPath);
} }
private static void skipAttributes(DataInputFullStream in) throws IOException { public static void skipAttributes(DataInputFullStream in) throws IOException {
int length = in.readUnsignedShort(); int length = in.readUnsignedShort();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
in.skip(2); in.discard(2);
in.skip(in.readInt()); in.discard(in.readInt());
} }
} }
public static class Link { public static class Link {
public static final int CLASS = 1; public static final int CLASS = 1;
public static final int ENTRY = 2; public static final int ENTRY = 2;
public int type; public int type;
public String externPath; public String externalPath;
public String internPath; public String internalPath;
public Link(int type, String externPath, String internPath) { public Link(int type, String externalPath, String internalPath) {
this.type = type; this.type = type;
this.externPath = externPath; this.externalPath = externalPath;
this.internPath = internPath; this.internalPath = internalPath;
} }
} }
} }

@ -25,20 +25,19 @@ public class DataInputFullStream extends DataInputStream {
super(in); super(in);
} }
public final int readFull(byte[] b) throws IOException { public int readFull(byte[] b) throws IOException {
int length = b.length; int length = b.length;
byte[] btemp = new byte[length]; byte[] temp = new byte[length];
int pos = 0; int pos = 0;
int bytes_read = -1; int bytes_read;
while (true) { while (true) {
bytes_read = read(btemp, 0, length - pos); bytes_read = read(temp, 0, length - pos);
if (bytes_read == -1) { if (bytes_read == -1) {
return -1; return -1;
} }
System.arraycopy(btemp, 0, b, pos, bytes_read); System.arraycopy(temp, 0, b, pos, bytes_read);
pos += bytes_read; pos += bytes_read;
if (pos == length) { if (pos == length) {
break; break;
@ -47,4 +46,10 @@ public class DataInputFullStream extends DataInputStream {
return length; return length;
} }
public void discard(int n) throws IOException {
if (super.skip(n) != n) {
throw new IOException("Skip failed");
}
}
} }

@ -33,9 +33,11 @@ public class SingleClassesTest {
@Before @Before
public void setUp() throws IOException { public void setUp() throws IOException {
//noinspection SSBasedInspection
tempDir = File.createTempFile("decompiler_test_", "_dir"); tempDir = File.createTempFile("decompiler_test_", "_dir");
assertTrue(tempDir.delete()); assertTrue(tempDir.delete());
assertTrue(tempDir.mkdirs()); assertTrue(tempDir.mkdirs());
decompiler = new ConsoleDecompiler(new HashMap<String, Object>() {{ decompiler = new ConsoleDecompiler(new HashMap<String, Object>() {{
put(IFernflowerPreferences.LOG_LEVEL, "warn"); put(IFernflowerPreferences.LOG_LEVEL, "warn");
put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1"); put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1");

Loading…
Cancel
Save