java-decompiler: more lambdas
This commit is contained in:
@@ -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)));
|
||||||
|
|||||||
Reference in New Issue
Block a user