java-decompiler: more lambdas

master
Roman Shevchenko 10 years ago
parent 2ea3feb527
commit c082dfba98
  1. 33
      src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
  2. 36
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2000-2014 JetBrains s.r.o. * Copyright 2000-2015 JetBrains s.r.o.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -35,29 +35,23 @@ import java.io.IOException;
import java.util.*; import java.util.*;
public class LambdaProcessor { public class LambdaProcessor {
@SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory";
private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory"; @SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_METHOD = "metafactory";
private static final String JAVAC_LAMBDA_METHOD = "metafactory"; @SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_ALT_METHOD = "altMetafactory";
private static final String JAVAC_LAMBDA_METHOD_DESCRIPTOR =
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
public void processClass(ClassNode node) throws IOException { public void processClass(ClassNode node) throws IOException {
for (ClassNode child : node.nested) { for (ClassNode child : node.nested) {
processClass(child); processClass(child);
} }
if (node.nested.isEmpty()) {
hasLambda(node); hasLambda(node);
} }
}
public boolean hasLambda(ClassNode node) throws IOException { public boolean hasLambda(ClassNode node) throws IOException {
ClassesProcessor clProcessor = DecompilerContext.getClassProcessor();
ClassesProcessor clprocessor = DecompilerContext.getClassProcessor();
StructClass cl = node.classStruct; StructClass cl = node.classStruct;
if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lamda beginning with Java 8 if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lambda beginning with Java 8
return false; return false;
} }
@ -67,17 +61,16 @@ public class LambdaProcessor {
return false; // no bootstrap constants in pool return false; // no bootstrap constants in pool
} }
Set<Integer> lambda_methods = new HashSet<Integer>(); BitSet lambda_methods = new BitSet();
// find lambda bootstrap constants // find lambda bootstrap constants
for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) { for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
LinkConstant method_ref = bootstrap.getMethodReference(i); // method handle LinkConstant method_ref = bootstrap.getMethodReference(i); // method handle
// FIXME: extend for Eclipse etc. at some point
if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) && if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) && (JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) || JAVAC_LAMBDA_ALT_METHOD.equals(method_ref.elementname))) {
JAVAC_LAMBDA_METHOD_DESCRIPTOR lambda_methods.set(i);
.equals(method_ref.descriptor)) { // check for javac lambda structure. FIXME: extend for Eclipse etc. at some point
lambda_methods.add(i);
} }
} }
@ -101,7 +94,7 @@ public class LambdaProcessor {
if (instr.opcode == CodeConstants.opc_invokedynamic) { if (instr.opcode == CodeConstants.opc_invokedynamic) {
LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.getOperand(0)); LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.getOperand(0));
if (lambda_methods.contains(invoke_dynamic.index1)) { // lambda invocation found if (lambda_methods.get(invoke_dynamic.index1)) { // lambda invocation found
List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1); List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor); MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
@ -121,7 +114,7 @@ public class LambdaProcessor {
node.nested.add(node_lambda); node.nested.add(node_lambda);
node_lambda.parent = node; node_lambda.parent = node;
clprocessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda); clProcessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
mapMethodsLambda.put(node_lambda.lambdaInformation.content_method_key, node_lambda.simpleName); mapMethodsLambda.put(node_lambda.lambdaInformation.content_method_key, node_lambda.simpleName);
} }
} }
@ -136,7 +129,7 @@ public class LambdaProcessor {
if (nd.type == ClassNode.CLASS_LAMBDA) { if (nd.type == ClassNode.CLASS_LAMBDA) {
String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod); String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod);
if (parent_class_name != null) { if (parent_class_name != null) {
ClassNode parent_class = clprocessor.getMapRootClasses().get(parent_class_name); ClassNode parent_class = clProcessor.getMapRootClasses().get(parent_class_name);
parent_class.nested.add(nd); parent_class.nested.add(nd);
nd.parent = parent_class; nd.parent = parent_class;

@ -87,7 +87,6 @@ public class InvocationExprent extends Exprent {
break; break;
case CodeConstants.opc_invokedynamic: case CodeConstants.opc_invokedynamic:
invocationTyp = INVOKE_DYNAMIC; invocationTyp = INVOKE_DYNAMIC;
classname = "java/lang/Class"; // dummy class name classname = "java/lang/Class"; // dummy class name
invokeDynamicClassSuffix = "##Lambda_" + cn.index1 + "_" + cn.index2; invokeDynamicClassSuffix = "##Lambda_" + cn.index1 + "_" + cn.index2;
} }
@ -139,6 +138,7 @@ public class InvocationExprent extends Exprent {
instance = instance.copy(); instance = instance.copy();
} }
invocationTyp = expr.getInvocationTyp(); invocationTyp = expr.getInvocationTyp();
invokeDynamicClassSuffix = expr.getInvokeDynamicClassSuffix();
stringDescriptor = expr.getStringDescriptor(); stringDescriptor = expr.getStringDescriptor();
descriptor = expr.getDescriptor(); descriptor = expr.getDescriptor();
lstParameters = new ArrayList<Exprent>(expr.getLstParameters()); lstParameters = new ArrayList<Exprent>(expr.getLstParameters());
@ -193,39 +193,7 @@ public class InvocationExprent extends Exprent {
tracer.addMapping(bytecode); tracer.addMapping(bytecode);
/*if (invocationTyp == INVOKE_DYNAMIC) { if (isStatic) {
// ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
//
// if(node != null) {
// ClassNode lambda_node = DecompilerContext.getClassprocessor().getMapRootClasses().get(node.classStruct.qualifiedName + invokeDynamicClassSuffix);
// if(lambda_node != null) {
//
// String typename = ExprProcessor.getCastTypeName(lambda_node.anonimousClassType);
//
// StringWriter strwriter = new StringWriter();
// BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
//
// ClassWriter clwriter = new ClassWriter();
//
// try {
// bufstrwriter.write("new " + typename + "() {");
// bufstrwriter.newLine();
//
//
//
// bufstrwriter.flush();
// } catch(IOException ex) {
// throw new RuntimeException(ex);
// }
//
// buf.append(strwriter.toString());
//
// }
// }
}
else*/ if (isStatic) {
ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
if (node == null || !classname.equals(node.classStruct.qualifiedName)) { if (node == null || !classname.equals(node.classStruct.qualifiedName)) {
buf.append(DecompilerContext.getImportCollector().getShortName(ExprProcessor.buildJavaClassName(classname))); buf.append(DecompilerContext.getImportCollector().getShortName(ExprProcessor.buildJavaClassName(classname)));

Loading…
Cancel
Save