[java decompiler] minor refactoring + cleanup (duplicates; dependencies; test data layout; typos; formatting)

GitOrigin-RevId: 3589e4d8f2dfa8a5096fcf49070bc65ba6734482
master
Roman Shevchenko 3 years ago committed by intellij-monorepo-bot
parent f259b38c72
commit f40b96ebcf
  1. 11
      src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java
  2. 196
      src/org/jetbrains/java/decompiler/main/ClassWriter.java
  3. 4
      src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
  4. 6
      src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
  5. 19
      src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
  6. 23
      src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java
  7. 27
      src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java
  8. 5
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
  9. 12
      src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
  10. 4
      src/org/jetbrains/java/decompiler/struct/ContextUnit.java
  11. 112
      src/org/jetbrains/java/decompiler/struct/StructClass.java
  12. 9
      src/org/jetbrains/java/decompiler/struct/StructContext.java
  13. 33
      src/org/jetbrains/java/decompiler/struct/StructField.java
  14. 53
      src/org/jetbrains/java/decompiler/struct/StructMember.java
  15. 118
      src/org/jetbrains/java/decompiler/struct/StructMethod.java
  16. 33
      src/org/jetbrains/java/decompiler/struct/StructRecordComponent.java
  17. 43
      src/org/jetbrains/java/decompiler/struct/attr/StructCodeAttribute.java
  18. 96
      src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
  19. 140
      src/org/jetbrains/java/decompiler/struct/attr/StructModuleAttribute.java
  20. 7
      src/org/jetbrains/java/decompiler/struct/attr/StructRecordAttribute.java
  21. 10
      src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
  22. 29
      src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
  23. BIN
      testData/classes/java9/module-info.class
  24. 13
      testData/results/module-info.dec
  25. 3
      testData/src/java9/sample.module/TestClass.java
  26. 3
      testData/src/java9/sample.module/TestService.java
  27. 3
      testData/src/java9/sample.module/TestServiceImpl.java
  28. 13
      testData/src/java9/sample.module/module-info.java
  29. 3
      testData/src/java9/sample.module/test/TestService.java
  30. 3
      testData/src/java9/sample.module/test/TestServiceImpl.java
  31. 3
      testData/src/java9/sample.module/test2/TestClass.java

