net.wpm.codegen.Utils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of records Show documentation
Show all versions of records Show documentation
C-Struct like features for Java 6+ to improve performance.
The newest version!
/*
* Copyright (C) 2015 SoftIndex LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.wpm.codegen;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;
import net.wpm.codegen.Context;
import net.wpm.codegen.Expression;
import net.wpm.codegen.VarLocal;
import net.wpm.codegen.utils.Preconditions;
import net.wpm.codegen.utils.Primitives;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import static java.lang.ClassLoader.getSystemClassLoader;
import static java.lang.String.format;
import static java.util.Arrays.asList;
import static org.objectweb.asm.Type.CHAR_TYPE;
import static org.objectweb.asm.Type.getType;
public class Utils {
private static final Map wrapperToPrimitive = new HashMap<>();
static {
for (Class> primitiveType : Primitives.allPrimitiveTypes()) {
Class> wrappedType = Primitives.wrap(primitiveType);
wrapperToPrimitive.put(wrappedType.getName(), getType(primitiveType));
}
}
private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
private static final Method INT_VALUE = Method.getMethod("int intValue()");
private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()");
private static final Method LONG_VALUE = Method.getMethod("long longValue()");
private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
private static final Method SHORT_VALUE = Method.getMethod("short shortValue()");
private static final Method BYTE_VALUE = Method.getMethod("byte byteValue()");
private static final Type BOOLEAN_TYPE = getType(Boolean.class);
private static final Type CHARACTER_TYPE = getType(Character.class);
private static final Type BYTE_TYPE = getType(Byte.class);
private static final Type SHORT_TYPE = getType(Short.class);
private static final Type INT_TYPE = getType(Integer.class);
private static final Type FLOAT_TYPE = getType(Float.class);
private static final Type LONG_TYPE = getType(Long.class);
private static final Type DOUBLE_TYPE = getType(Double.class);
private static final Type VOID_TYPE = getType(Void.class);
public static boolean isPrimitiveType(Type type) {
int sort = type.getSort();
return sort == Type.BOOLEAN ||
sort == Type.CHAR ||
sort == Type.BYTE ||
sort == Type.SHORT ||
sort == Type.INT ||
sort == Type.FLOAT ||
sort == Type.LONG ||
sort == Type.DOUBLE ||
sort == Type.VOID;
}
public static boolean isWrapperType(Type type) {
return type.getSort() == Type.OBJECT &&
wrapperToPrimitive.containsKey(type.getClassName());
}
public static Method primitiveValueMethod(Type type) {
if (type.equals(getType(char.class)) || type.equals(CHAR_TYPE))
return CHAR_VALUE;
if (type.equals(getType(boolean.class)) || type.equals(BOOLEAN_TYPE))
return BOOLEAN_VALUE;
if (type.equals(getType(double.class)) || type.equals(DOUBLE_TYPE))
return DOUBLE_VALUE;
if (type.equals(getType(float.class)) || type.equals(FLOAT_TYPE))
return FLOAT_VALUE;
if (type.equals(getType(long.class)) || type.equals(LONG_TYPE))
return LONG_VALUE;
if (type.equals(getType(int.class)) || type.equals(INT_TYPE))
return INT_VALUE;
if (type.equals(getType(short.class)) || type.equals(SHORT_TYPE))
return SHORT_VALUE;
if (type.equals(getType(byte.class)) || type.equals(BYTE_TYPE))
return BYTE_VALUE;
throw new RuntimeException(format("No primitive value method for %s ", type.getClassName()));
}
public static Type wrap(Type type) {
int sort = type.getSort();
if (sort == Type.BOOLEAN)
return BOOLEAN_TYPE;
if (sort == Type.CHAR)
return CHARACTER_TYPE;
if (sort == Type.BYTE)
return BYTE_TYPE;
if (sort == Type.SHORT)
return SHORT_TYPE;
if (sort == Type.INT)
return INT_TYPE;
if (sort == Type.FLOAT)
return FLOAT_TYPE;
if (sort == Type.LONG)
return LONG_TYPE;
if (sort == Type.DOUBLE)
return DOUBLE_TYPE;
if (sort == Type.VOID)
return VOID_TYPE;
throw new RuntimeException(format("%s is not primitive", type.getClassName()));
}
public static Type unwrap(Type type) {
Preconditions.check(type.getSort() == Type.OBJECT);
Type result = wrapperToPrimitive.get(type.getClassName());
Preconditions.check(result != null);
return result;
}
public static Type complementTypeOrNull(Type type) {
if (isPrimitiveType(type))
return wrap(type);
if (isWrapperType(type))
return unwrap(type);
return null;
}
public static Type complementType(Type type) {
Type result = complementTypeOrNull(type);
if (result != null)
return result;
throw new RuntimeException(format("%s is not primitive or wrapper", type.getClassName()));
}
public static Class> getJavaType(ClassLoader classLoader, Type type) {
int sort = type.getSort();
if (sort == Type.BOOLEAN)
return boolean.class;
if (sort == Type.CHAR)
return char.class;
if (sort == Type.BYTE)
return byte.class;
if (sort == Type.SHORT)
return short.class;
if (sort == Type.INT)
return int.class;
if (sort == Type.FLOAT)
return float.class;
if (sort == Type.LONG)
return long.class;
if (sort == Type.DOUBLE)
return double.class;
if (sort == Type.VOID)
return void.class;
if (sort == Type.OBJECT) {
try {
return classLoader.loadClass(type.getClassName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(format("No class %s in class loader", type.getClassName()), e);
}
}
if (sort == Type.ARRAY) {
Class> result;
if (type.equals(getType(Object[].class))) {
result = Object[].class;
} else {
final String className = type.getDescriptor().replace('/', '.');
try {
result = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(format("No class %s in Class.forName", className), e);
}
}
return result;
}
throw new RuntimeException(format("No Java type for %s", type.getClassName()));
}
public static Class> getJavaType(Type type) {
return getJavaType(getSystemClassLoader(), type);
}
public static Class> tryGetJavaType(Type type) {
return tryGetJavaType(getSystemClassLoader(), type);
}
public static Class> tryGetJavaType(ClassLoader classLoader, Type type) {
int sort = type.getSort();
if (sort == Type.BOOLEAN)
return boolean.class;
if (sort == Type.CHAR)
return char.class;
if (sort == Type.BYTE)
return byte.class;
if (sort == Type.SHORT)
return short.class;
if (sort == Type.INT)
return int.class;
if (sort == Type.FLOAT)
return float.class;
if (sort == Type.LONG)
return long.class;
if (sort == Type.DOUBLE)
return double.class;
if (sort == Type.VOID)
return void.class;
if (sort == Type.OBJECT) {
try {
return classLoader.loadClass(type.getClassName());
} catch (ClassNotFoundException e) {
return Object.class;
}
}
if (sort == Type.ARRAY) {
Class> result;
if (type.equals(getType(Object[].class))) {
result = Object[].class;
} else {
final String className = type.getDescriptor().replace('/', '.');
try {
result = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(format("No class %s in Class.forName", className), e);
}
}
return result;
}
return Object.class;
}
public static void invokeVirtualOrInterface(GeneratorAdapter g, Class> owner, Method method) {
if (owner.isInterface())
g.invokeInterface(getType(owner), method);
else
g.invokeVirtual(getType(owner), method);
}
public static VarLocal newLocal(Context ctx, Type type) {
int local = ctx.getGeneratorAdapter().newLocal(type);
return new VarLocal(local);
}
public static void loadAndCast(Context ctx, Expression expression, Type targetType) {
Type type = expression.load(ctx);
cast(ctx, type, targetType);
}
public static void cast(Context ctx, Type type, Type targetType) {
GeneratorAdapter g = ctx.getGeneratorAdapter();
if (type.equals(targetType)) {
return;
}
if (targetType == Type.VOID_TYPE) {
if (type.getSize() == 1)
g.pop();
if (type.getSize() == 2)
g.pop2();
return;
}
if (type == Type.VOID_TYPE) {
throw new RuntimeException(format("Can't cast VOID_TYPE to %s. %s",
targetType.getClassName(),
exceptionInGeneratedClass(ctx)));
}
if (type.equals(ctx.getThisType())) {
final Class> javaType = getJavaType(ctx.getClassLoader(), targetType);
for (Class> aClass : ctx.getOtherClasses()) {
if (javaType.isAssignableFrom(aClass)) {
return;
}
}
throw new RuntimeException(format("Can't cast self %s to %s, %s",
type.getClassName(),
targetType.getClassName(),
exceptionInGeneratedClass(ctx)));
}
if (!type.equals(ctx.getThisType()) && !targetType.equals(ctx.getThisType()) &&
getJavaType(ctx.getClassLoader(), targetType).isAssignableFrom(getJavaType(ctx.getClassLoader(), type))) {
return;
}
if (targetType.equals(getType(Object.class)) && isPrimitiveType(type)) {
g.box(type);
g.cast(wrap(type), getType(Object.class));
return;
}
if ((isPrimitiveType(type) || isWrapperType(type)) &&
(isPrimitiveType(targetType) || isWrapperType(targetType))) {
Type targetTypePrimitive = isPrimitiveType(targetType) ? targetType : unwrap(targetType);
if (isWrapperType(type)) {
g.invokeVirtual(type, primitiveValueMethod(targetType));
return;
}
assert isPrimitiveType(type);
if (type != targetTypePrimitive) {
g.cast(type, targetTypePrimitive);
}
if (isWrapperType(targetType)) {
g.valueOf(targetTypePrimitive);
}
return;
}
g.checkCast(targetType);
}
public static String exceptionInGeneratedClass(Context ctx) {
return format("Throwed in generated class %s in method %s",
ctx.getThisType().getClassName(),
ctx.getNewMethod()
);
}
public static String argsToString(T[] args) {
return argsToString(asList(args));
}
public static String argsToString(T[] args, String separator) {
return argsToString(asList(args), separator);
}
public static String argsToString(Collection args) {
return argsToString(args, ", ");
}
public static String argsToString(Collection args, String separator) {
StringBuilder stringBuilder = new StringBuilder();
Iterator iterator = args.iterator();
stringBuilder.append(iterator.next());
while (iterator.hasNext()) {
stringBuilder.append(separator).append(iterator.next());
}
return stringBuilder.toString();
}
}