/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.lang.invoke;
import sun.invoke.util.VerifyAccess;
import java.lang.invoke.LambdaForm.Name;
import java.lang.invoke.MethodHandles.Lookup;
import sun.invoke.util.Wrapper;
import java.io.*;
import java.util.*;
import com.sun.xml.internal.ws.org.objectweb.asm.*;
import java.lang.reflect.*;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyType;
/**
* Code generation backend for LambdaForm.
*
* @author John Rose, JSR 292 EG
*/
class InvokerBytecodeGenerator {
/** Define class names for convenience. */
private static final String MH = "java/lang/invoke/MethodHandle";
private static final String BMH = "java/lang/invoke/BoundMethodHandle";
private static final String LF = "java/lang/invoke/LambdaForm";
private static final String LFN = "java/lang/invoke/LambdaForm$Name";
private static final String CLS = "java/lang/Class";
private static final String OBJ = "java/lang/Object";
private static final String OBJARY = "[Ljava/lang/Object;";
private static final String LF_SIG = "L" + LF + ";";
private static final String LFN_SIG = "L" + LFN + ";";
private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
/** Name of its super class*/
private static final String superName = LF;
/** Name of new class */
private final String className;
/** Name of the source file (for stack trace printing). */
private final String sourceFile;
private final LambdaForm lambdaForm;
private final String invokerName;
private final MethodType invokerType;
private final int[] localsMap;
/** ASM bytecode generation. */
private ClassWriter cw;
private MethodVisitor mv;
private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
private static final Class> HOST_CLASS = LambdaForm.class;
private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
String className, String invokerName, MethodType invokerType) {
if (invokerName.contains(".")) {
int p = invokerName.indexOf(".");
className = invokerName.substring(0, p);
invokerName = invokerName.substring(p+1);
}
if (DUMP_CLASS_FILES) {
className = makeDumpableClassName(className);
}
this.className = superName + "$" + className;
this.sourceFile = "LambdaForm$" + className;
this.lambdaForm = lambdaForm;
this.invokerName = invokerName;
this.invokerType = invokerType;
this.localsMap = new int[localsMapSize];
}
private InvokerBytecodeGenerator(String className, String invokerName, MethodType invokerType) {
this(null, invokerType.parameterCount(),
className, invokerName, invokerType);
// Create an array to map name indexes to locals indexes.
for (int i = 0; i < localsMap.length; i++) {
localsMap[i] = invokerType.parameterSlotCount() - invokerType.parameterSlotDepth(i);
}
}
private InvokerBytecodeGenerator(String className, LambdaForm form, MethodType invokerType) {
this(form, form.names.length,
className, form.debugName, invokerType);
// Create an array to map name indexes to locals indexes.
Name[] names = form.names;
for (int i = 0, index = 0; i < localsMap.length; i++) {
localsMap[i] = index;
index += Wrapper.forBasicType(names[i].type).stackSlots();
}
}
/** instance counters for dumped classes */
private final static HashMap DUMP_CLASS_FILES_COUNTERS;
/** debugging flag for saving generated class files */
private final static File DUMP_CLASS_FILES_DIR;
static {
if (DUMP_CLASS_FILES) {
DUMP_CLASS_FILES_COUNTERS = new HashMap<>();
try {
File dumpDir = new File("DUMP_CLASS_FILES");
if (!dumpDir.exists()) {
dumpDir.mkdirs();
}
DUMP_CLASS_FILES_DIR = dumpDir;
System.out.println("Dumping class files to "+DUMP_CLASS_FILES_DIR+"/...");
} catch (Exception e) {
throw newInternalError(e);
}
} else {
DUMP_CLASS_FILES_COUNTERS = null;
DUMP_CLASS_FILES_DIR = null;
}
}
static void maybeDump(final String className, final byte[] classFile) {
if (DUMP_CLASS_FILES) {
System.out.println("dump: " + className);
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Void run() {
try {
String dumpName = className;
//dumpName = dumpName.replace('/', '-');
File dumpFile = new File(DUMP_CLASS_FILES_DIR, dumpName+".class");
dumpFile.getParentFile().mkdirs();
FileOutputStream file = new FileOutputStream(dumpFile);
file.write(classFile);
file.close();
return null;
} catch (IOException ex) {
throw newInternalError(ex);
}
}
});
}
}
private static String makeDumpableClassName(String className) {
Integer ctr;
synchronized (DUMP_CLASS_FILES_COUNTERS) {
ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
if (ctr == null) ctr = 0;
DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
}
String sfx = ctr.toString();
while (sfx.length() < 3)
sfx = "0"+sfx;
className += sfx;
return className;
}
class CpPatch {
final int index;
final String placeholder;
final Object value;
CpPatch(int index, String placeholder, Object value) {
this.index = index;
this.placeholder = placeholder;
this.value = value;
}
public String toString() {
return "CpPatch/index="+index+",placeholder="+placeholder+",value="+value;
}
}
Map