@ -1,10 +1,11 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.code.cfg;
import org.jetbrains.java.decompiler.code.*;
import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.struct.gen.DataPoint;
@ -96,9 +97,9 @@ public class ControlFlowGraph implements CodeConstants {
return buf.toString();
}
public void inlineJsr(StructMethod mt) {
public void inlineJsr(StructClass cl, StructMethod mt) {
processJsr();
removeJsr(mt);
removeJsr(cl, mt);
removeMarkers();
@ -668,8 +669,8 @@ public class ControlFlowGraph implements CodeConstants {
}
}
private void removeJsr(StructMethod mt) {
removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt));
private void removeJsr(StructClass cl, StructMethod mt) {
removeJsrInstructions(cl.getPool(), first, DataPoint.getInitialDataPoint(mt));
}
private static void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {

@ -41,7 +41,7 @@ public class ClassWriter {
InitializerProcessor.extractInitializers(wrapper);
if (node.type == ClassNode.CLASS_ROOT &&
!cl.isVersionGE_1_5() &&
!cl.isVersion5() &&
DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) {
ClassReference14Processor.processClassReferences(node);
}
@ -249,10 +249,11 @@ public class ClassWriter {
}
}
boolean isModuleInfo = cl.hasModifier(CodeConstants.ACC_MODULE) && cl.hasAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
if (isModuleInfo) {
writeModuleInfoBody(buffer, cl);
if (cl.hasModifier(CodeConstants.ACC_MODULE)) {
StructModuleAttribute moduleAttribute = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
if (moduleAttribute != null) {
writeModuleInfoBody(buffer, moduleAttribute);
}
}
buffer.appendIndent(indent).append('}');
@ -268,111 +269,61 @@ public class ClassWriter {
DecompilerContext.getLogger().endWriteClass();
}
private static boolean isSyntheticRecordMethod(StructMethod mt, TextBuffer code) {
if (mt.getClassStruct().getRecordComponents() == null) return false;
String name = mt.getName();
String descriptor = mt.getDescriptor();
if (name.equals("equals") && descriptor.equals("(Ljava/lang/Object;)Z") ||
name.equals("hashCode") && descriptor.equals("()I") ||
name.equals("toString") && descriptor.equals("()Ljava/lang/String;")) {
if (code.countLines() == 1) {
String str = code.toString().trim();
return str.startsWith("return this." + name + "<invokedynamic>(this");
private static boolean isSyntheticRecordMethod(StructClass cl, StructMethod mt, TextBuffer code) {
if (cl.getRecordComponents() != null) {
String name = mt.getName(), descriptor = mt.getDescriptor();
//noinspection SpellCheckingInspection
if (name.equals("equals") && descriptor.equals("(Ljava/lang/Object;)Z") ||
name.equals("hashCode") && descriptor.equals("()I") ||
name.equals("toString") && descriptor.equals("()Ljava/lang/String;")) {
if (code.countLines() == 1) {
String str = code.toString().trim();
return str.startsWith("return this." + name + "<invokedynamic>(this");
}
}
}
return false;
}
private void writeModuleInfoBody(TextBuffer buffer, StructClass cl) {
StructModuleAttribute moduleAttribute = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_MODULE);
private static void writeModuleInfoBody(TextBuffer buffer, StructModuleAttribute moduleAttribute) {
for (StructModuleAttribute.RequiresEntry requires : moduleAttribute.requires) {
String moduleName = requires.moduleName.replace('/', '.');
buffer.appendIndent(1)
.append("requires ")
.append(moduleName)
.append(';')
.appendLineSeparator();
buffer.appendIndent(1).append("requires ").append(requires.moduleName.replace('/', '.')).append(';').appendLineSeparator();
}
for (StructModuleAttribute.ExportsEntry exports : moduleAttribute.exports) {
String packageName = exports.packageName.replace('/', '.');
buffer.appendIndent(1).append("exports ").append(packageName);
buffer.appendIndent(1).append("exports ").append(exports.packageName.replace('/', '.'));
List<String> exportToModules = exports.exportToModules;
if (exportToModules.size() > 0) {
buffer.append(" to").appendLineSeparator();
int lastIndex = exportToModules.size() - 1;
for (int i = 0; i < exportToModules.size(); i++) {
String moduleName = exportToModules.get(i).replace('/', '.');
char separator = i == lastIndex ? ';' : ',';
buffer.appendIndent(2)
.append(moduleName)
.append(separator)
.appendLineSeparator();
}
} else {
buffer.append(';').appendLineSeparator();
appendFQClassNames(buffer, exportToModules);
}
buffer.append(';').appendLineSeparator();
}
for (StructModuleAttribute.OpensEntry opens : moduleAttribute.opens) {
String packageName = opens.packageName.replace('/', '.');
buffer.appendIndent(1).append("opens ").append(packageName);
buffer.appendIndent(1).append("opens ").append(opens.packageName.replace('/', '.'));
List<String> opensToModules = opens.opensToModules;
if (opensToModules.size() > 0) {
buffer.append(" to").appendLineSeparator();
int lastIndex = opensToModules.size() - 1;
for (int i = 0; i < opensToModules.size(); i++) {
String moduleName = opensToModules.get(i).replace('/', '.');
char separator = i == lastIndex ? ';' : ',';
buffer.appendIndent(2)
.append(moduleName)
.append(separator)
.appendLineSeparator();
}
} else {
buffer.append(';').appendLineSeparator();
appendFQClassNames(buffer, opensToModules);
}
buffer.append(';').appendLineSeparator();
}
for (String uses : moduleAttribute.uses) {
String className = ExprProcessor.buildJavaClassName(uses);
buffer.appendIndent(1)
.append("uses ")
.append(className)
.append(';')
.appendLineSeparator();
buffer.appendIndent(1).append("uses ").append(ExprProcessor.buildJavaClassName(uses)).append(';').appendLineSeparator();
}
for (StructModuleAttribute.ProvidesEntry provides : moduleAttribute.provides) {
String interfaceName = ExprProcessor.buildJavaClassName(provides.interfaceName);
buffer.appendIndent(1)
.append("provides ")
.append(interfaceName)
.append(" with")
.appendLineSeparator();
int lastIndex = provides.implementationNames.size() - 1;
for (int i = 0; i < provides.implementationNames.size(); i++) {
String className = ExprProcessor.buildJavaClassName(provides.implementationNames.get(i));
char separator = i == lastIndex ? ';' : ',';
buffer.appendIndent(2)
.append(className)
.append(separator)
.appendLineSeparator();
}
buffer.appendIndent(1).append("provides ").append(ExprProcessor.buildJavaClassName(provides.interfaceName)).append(" with").appendLineSeparator();
@SuppressWarnings({"SSBasedInspection", "RedundantSuppression"}) List<String> javaNames =
provides.implementationNames.stream().map(ExprProcessor::buildJavaClassName).collect(Collectors.toList());
appendFQClassNames(buffer, javaNames);
buffer.append(';').appendLineSeparator();
}
}
@ -519,11 +470,11 @@ public class ClassWriter {
buffer.append('{').appendLineSeparator();
}
private boolean isVarArgRecord(StructClass cl) {
private static boolean isVarArgRecord(StructClass cl) {
String canonicalConstructorDescriptor =
cl.getRecordComponents().stream().map(c -> c.getDescriptor()).collect(Collectors.joining("", "(", ")V"));
StructMethod ctor = cl.getMethod(CodeConstants.INIT_NAME, canonicalConstructorDescriptor);
return ctor != null && ctor.hasModifier(CodeConstants.ACC_VARARGS);
StructMethod init = cl.getMethod(CodeConstants.INIT_NAME, canonicalConstructorDescriptor);
return init != null && init.hasModifier(CodeConstants.ACC_VARARGS);
}
private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {
@ -553,15 +504,9 @@ public class ClassWriter {
appendModifiers(buffer, fd.getAccessFlags(), FIELD_ALLOWED, isInterface, FIELD_EXCLUDED);
}
VarType fieldType = new VarType(fd.getDescriptor(), false);
GenericFieldDescriptor descriptor = null;
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
StructGenericSignatureAttribute attr = fd.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE);
if (attr != null) {
descriptor = GenericMain.parseFieldSignature(attr.getSignature());
}
}
Map.Entry<VarType, GenericFieldDescriptor> fieldTypeData = getFieldTypeData(fd);
VarType fieldType = fieldTypeData.getKey();
GenericFieldDescriptor descriptor = fieldTypeData.getValue();
if (!isEnum) {
if (descriptor != null) {
@ -619,15 +564,9 @@ public class ClassWriter {
private static void recordComponentToJava(StructRecordComponent cd, TextBuffer buffer, boolean varArgComponent) {
appendAnnotations(buffer, -1, cd, TypeAnnotation.FIELD);
VarType fieldType = new VarType(cd.getDescriptor(), false);
GenericFieldDescriptor descriptor = null;
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
StructGenericSignatureAttribute attr = cd.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE);
if (attr != null) {
descriptor = GenericMain.parseFieldSignature(attr.getSignature());
}
}
Map.Entry<VarType, GenericFieldDescriptor> fieldTypeData = getFieldTypeData(cd);
VarType fieldType = fieldTypeData.getKey();
GenericFieldDescriptor descriptor = fieldTypeData.getValue();
if (descriptor != null) {
buffer.append(GenericMain.getGenericCastTypeName(varArgComponent ? descriptor.type.decreaseArrayDim() : descriptor.type));
@ -770,7 +709,7 @@ public class ClassWriter {
boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);
boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
boolean isDeprecated = mt.hasAttribute(StructGeneralAttribute.ATTRIBUTE_DEPRECATED);
boolean clinit = false, init = false, dinit = false;
boolean clInit = false, init = false, dInit = false;
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
@ -815,7 +754,7 @@ public class ClassWriter {
if (CodeConstants.INIT_NAME.equals(name)) {
if (node.type == ClassNode.CLASS_ANONYMOUS) {
name = "";
dinit = true;
dInit = true;
}
else {
name = node.simpleName;
@ -824,7 +763,7 @@ public class ClassWriter {
}
else if (CodeConstants.CLINIT_NAME.equals(name)) {
name = "";
clinit = true;
clInit = true;
}
GenericMethodDescriptor descriptor = null;
@ -853,7 +792,7 @@ public class ClassWriter {
boolean throwsExceptions = false;
int paramCount = 0;
if (!clinit && !dinit) {
if (!clInit && !dInit) {
boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);
if (descriptor != null && !descriptor.typeParameters.isEmpty()) {
@ -992,7 +931,7 @@ public class ClassWriter {
buffer.appendLineSeparator();
}
else {
if (!clinit && !dinit) {
if (!clInit && !dInit) {
buffer.append(' ');
}
@ -1008,8 +947,8 @@ public class ClassWriter {
BytecodeMappingTracer codeTracer = new BytecodeMappingTracer(tracer.getCurrentSourceLine());
TextBuffer code = root.toJava(indent + 1, codeTracer);
hideMethod = (code.length() == 0) && (clinit || dinit || hideConstructor(node, init, throwsExceptions, paramCount, flags))
|| isSyntheticRecordMethod(mt, code);
hideMethod = code.length() == 0 && (clInit || dInit || hideConstructor(node, init, throwsExceptions, paramCount, flags)) ||
isSyntheticRecordMethod(cl, mt, code);
buffer.append(code);
@ -1049,7 +988,6 @@ public class ClassWriter {
}
private static boolean hideConstructor(ClassNode node, boolean init, boolean throwsExceptions, int paramCount, int methodAccessFlags) {
if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
return false;
}
@ -1057,11 +995,11 @@ public class ClassWriter {
ClassWrapper wrapper = node.getWrapper();
StructClass cl = wrapper.getClassStruct();
int classAccesFlags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
int classAccessFlags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
// default constructor requires same accessibility flags. Exception: enum constructor which is always private
if(!isEnum && ((classAccesFlags & ACCESSIBILITY_FLAGS) != (methodAccessFlags & ACCESSIBILITY_FLAGS))) {
if(!isEnum && ((classAccessFlags & ACCESSIBILITY_FLAGS) != (methodAccessFlags & ACCESSIBILITY_FLAGS))) {
return false;
}
@ -1077,6 +1015,20 @@ public class ClassWriter {
return true;
}
private static Map.Entry<VarType, GenericFieldDescriptor> getFieldTypeData(StructField fd) {
VarType fieldType = new VarType(fd.getDescriptor(), false);
GenericFieldDescriptor descriptor = null;
if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
StructGenericSignatureAttribute attr = fd.getAttribute(StructGeneralAttribute.ATTRIBUTE_SIGNATURE);
if (attr != null) {
descriptor = GenericMain.parseFieldSignature(attr.getSignature());
}
}
return new AbstractMap.SimpleImmutableEntry<>(fieldType, descriptor);
}
private static void appendDeprecation(TextBuffer buffer, int indent) {
buffer.appendIndent(indent).append("/** @deprecated */").appendLineSeparator();
}
@ -1135,11 +1087,11 @@ public class ClassWriter {
buffer.appendIndent(indent).append("// $FF: ").append(comment).appendLineSeparator();
}
private static final StructGeneralAttribute.Key[] ANNOTATION_ATTRIBUTES = {
private static final StructGeneralAttribute.Key<?>[] ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
private static final StructGeneralAttribute.Key[] PARAMETER_ANNOTATION_ATTRIBUTES = {
private static final StructGeneralAttribute.Key<?>[] PARAMETER_ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
private static final StructGeneralAttribute.Key[] TYPE_ANNOTATION_ATTRIBUTES = {
private static final StructGeneralAttribute.Key<?>[] TYPE_ANNOTATION_ATTRIBUTES = {
StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS};
private static void appendAnnotations(TextBuffer buffer, int indent, StructMember mb, int targetType) {
@ -1283,4 +1235,14 @@ public class ClassWriter {
buffer.append('>');
}
}
private static void appendFQClassNames(TextBuffer buffer, List<String> names) {
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
buffer.appendIndent(2).append(name);
if (i < names.size() - 1) {
buffer.append(',').appendLineSeparator();
}
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -245,7 +245,7 @@ public class ClassesProcessor implements CodeConstants {
}
try {
mt.expandData();
mt.expandData(enclosingCl);
InstructionSequence seq = mt.getInstructionSequence();
if (seq != null) {

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main.rels;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -59,10 +59,10 @@ public class ClassWrapper {
try {
if (mt.containsCode()) {
if (maxSec == 0 || testMode) {
root = MethodProcessorRunnable.codeToJava(mt, md, varProc);
root = MethodProcessorRunnable.codeToJava(classStruct, mt, md, varProc);
}
else {
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(mt, md, varProc, DecompilerContext.getCurrentContext());
MethodProcessorRunnable mtProc = new MethodProcessorRunnable(classStruct, mt, md, varProc, DecompilerContext.getCurrentContext());
Thread mtThread = new Thread(mtProc, "Java decompiler");
long stopAt = System.currentTimeMillis() + maxSec * 1000L;

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main.rels;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -33,17 +33,16 @@ public class LambdaProcessor {
ClassesProcessor clProcessor = DecompilerContext.getClassProcessor();
StructClass cl = node.classStruct;
if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lambda beginning with Java 8
if (!cl.isVersion8()) { // lambda beginning with Java 8
return;
}
StructBootstrapMethodsAttribute bootstrap =
cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
if (bootstrap == null || bootstrap.getMethodsNumber() == 0) {
return; // no bootstrap constants in pool
}
BitSet lambda_methods = new BitSet();
BitSet lambdaMethods = new BitSet();
// find lambda bootstrap constants
for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
@ -52,11 +51,11 @@ public class LambdaProcessor {
// FIXME: extend for Eclipse etc. at some point
if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
(JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) || JAVAC_LAMBDA_ALT_METHOD.equals(method_ref.elementname))) {
lambda_methods.set(i);
lambdaMethods.set(i);
}
}
if (lambda_methods.isEmpty()) {
if (lambdaMethods.isEmpty()) {
return; // no lambda bootstrap constant found
}
@ -64,7 +63,7 @@ public class LambdaProcessor {
// iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes.
for (StructMethod mt : cl.getMethods()) {
mt.expandData();
mt.expandData(cl);
InstructionSequence seq = mt.getInstructionSequence();
if (seq != null && seq.length() > 0) {
@ -76,7 +75,7 @@ public class LambdaProcessor {
if (instr.opcode == CodeConstants.opc_invokedynamic) {
LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.operand(0));
if (lambda_methods.get(invoke_dynamic.index1)) { // lambda invocation found
if (lambdaMethods.get(invoke_dynamic.index1)) { // lambda invocation found
List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
@ -123,4 +122,4 @@ public class LambdaProcessor {
// FIXME: mixed hierarchy?
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.main.rels;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -22,6 +22,7 @@ import java.io.IOException;
public class MethodProcessorRunnable implements Runnable {
public final Object lock = new Object();
private final StructClass klass;
private final StructMethod method;
private final MethodDescriptor methodDescriptor;
private final VarProcessor varProc;
@ -31,10 +32,12 @@ public class MethodProcessorRunnable implements Runnable {
private volatile Throwable error;
private volatile boolean finished = false;
public MethodProcessorRunnable(StructMethod method,
public MethodProcessorRunnable(StructClass klass,
StructMethod method,
MethodDescriptor methodDescriptor,
VarProcessor varProc,
DecompilerContext parentContext) {
this.klass = klass;
this.method = method;
this.methodDescriptor = methodDescriptor;
this.varProc = varProc;
@ -48,7 +51,7 @@ public class MethodProcessorRunnable implements Runnable {
try {
DecompilerContext.setCurrentContext(parentContext);
root = codeToJava(method, methodDescriptor, varProc);
root = codeToJava(klass, method, methodDescriptor, varProc);
}
catch (Throwable t) {
error = t;
@ -63,17 +66,15 @@ public class MethodProcessorRunnable implements Runnable {
}
}
public static RootStatement codeToJava(StructMethod mt, MethodDescriptor md, VarProcessor varProc) throws IOException {
StructClass cl = mt.getClassStruct();
public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDescriptor md, VarProcessor varProc) throws IOException {
boolean isInitializer = CodeConstants.CLINIT_NAME.equals(mt.getName()); // for now static initializer only
mt.expandData();
mt.expandData(cl);
InstructionSequence seq = mt.getInstructionSequence();
ControlFlowGraph graph = new ControlFlowGraph(seq);
DeadCodeHelper.removeDeadBlocks(graph);
graph.inlineJsr(mt);
graph.inlineJsr(cl, mt);
// TODO: move to the start, before jsr inlining
DeadCodeHelper.connectDummyExitBlock(graph);
@ -110,13 +111,13 @@ public class MethodProcessorRunnable implements Runnable {
if (!ExceptionDeobfuscator.handleMultipleEntryExceptionRanges(graph)) {
DecompilerContext.getLogger().writeMessage("Found multiple entry exception ranges which could not be splitted", IFernflowerLogger.Severity.WARN);
}
ExceptionDeobfuscator.insertDummyExceptionHandlerBlocks(graph, cl.getBytecodeVersion());
ExceptionDeobfuscator.insertDummyExceptionHandlerBlocks(graph, mt.getBytecodeVersion());
}
RootStatement root = DomHelper.parseGraph(graph);
FinallyProcessor fProc = new FinallyProcessor(md, varProc);
while (fProc.iterateGraph(mt, root, graph)) {
while (fProc.iterateGraph(cl, mt, root, graph)) {
root = DomHelper.parseGraph(graph);
}
@ -200,4 +201,4 @@ public class MethodProcessorRunnable implements Runnable {
public boolean isFinished() {
return finished;
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.modules.decompiler;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -26,6 +26,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPair;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
@ -46,12 +47,8 @@ public class FinallyProcessor {
varProcessor = varProc;
}
public boolean iterateGraph(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
return processStatementEx(mt, root, graph);
}
private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
int bytecode_version = mt.getClassStruct().getBytecodeVersion();
public boolean iterateGraph(StructClass cl, StructMethod mt, RootStatement root, ControlFlowGraph graph) {
int bytecodeVersion = mt.getBytecodeVersion();
LinkedList<Statement> stack = new LinkedList<>();
stack.add(root);
@ -77,22 +74,20 @@ public class FinallyProcessor {
fin.setMonitor(var == null ? null : new VarExprent(var, VarType.VARTYPE_INT, varProcessor));
}
else {
Record inf = getFinallyInformation(mt, root, fin);
Record inf = getFinallyInformation(cl, mt, root, fin);
if (inf == null) { // inconsistent finally
catchallBlockIDs.put(handler.id, null);
}
else {
if (DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
finallyBlockIDs.put(handler.id, null);
}
else {
int varIndex = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varIndex, inf, bytecodeVersion);
int varindex = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf, bytecode_version);
finallyBlockIDs.put(handler.id, varindex);
finallyBlockIDs.put(handler.id, varIndex);
}
DeadCodeHelper.removeDeadBlocks(graph); // e.g. multiple return blocks after a nested finally
@ -120,7 +115,7 @@ public class FinallyProcessor {
}
}
private Record getFinallyInformation(StructMethod mt, RootStatement root, CatchAllStatement fstat) {
private Record getFinallyInformation(StructClass cl, StructMethod mt, RootStatement root, CatchAllStatement fstat) {
Map<BasicBlock, Boolean> mapLast = new HashMap<>();
BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
@ -138,7 +133,7 @@ public class FinallyProcessor {
}
ExprProcessor proc = new ExprProcessor(methodDescriptor, varProcessor);
proc.processStatement(root, mt.getClassStruct());
proc.processStatement(root, cl);
SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
ssa.splitVariables(root, mt);
@ -977,4 +972,4 @@ public class FinallyProcessor {
}
}
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.modules.decompiler.exps;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -30,7 +30,6 @@ import java.util.ArrayList;
import java.util.List;
public class VarExprent extends Exprent {
public static final int STACK_BASE = 10000;
public static final String VAR_NAMELESS_ENCLOSURE = "<VAR_NAMELESS_ENCLOSURE>";
@ -122,7 +121,7 @@ public class VarExprent extends Exprent {
Integer origIndex = processor.getVarOriginalIndex(index);
if (origIndex != null) {
String name = attr.getName(origIndex, visibleOffset);
if (name != null && TextUtil.isValidIdentifier(name, method.getClassStruct().getBytecodeVersion())) {
if (name != null && TextUtil.isValidIdentifier(name, method.getBytecodeVersion())) {
return name;
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.modules.decompiler.vars;
import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
@ -55,7 +55,7 @@ public class VarProcessor {
Integer index = mapOriginalVarIndices.get(pair.var);
if (index != null) {
String debugName = mapDebugVarNames.get(index);
if (debugName != null && TextUtil.isValidIdentifier(debugName, method.getClassStruct().getBytecodeVersion())) {
if (debugName != null && TextUtil.isValidIdentifier(debugName, method.getBytecodeVersion())) {
name = debugName;
}
}
@ -72,11 +72,7 @@ public class VarProcessor {
}
public Integer getVarOriginalIndex(int index) {
if (varVersions == null) {
return null;
}
return varVersions.getMapOriginalVarIndices().get(index);
return varVersions == null ? null : varVersions.getMapOriginalVarIndices().get(index);
}
public void refreshVarNames(VarNamesCollector vc) {
@ -125,4 +121,4 @@ public class VarProcessor {
public Set<VarVersionPair> getExternalVars() {
return externalVars;
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@ -65,7 +65,7 @@ public class ContextUnit {
StructClass newCl;
try (DataInputFullStream in = loader.getClassStream(oldName)) {
newCl = new StructClass(in, cl.isOwn(), loader);
newCl = StructClass.create(in, cl.isOwn(), loader);
}
lstClasses.add(newCl);

@ -1,4 +1,4 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -13,6 +13,7 @@ import org.jetbrains.java.decompiler.util.VBStyleCollection;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/*
class_file {
@ -35,71 +36,86 @@ import java.util.List;
}
*/
public class StructClass extends StructMember {
public final String qualifiedName;
public final PrimitiveConstant superClass;
private final boolean own;
private final LazyLoader loader;
private final int minorVersion;
private final int majorVersion;
private final int[] interfaces;
private final String[] interfaceNames;
private final VBStyleCollection<StructField, String> fields;
private final VBStyleCollection<StructMethod, String> methods;
private ConstantPool pool;
public StructClass(byte[] bytes, boolean own, LazyLoader loader) throws IOException {
this(new DataInputFullStream(bytes), own, loader);
}
public StructClass(DataInputFullStream in, boolean own, LazyLoader loader) throws IOException {
this.own = own;
this.loader = loader;
public static StructClass create(DataInputFullStream in, boolean own, LazyLoader loader) throws IOException {
in.discard(4);
int minorVersion = in.readUnsignedShort();
int majorVersion = in.readUnsignedShort();
int bytecodeVersion = Math.max(majorVersion, CodeConstants.BYTECODE_JAVA_LE_4);
minorVersion = in.readUnsignedShort();
majorVersion = in.readUnsignedShort();
ConstantPool pool = new ConstantPool(in);
pool = new ConstantPool(in);
accessFlags = in.readUnsignedShort();
int accessFlags = in.readUnsignedShort();
int thisClassIdx = in.readUnsignedShort();
int superClassIdx = in.readUnsignedShort();
qualifiedName = pool.getPrimitiveConstant(thisClassIdx).getString();
superClass = pool.getPrimitiveConstant(superClassIdx);
String qualifiedName = pool.getPrimitiveConstant(thisClassIdx).getString();
PrimitiveConstant superClass = pool.getPrimitiveConstant(superClassIdx);
// interfaces
int length = in.readUnsignedShort();
interfaces = new int[length];
interfaceNames = new String[length];
int[] interfaces = new int[length];
String[] interfaceNames = new String[length];
for (int i = 0; i < length; i++) {
interfaces[i] = in.readUnsignedShort();
interfaceNames[i] = pool.getPrimitiveConstant(interfaces[i]).getString();
}
// fields
length = in.readUnsignedShort();
fields = new VBStyleCollection<>(length);
VBStyleCollection<StructField, String>fields = new VBStyleCollection<>(length);
for (int i = 0; i < length; i++) {
StructField field = new StructField(in, this);
StructField field = StructField.create(in, pool, qualifiedName);
fields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
}
// methods
length = in.readUnsignedShort();
methods = new VBStyleCollection<>(length);
VBStyleCollection<StructMethod, String>methods = new VBStyleCollection<>(length);
for (int i = 0; i < length; i++) {
StructMethod method = new StructMethod(in, this);
StructMethod method = StructMethod.create(in, pool, qualifiedName, bytecodeVersion, own);
methods.addWithKey(method, InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor()));
}
// attributes
attributes = readAttributes(in, pool);
Map<String, StructGeneralAttribute> attributes = readAttributes(in, pool);
StructClass cl = new StructClass(
accessFlags, attributes, qualifiedName, superClass, own, loader, minorVersion, majorVersion, interfaces, interfaceNames, fields, methods);
if (loader == null) cl.pool = pool;
return cl;
}
public final String qualifiedName;
public final PrimitiveConstant superClass;
private final boolean own;
private final LazyLoader loader;
private final int minorVersion;
private final int majorVersion;
private final int[] interfaces;
private final String[] interfaceNames;
private final VBStyleCollection<StructField, String> fields;
private final VBStyleCollection<StructMethod, String> methods;
private ConstantPool pool;
releaseResources();
private StructClass(int accessFlags,
Map<String, StructGeneralAttribute> attributes,
String qualifiedName,
PrimitiveConstant superClass,
boolean own,
LazyLoader loader,
int minorVersion,
int majorVersion,
int[] interfaces,
String[] interfaceNames,
VBStyleCollection<StructField, String> fields,
VBStyleCollection<StructMethod, String> methods) {
super(accessFlags, attributes);
this.qualifiedName = qualifiedName;
this.superClass = superClass;
this.own = own;
this.loader = loader;
this.minorVersion = minorVersion;
this.majorVersion = majorVersion;
this.interfaces = interfaces;
this.interfaceNames = interfaceNames;
this.fields = fields;
this.methods = methods;
}
public boolean hasField(String name, String descriptor) {
@ -168,17 +184,13 @@ public class StructClass extends StructMember {
return loader;
}
public boolean isVersionGE_1_5() {
public boolean isVersion5() {
return (majorVersion > CodeConstants.BYTECODE_JAVA_LE_4 ||
(majorVersion == CodeConstants.BYTECODE_JAVA_LE_4 && minorVersion > 0)); // FIXME: check second condition
}
public boolean isVersionGE_1_7() {
return (majorVersion >= CodeConstants.BYTECODE_JAVA_7);
}
public int getBytecodeVersion() {
return Math.max(majorVersion, CodeConstants.BYTECODE_JAVA_LE_4);
public boolean isVersion8() {
return majorVersion >= CodeConstants.BYTECODE_JAVA_8;
}
@Override

@ -1,4 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.main.DecompilerContext;
@ -17,7 +17,6 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class StructContext {
private final IResultSaver saver;
private final IDecompiledData decompiledData;
private final LazyLoader loader;
@ -106,7 +105,7 @@ public class StructContext {
if (filename.endsWith(".class")) {
try (DataInputFullStream in = loader.getClassStream(file.getAbsolutePath(), null)) {
StructClass cl = new StructClass(in, isOwn, loader);
StructClass cl = StructClass.create(in, isOwn, loader);
classes.put(cl.qualifiedName, cl);
unit.addClass(cl, filename);
loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(file.getAbsolutePath(), null));
@ -141,7 +140,7 @@ public class StructContext {
if (!entry.isDirectory()) {
if (name.endsWith(".class")) {
byte[] bytes = InterpreterUtil.getBytes(archive, entry);
StructClass cl = new StructClass(bytes, isOwn, loader);
StructClass cl = StructClass.create(new DataInputFullStream(bytes), isOwn, loader);
classes.put(cl.qualifiedName, cl);
unit.addClass(cl, name);
loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(file.getAbsolutePath(), name));
@ -160,4 +159,4 @@ public class StructContext {
public Map<String, StructClass> getClasses() {
return classes;
}
}
}

@ -1,10 +1,12 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
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.util.DataInputFullStream;
import java.io.IOException;
import java.util.Map;
/*
field_info {
@ -16,29 +18,32 @@ import java.io.IOException;
}
*/
public class StructField extends StructMember {
public static StructField create(DataInputFullStream in, ConstantPool pool, String clQualifiedName) throws IOException {
int accessFlags = in.readUnsignedShort();
int nameIndex = in.readUnsignedShort();
int descriptorIndex = in.readUnsignedShort();
private final String name;
private final String descriptor;
String[] values = pool.getClassElement(ConstantPool.FIELD, clQualifiedName, nameIndex, descriptorIndex);
Map<String, StructGeneralAttribute> attributes = readAttributes(in, pool);
public StructField(DataInputFullStream in, StructClass clStruct) throws IOException {
accessFlags = in.readUnsignedShort();
int nameIndex = in.readUnsignedShort();
int descriptorIndex = in.readUnsignedShort();
return new StructField(accessFlags, attributes, values[0], values[1]);
}
ConstantPool pool = clStruct.getPool();
String[] values = pool.getClassElement(ConstantPool.FIELD, clStruct.qualifiedName, nameIndex, descriptorIndex);
name = values[0];
descriptor = values[1];
private final String name;
private final String descriptor;
attributes = readAttributes(in, pool);
protected StructField(int accessFlags, Map<String, StructGeneralAttribute> attributes, String name, String descriptor) {
super(accessFlags, attributes);
this.name = name;
this.descriptor = descriptor;
}
public String getName() {
public final String getName() {
return name;
}
public String getDescriptor() {
public final String getDescriptor() {
return descriptor;
}

@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.code.CodeConstants;
@ -12,23 +12,26 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class StructMember {
protected int accessFlags;
protected Map<String, StructGeneralAttribute> attributes;
public abstract class StructMember {
private final int accessFlags;
private final Map<String, StructGeneralAttribute> attributes;
protected StructMember(int accessFlags, Map<String, StructGeneralAttribute> attributes) {
this.accessFlags = accessFlags;
this.attributes = attributes;
}
public int getAccessFlags() {
return accessFlags;
}
public <T extends StructGeneralAttribute> T getAttribute(StructGeneralAttribute.Key<T> attribute) {
//noinspection unchecked
return (T)attributes.get(attribute.getName());
@SuppressWarnings("unchecked") T t = (T)attributes.get(attribute.name);
return t;
}
public boolean hasAttribute(StructGeneralAttribute.Key<?> attribute) {
return attributes.containsKey(attribute.getName());
return attributes.containsKey(attribute.name);
}
public boolean hasModifier(int modifier) {
@ -39,45 +42,37 @@ public class StructMember {
return hasModifier(CodeConstants.ACC_SYNTHETIC) || hasAttribute(StructGeneralAttribute.ATTRIBUTE_SYNTHETIC);
}
protected Map<String, StructGeneralAttribute> readAttributes(DataInputFullStream in, ConstantPool pool) throws IOException {
public static Map<String, StructGeneralAttribute> readAttributes(DataInputFullStream in, ConstantPool pool) throws IOException {
int length = in.readUnsignedShort();
Map<String, StructGeneralAttribute> attributes = new HashMap<>(length);
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.getName().equals(name) && attributes.containsKey(name)) {
StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name);
int attLength = in.readInt();
if (attribute == null) {
in.discard(attLength);
}
else {
attribute.initContent(in, pool);
if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.name.equals(name) && attributes.containsKey(name)) {
// merge all variable tables
StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.get(name);
table.add((StructLocalVariableTableAttribute)attribute);
}
else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.getName().equals(name) && attributes.containsKey(name)) {
else if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.name.equals(name) && attributes.containsKey(name)) {
// merge all variable tables
StructLocalVariableTypeTableAttribute table = (StructLocalVariableTypeTableAttribute)attributes.get(name);
table.add((StructLocalVariableTypeTableAttribute)attribute);
}
else {
attributes.put(attribute.getName(), attribute);
attributes.put(name, attribute);
}
}
}
return attributes;
}
protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name);
int length = in.readInt();
if (attribute == null) {
in.discard(length);
}
else {
attribute.initContent(in, pool);
}
return attribute;
}
}
}

@ -1,7 +1,8 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct;
import org.jetbrains.java.decompiler.code.*;
import org.jetbrains.java.decompiler.struct.attr.StructCodeAttribute;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
@ -25,80 +26,66 @@ import static org.jetbrains.java.decompiler.code.CodeConstants.*;
}
*/
public class StructMethod extends StructMember {
public static StructMethod create(DataInputFullStream in, ConstantPool pool, String clQualifiedName, int bytecodeVersion, boolean own) throws IOException {
int accessFlags = in.readUnsignedShort();
int nameIndex = in.readUnsignedShort();
int descriptorIndex = in.readUnsignedShort();
String[] values = pool.getClassElement(ConstantPool.METHOD, clQualifiedName, nameIndex, descriptorIndex);
Map<String, StructGeneralAttribute> attributes = readAttributes(in, pool);
StructCodeAttribute code = (StructCodeAttribute)attributes.remove(StructGeneralAttribute.ATTRIBUTE_CODE.name);
if (code != null) {
attributes.putAll(code.codeAttributes);
}
return new StructMethod(accessFlags, attributes, values[0], values[1], bytecodeVersion, own ? code : null);
}
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};
private static final int[] opcs_store = {opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
private final StructClass classStruct;
private final String name;
private final String descriptor;
private boolean containsCode = false;
private int localVariables = 0;
private int codeLength = 0;
private int codeFullLength = 0;
private InstructionSequence seq;
private final int bytecodeVersion;
private final int localVariables;
private final int codeLength;
private final int codeFullLength;
private InstructionSequence seq = null;
private boolean expanded = false;
private Map<String, StructGeneralAttribute> codeAttributes;
public StructMethod(DataInputFullStream in, StructClass clStruct) throws IOException {
classStruct = clStruct;
accessFlags = in.readUnsignedShort();
int nameIndex = in.readUnsignedShort();
int descriptorIndex = in.readUnsignedShort();
ConstantPool pool = clStruct.getPool();
String[] values = pool.getClassElement(ConstantPool.METHOD, clStruct.qualifiedName, nameIndex, descriptorIndex);
name = values[0];
descriptor = values[1];
attributes = readAttributes(in, pool);
if (codeAttributes != null) {
attributes.putAll(codeAttributes);
codeAttributes = null;
private StructMethod(int accessFlags,
Map<String, StructGeneralAttribute> attributes,
String name,
String descriptor,
int bytecodeVersion,
StructCodeAttribute code) {
super(accessFlags, attributes);
this.name = name;
this.descriptor = descriptor;
this.bytecodeVersion = bytecodeVersion;
if (code != null) {
this.localVariables = code.localVariables;
this.codeLength = code.codeLength;
this.codeFullLength = code.codeFullLength;
}
}
@Override
protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
if (StructGeneralAttribute.ATTRIBUTE_CODE.getName().equals(name)) {
if (!classStruct.isOwn()) {
// skip code in foreign classes
in.discard(8);
in.discard(in.readInt());
in.discard(8 * in.readUnsignedShort());
}
else {
containsCode = true;
in.discard(6);
localVariables = in.readUnsignedShort();
codeLength = in.readInt();
in.discard(codeLength);
int excLength = in.readUnsignedShort();
in.discard(excLength * 8);
codeFullLength = codeLength + excLength * 8 + 2;
}
codeAttributes = readAttributes(in, pool);
return null;
else {
this.localVariables = this.codeLength = this.codeFullLength = -1;
}
return super.readAttribute(in, pool, name);
}
public void expandData() throws IOException {
if (containsCode && !expanded) {
byte[] code = classStruct.getLoader().loadBytecode(this, codeFullLength);
public void expandData(StructClass classStruct) throws IOException {
if (codeLength >= 0 && !expanded) {
byte[] code = classStruct.getLoader().loadBytecode(classStruct, this, codeFullLength);
seq = parseBytecode(new DataInputFullStream(code), codeLength, classStruct.getPool());
expanded = true;
}
}
public void releaseResources() {
if (containsCode && expanded) {
if (codeLength >= 0 && expanded) {
seq = null;
expanded = false;
}
@ -108,10 +95,7 @@ public class StructMethod extends StructMember {
private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException {
VBStyleCollection<Instruction, Integer> instructions = new VBStyleCollection<>();
int bytecode_version = classStruct.getBytecodeVersion();
for (int i = 0; i < length; ) {
int offset = i;
int opcode = in.readUnsignedByte();
@ -197,7 +181,7 @@ public class StructMethod extends StructMember {
}
break;
case opc_invokedynamic:
if (classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before
if (bytecodeVersion >= CodeConstants.BYTECODE_JAVA_7) { // instruction unused in Java 6 and before
operands.add(in.readUnsignedShort());
in.discard(2);
group = GROUP_INVOCATION;
@ -313,7 +297,7 @@ public class StructMethod extends StructMember {
}
}
Instruction instr = Instruction.create(opcode, wide, group, bytecode_version, ops);
Instruction instr = Instruction.create(opcode, wide, group, bytecodeVersion, ops);
instructions.addWithKey(instr, offset);
@ -355,10 +339,6 @@ public class StructMethod extends StructMember {
return seq;
}
public StructClass getClassStruct() {
return classStruct;
}
public String getName() {
return name;
}
@ -367,8 +347,12 @@ public class StructMethod extends StructMember {
return descriptor;
}
public int getBytecodeVersion() {
return bytecodeVersion;
}
public boolean containsCode() {
return containsCode;
return codeLength >= 0;
}
public int getLocalVariables() {
@ -387,4 +371,4 @@ public class StructMethod extends StructMember {
public String toString() {
return name;
}
}
}

@ -1,11 +1,13 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
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.PrimitiveConstant;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.IOException;
import java.util.Map;
/*
record_component_info {
@ -15,33 +17,20 @@ import java.io.IOException;
attribute_info attributes[attributes_count];
}
*/
public class StructRecordComponent extends StructMember {
private final String name;
private final String descriptor;
public StructRecordComponent(DataInputFullStream in, ConstantPool pool) throws IOException {
accessFlags = 0;
public class StructRecordComponent extends StructField {
public static StructRecordComponent create(DataInputFullStream in, ConstantPool pool) throws IOException {
int nameIndex = in.readUnsignedShort();
int descriptorIndex = in.readUnsignedShort();
name = ((PrimitiveConstant)pool.getConstant(nameIndex)).getString();
descriptor = ((PrimitiveConstant)pool.getConstant(descriptorIndex)).getString();
String name = ((PrimitiveConstant)pool.getConstant(nameIndex)).getString();
String descriptor = ((PrimitiveConstant)pool.getConstant(descriptorIndex)).getString();
attributes = readAttributes(in, pool);
}
public String getName() {
return name;
}
Map<String, StructGeneralAttribute> attributes = readAttributes(in, pool);
public String getDescriptor() {
return descriptor;
return new StructRecordComponent(0, attributes, name, descriptor);
}
@Override
public String toString() {
return name;
private StructRecordComponent(int flags, Map<String, StructGeneralAttribute> attributes, String name, String descriptor) {
super(flags, attributes, name, descriptor);
}
}

@ -0,0 +1,43 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.StructMember;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.DataInputFullStream;
import java.io.IOException;
import java.util.Map;
/*
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[];
u2 exception_table_length;
exception_table[] {
u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
};
u2 attributes_count;
attribute_info attributes[];
*/
public class StructCodeAttribute extends StructGeneralAttribute {
public int localVariables = 0;
public int codeLength = 0;
public int codeFullLength = 0;
public Map<String, StructGeneralAttribute> codeAttributes;
@Override
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException {
data.discard(2);
localVariables = data.readUnsignedShort();
codeLength = data.readInt();
data.discard(codeLength);
int excLength = data.readUnsignedShort();
data.discard(excLength * 8);
codeFullLength = codeLength + excLength * 8 + 2;
codeAttributes = StructMember.readAttributes(data, pool);
}
}

@ -14,7 +14,7 @@ import java.io.IOException;
}
*/
public class StructGeneralAttribute {
public static final Key<StructGeneralAttribute> ATTRIBUTE_CODE = new Key<>("Code");
public static final Key<StructCodeAttribute> ATTRIBUTE_CODE = new Key<>("Code");
public static final Key<StructInnerClassesAttribute> ATTRIBUTE_INNER_CLASSES = new Key<>("InnerClasses");
public static final Key<StructGenericSignatureAttribute> ATTRIBUTE_SIGNATURE = new Key<>("Signature");
public static final Key<StructAnnDefaultAttribute> ATTRIBUTE_ANNOTATION_DEFAULT = new Key<>("AnnotationDefault");
@ -37,86 +37,74 @@ public class StructGeneralAttribute {
public static final Key<StructModuleAttribute> ATTRIBUTE_MODULE = new Key<>("Module");
public static final Key<StructRecordAttribute> ATTRIBUTE_RECORD = new Key<>("Record");
@SuppressWarnings("unused")
public static class Key<T extends StructGeneralAttribute> {
private final String name;
public final String name;
public Key(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
private String name;
public static StructGeneralAttribute createAttribute(String name) {
StructGeneralAttribute attr;
if (ATTRIBUTE_INNER_CLASSES.getName().equals(name)) {
attr = new StructInnerClassesAttribute();
if (ATTRIBUTE_CODE.name.equals(name)) {
return new StructCodeAttribute();
}
else if (ATTRIBUTE_CONSTANT_VALUE.getName().equals(name)) {
attr = new StructConstantValueAttribute();
else if (ATTRIBUTE_INNER_CLASSES.name.equals(name)) {
return new StructInnerClassesAttribute();
}
else if (ATTRIBUTE_SIGNATURE.getName().equals(name)) {
attr = new StructGenericSignatureAttribute();
else if (ATTRIBUTE_CONSTANT_VALUE.name.equals(name)) {
return new StructConstantValueAttribute();
}
else if (ATTRIBUTE_ANNOTATION_DEFAULT.getName().equals(name)) {
attr = new StructAnnDefaultAttribute();
else if (ATTRIBUTE_SIGNATURE.name.equals(name)) {
return new StructGenericSignatureAttribute();
}
else if (ATTRIBUTE_EXCEPTIONS.getName().equals(name)) {
attr = new StructExceptionsAttribute();
else if (ATTRIBUTE_ANNOTATION_DEFAULT.name.equals(name)) {
return new StructAnnDefaultAttribute();
}
else if (ATTRIBUTE_ENCLOSING_METHOD.getName().equals(name)) {
attr = new StructEnclosingMethodAttribute();
else if (ATTRIBUTE_EXCEPTIONS.name.equals(name)) {
return new StructExceptionsAttribute();
}
else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.getName().equals(name) || ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.getName().equals(name)) {
attr = new StructAnnotationAttribute();
else if (ATTRIBUTE_ENCLOSING_METHOD.name.equals(name)) {
return new StructEnclosingMethodAttribute();
}
else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.getName().equals(name) || ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.getName().equals(name)) {
attr = new StructAnnotationParameterAttribute();
else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.name.equals(name) || ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.name.equals(name)) {
return new StructAnnotationAttribute();
}
else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.getName().equals(name) || ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.getName().equals(name)) {
attr = new StructTypeAnnotationAttribute();
else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.name.equals(name) || ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.name.equals(name)) {
return new StructAnnotationParameterAttribute();
}
else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.getName().equals(name)) {
attr = new StructLocalVariableTableAttribute();
else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.name.equals(name) || ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.name.equals(name)) {
return new StructTypeAnnotationAttribute();
}
else if (ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.getName().equals(name)) {
attr = new StructLocalVariableTypeTableAttribute();
else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.name.equals(name)) {
return new StructLocalVariableTableAttribute();
}
else if (ATTRIBUTE_BOOTSTRAP_METHODS.getName().equals(name)) {
attr = new StructBootstrapMethodsAttribute();
else if (ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE.name.equals(name)) {
return new StructLocalVariableTypeTableAttribute();
}
else if (ATTRIBUTE_SYNTHETIC.getName().equals(name) || ATTRIBUTE_DEPRECATED.getName().equals(name)) {
attr = new StructGeneralAttribute();
else if (ATTRIBUTE_BOOTSTRAP_METHODS.name.equals(name)) {
return new StructBootstrapMethodsAttribute();
}
else if (ATTRIBUTE_LINE_NUMBER_TABLE.getName().equals(name)) {
attr = new StructLineNumberTableAttribute();
else if (ATTRIBUTE_SYNTHETIC.name.equals(name) || ATTRIBUTE_DEPRECATED.name.equals(name)) {
return new StructGeneralAttribute();
}
else if (ATTRIBUTE_METHOD_PARAMETERS.getName().equals(name)) {
attr = new StructMethodParametersAttribute();
else if (ATTRIBUTE_LINE_NUMBER_TABLE.name.equals(name)) {
return new StructLineNumberTableAttribute();
}
else if (ATTRIBUTE_MODULE.getName().equals(name)) {
attr = new StructModuleAttribute();
else if (ATTRIBUTE_METHOD_PARAMETERS.name.equals(name)) {
return new StructMethodParametersAttribute();
}
else if (ATTRIBUTE_RECORD.getName().equals(name)) {
attr = new StructRecordAttribute();
else if (ATTRIBUTE_MODULE.name.equals(name)) {
return new StructModuleAttribute();
}
else if (ATTRIBUTE_RECORD.name.equals(name)) {
return new StructRecordAttribute();
}
else {
// unsupported attribute
return null;
return null; // unsupported attribute
}
attr.name = name;
return attr;
}
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { }
public String getName() {
return name;
}
}
}

@ -23,7 +23,6 @@ public class StructModuleAttribute extends StructGeneralAttribute {
@Override
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException {
int moduleNameIndex = data.readUnsignedShort();
this.moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString();
this.moduleFlags = data.readUnsignedShort();
@ -41,147 +40,87 @@ public class StructModuleAttribute extends StructGeneralAttribute {
public List<RequiresEntry> readRequires(DataInputFullStream data, ConstantPool pool) throws IOException {
int requiresCount = data.readUnsignedShort();
if (requiresCount <= 0) {
return Collections.emptyList();
}
if (requiresCount <= 0) return Collections.emptyList();
List<RequiresEntry> requires = new ArrayList<>(requiresCount);
for (int i = 0; i < requiresCount; i++) {
int moduleNameIndex = data.readUnsignedShort();
int moduleFlags = data.readUnsignedShort();
int versionIndex = data.readUnsignedShort();
String moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString();
String version = versionIndex == 0 ? null : pool.getPrimitiveConstant(versionIndex).getString();
requires.add(new RequiresEntry(moduleName, moduleFlags, version));
}
return requires;
}
private List<ExportsEntry> readExports(DataInputFullStream data, ConstantPool pool) throws IOException {
private static List<ExportsEntry> readExports(DataInputFullStream data, ConstantPool pool) throws IOException {
int exportsCount = data.readUnsignedShort();
if (exportsCount <= 0) {
return Collections.emptyList();
}
if (exportsCount <= 0) return Collections.emptyList();
List<ExportsEntry> exports = new ArrayList<>(exportsCount);
for (int i = 0; i < exportsCount; i++) {
int packageNameIndex = data.readUnsignedShort();
int exportsFlags = data.readUnsignedShort();
int exportsToCount = data.readUnsignedShort();
List<String> exportsToModules;
if (exportsToCount > 0) {
exportsToModules = new ArrayList<>(exportsToCount);
for (int j = 0; j < exportsToCount; j++) {
int moduleNameIndex = data.readUnsignedShort();
String moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString();
exportsToModules.add(moduleName);
}
} else {
exportsToModules = Collections.emptyList();
}
List<String> exportsToModules = readStringList(data, pool);
String packageName = pool.getPrimitiveConstant(packageNameIndex).getString();
exports.add(new ExportsEntry(packageName, exportsFlags, exportsToModules));
}
return exports;
}
private List<OpensEntry> readOpens(DataInputFullStream data, ConstantPool pool) throws IOException {
private static List<OpensEntry> readOpens(DataInputFullStream data, ConstantPool pool) throws IOException {
int opensCount = data.readUnsignedShort();
if (opensCount <= 0) {
return Collections.emptyList();
}
if (opensCount <= 0) return Collections.emptyList();
List<OpensEntry> opens = new ArrayList<>(opensCount);
for (int i = 0; i < opensCount; i++) {
int packageNameIndex = data.readUnsignedShort();
int opensFlags = data.readUnsignedShort();
int opensToCount = data.readUnsignedShort();
List<String> opensToModules;
if (opensToCount > 0) {
opensToModules = new ArrayList<>(opensToCount);
for (int j = 0; j < opensToCount; j++) {
int moduleNameIndex = data.readUnsignedShort();
String moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString();
opensToModules.add(moduleName);
}
} else {
opensToModules = Collections.emptyList();
}
List<String> opensToModules = readStringList(data, pool);
String packageName = pool.getPrimitiveConstant(packageNameIndex).getString();
opens.add(new OpensEntry(packageName, opensFlags, opensToModules));
}
return opens;
}
private List<String> readUses(DataInputFullStream data, ConstantPool pool) throws IOException {
int usesCount = data.readUnsignedShort();
if (usesCount <= 0) {
return Collections.emptyList();
}
List<String> uses = new ArrayList<>(usesCount);
for (int i = 0; i < usesCount; i++) {
int classNameIndex = data.readUnsignedShort();
String className = pool.getPrimitiveConstant(classNameIndex).getString();
uses.add(className);
}
return uses;
private static List<String> readUses(DataInputFullStream data, ConstantPool pool) throws IOException {
return readStringList(data, pool);
}
private List<ProvidesEntry> readProvides(DataInputFullStream data, ConstantPool pool) throws IOException {
private static List<ProvidesEntry> readProvides(DataInputFullStream data, ConstantPool pool) throws IOException {
int providesCount = data.readUnsignedShort();
if (providesCount <= 0) {
return Collections.emptyList();
}
if (providesCount <= 0) return Collections.emptyList();
List<ProvidesEntry> provides = new ArrayList<>(providesCount);
for (int i = 0; i < providesCount; i++) {
int interfaceNameIndex = data.readUnsignedShort();
String interfaceName = pool.getPrimitiveConstant(interfaceNameIndex).getString();
// Always nonzero
int providesWithCount = data.readUnsignedShort();
List<String> implementationNames = new ArrayList<>(providesWithCount);
for (int j = 0; j < providesWithCount; j++) {
int classNameIndex = data.readUnsignedShort();
String className = pool.getPrimitiveConstant(classNameIndex).getString();
implementationNames.add(className);
}
List<String> implementationNames = readStringList(data, pool);
provides.add(new ProvidesEntry(interfaceName, implementationNames));
}
return provides;
}
private static List<String> readStringList(DataInputFullStream data, ConstantPool pool) throws IOException {
int count = data.readUnsignedShort();
if (count <= 0) {
return Collections.emptyList();
}
else {
List<String> strings = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
int index = data.readUnsignedShort();
strings.add(pool.getPrimitiveConstant(index).getString());
}
return strings;
}
}
public static final class RequiresEntry {
public String moduleName;
public int moduleFlags;
public String moduleVersion;
public final String moduleName;
public final int moduleFlags;
public final String moduleVersion;
public RequiresEntry(String moduleName, int moduleFlags, String moduleVersion) {
this.moduleName = moduleName;
@ -191,9 +130,9 @@ public class StructModuleAttribute extends StructGeneralAttribute {
}
public static final class ExportsEntry {
public String packageName;
public int exportsFlags;
public List<String> exportToModules;
public final String packageName;
public final int exportsFlags;
public final List<String> exportToModules;
public ExportsEntry(String packageName, int exportsFlags, List<String> exportToModules) {
this.packageName = packageName;
@ -203,9 +142,9 @@ public class StructModuleAttribute extends StructGeneralAttribute {
}
public static final class OpensEntry {
public String packageName;
public int opensFlags;
public List<String> opensToModules;
public final String packageName;
public final int opensFlags;
public final List<String> opensToModules;
public OpensEntry(String packageName, int exportsFlags, List<String> exportToModules) {
this.packageName = packageName;
@ -215,13 +154,12 @@ public class StructModuleAttribute extends StructGeneralAttribute {
}
public static final class ProvidesEntry {
public String interfaceName;
public List<String> implementationNames;
public final String interfaceName;
public final List<String> implementationNames;
public ProvidesEntry(String interfaceName, List<String> implementationNames) {
this.interfaceName = interfaceName;
this.implementationNames = implementationNames;
}
}
}
}

@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct.attr;
import org.jetbrains.java.decompiler.struct.StructRecordComponent;
@ -22,12 +22,11 @@ public class StructRecordAttribute extends StructGeneralAttribute {
List<StructRecordComponent> components;
@Override
public void initContent(DataInputFullStream data,
ConstantPool pool) throws IOException {
public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException {
int componentCount = data.readUnsignedShort();
StructRecordComponent[] components = new StructRecordComponent[componentCount];
for (int i = 0; i < componentCount; i++) {
components[i] = new StructRecordComponent(data, pool);
components[i] = StructRecordComponent.create(data, pool);
}
this.components = Arrays.asList(components);
}

@ -212,18 +212,12 @@ public class ConstantPool implements NewClassNameBuilder {
String newName = interceptor.getName(vt.value);
if (newName != null) {
StringBuilder buffer = new StringBuilder();
if (vt.arrayDim > 0) {
for (int i = 0; i < vt.arrayDim; i++) {
buffer.append('[');
}
buffer.append('L').append(newName).append(';');
buffer.append("[".repeat(vt.arrayDim)).append('L').append(newName).append(';');
}
else {
buffer.append(newName);
}
return buffer.toString();
}
@ -238,4 +232,4 @@ public class ConstantPool implements NewClassNameBuilder {
return MethodDescriptor.parseDescriptor(descriptor).buildNewDescriptor(this);
}
}
}
}

@ -1,7 +1,8 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.java.decompiler.struct.lazy;
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
@ -19,20 +20,20 @@ public class LazyLoader {
this.provider = provider;
}
public void addClassLink(String classname, Link link) {
mapClassLinks.put(classname, link);
public void addClassLink(String className, Link link) {
mapClassLinks.put(className, link);
}
public void removeClassLink(String classname) {
mapClassLinks.remove(classname);
public void removeClassLink(String className) {
mapClassLinks.remove(className);
}
public Link getClassLink(String classname) {
return mapClassLinks.get(classname);
public Link getClassLink(String className) {
return mapClassLinks.get(className);
}
public ConstantPool loadPool(String classname) {
try (DataInputFullStream in = getClassStream(classname)) {
public ConstantPool loadPool(String className) {
try (DataInputFullStream in = getClassStream(className)) {
if (in != null) {
in.discard(8);
return new ConstantPool(in);
@ -45,14 +46,14 @@ public class LazyLoader {
}
}
public byte[] loadBytecode(StructMethod mt, int codeFullLength) {
String className = mt.getClassStruct().qualifiedName;
public byte[] loadBytecode(StructClass classStruct, StructMethod mt, int codeFullLength) {
String className = classStruct.qualifiedName;
try (DataInputFullStream in = getClassStream(className)) {
if (in != null) {
in.discard(8);
ConstantPool pool = mt.getClassStruct().getPool();
ConstantPool pool = classStruct.getPool();
if (pool == null) {
pool = new ConstantPool(in);
}
@ -90,7 +91,7 @@ public class LazyLoader {
for (int j = 0; j < attrSize; j++) {
int attrNameIndex = in.readUnsignedShort();
String attrName = pool.getPrimitiveConstant(attrNameIndex).getString();
if (!StructGeneralAttribute.ATTRIBUTE_CODE.getName().equals(attrName)) {
if (!StructGeneralAttribute.ATTRIBUTE_CODE.name.equals(attrName)) {
in.discard(in.readInt());
continue;
}
@ -138,4 +139,4 @@ public class LazyLoader {
this.internalPath = internalPath;
}
}
}
}

@ -1,13 +1,14 @@
@Deprecated
module sample.module {
requires java.base;
exports test;
exports test2 to
exports sample.pkg1;
exports sample.pkg2 to
java.base;
opens test;
opens test2 to
opens sample.pkg1;
opens sample.pkg2 to
java.base;
uses java.util.spi.ToolProvider;
provides test.TestService with
test.TestServiceImpl;
provides sample.pkg1.TestService with
sample.pkg1.TestServiceImpl;
}

@ -0,0 +1,3 @@
package sample.pkg2;
public class TestClass {}

@ -0,0 +1,3 @@
package sample.pkg1;
public interface TestService {}

@ -0,0 +1,3 @@
package sample.pkg1;
public class TestServiceImpl implements TestService {}

@ -1,15 +1,16 @@
@Deprecated
module sample.module {
requires java.base;
uses java.util.spi.ToolProvider;
provides test.TestService with test.TestServiceImpl;
provides sample.pkg1.TestService with sample.pkg1.TestServiceImpl;
exports test;
exports sample.pkg1;
exports test2 to java.base;
exports sample.pkg2 to java.base;
opens test;
opens sample.pkg1;
opens test2 to java.base;
}
opens sample.pkg2 to java.base;
}

@ -1,3 +0,0 @@
package test;
public interface TestService {}

@ -1,3 +0,0 @@
package test;
public class TestServiceImpl implements TestService {}

@ -1,3 +0,0 @@
package test2;
public class TestClass {}
Loading…
Cancel
Save