Skip to content

Commit

Permalink
ConstantDynamics
Browse files Browse the repository at this point in the history
  • Loading branch information
wagyourtail committed Aug 17, 2024
1 parent acdb729 commit 9541210
Show file tree
Hide file tree
Showing 20 changed files with 1,519 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ public int take() {
return buffer.charAt(pos++);
}

public String takeUntil(char character) {
StringBuilder sb = new StringBuilder();
int next = peek();
while (next != -1 && next != character) {
sb.append((char) take());
next = peek();
}
return sb.toString();
}

public String takeUntil(Set<Integer> c) {
StringBuilder sb = new StringBuilder();
while (pos < buffer.length()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package xyz.wagyourtail.jvmdg.j11.stub.java_base;

import xyz.wagyourtail.jvmdg.util.Utils;
import xyz.wagyourtail.jvmdg.version.Adapter;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

@Adapter("java/lang/invoke/ConstantBootstraps")
public class J_L_I_ConstantBootstraps {

public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type) {
if (Objects.requireNonNull(type).isPrimitive()) {
throw new IllegalArgumentException("Primitive type cannot be null");
}
return null;
}

public static Class<?> primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type) {
if (!Objects.requireNonNull(type).equals(Class.class)) {
throw new IllegalArgumentException("Type must be Class");
}
try {
return Utils.getClassForDesc(name);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Primitive not found", e);
}
}

public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type) {
Objects.requireNonNull(lookup);
Objects.requireNonNull(name);
Objects.requireNonNull(type);
checkClass(lookup, type);
return Enum.valueOf(type, name);
}

public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type, Class<?> declaringClass) {
Objects.requireNonNull(lookup);
Objects.requireNonNull(name);
Objects.requireNonNull(type);
Objects.requireNonNull(declaringClass);

MethodHandle h;
try {
Field f = declaringClass.getDeclaredField(name);
if (!Modifier.isFinal(f.getModifiers())) {
throw new IncompatibleClassChangeError("not a final field: " + name);
}
h = lookup.unreflectGetter(f);
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
} catch (IllegalAccessException e) {
throw new IllegalAccessError(e.getMessage());
}
try {
return h.invoke();
} catch (Throwable t) {
Utils.sneakyThrow(t);
}
throw new AssertionError("unreachable");
}

public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type) {
Objects.requireNonNull(type);
Class<?> declaring = type.isPrimitive() ? Utils.getBoxFor(type) : type;
return getStaticFinal(lookup, name, type, declaring);
}

public static Object invoke(MethodHandles.Lookup lookup, String name, Class<?> type, MethodHandle handle, Object... args) throws Throwable {
Objects.requireNonNull(type);
Objects.requireNonNull(handle);
Objects.requireNonNull(args);
if (type != handle.type().returnType()) {
handle = handle.asType(handle.type().changeReturnType(type)).withVarargs(handle.isVarargsCollector());
}
return handle.invokeWithArguments(args);
}

/**
* callsite for ldc condy to become an invokeDynamic
*/
public static CallSite ldcCondyToIndy(MethodHandles.Lookup lookup, String invocationName, MethodType invokeType, MethodHandle condyBSM, Object... condyArgs) throws Throwable {
Objects.requireNonNull(lookup);
Objects.requireNonNull(invocationName);
Objects.requireNonNull(condyBSM);
Objects.requireNonNull(condyArgs);
if (invokeType.parameterCount() > 0) {
throw new IllegalArgumentException("Unexpected arguments");
}
Object[] args = new Object[condyArgs.length + 3];
args[0] = lookup;
args[1] = invocationName;
args[2] = invokeType.returnType();
System.arraycopy(condyArgs, 0, args, 3, condyArgs.length);
Object value = condyBSM.invokeWithArguments(args);
return new ConstantCallSite(MethodHandles.constant(invokeType.returnType(), value));
}

/**
* callsite for condy's within invokeDynamics
*
* flattened args, inner condy args:
* MethodHandle condyBSM, String name, Class desc, Int argCount, String condyArgs, // use condy bsm to determine arg count to eat
*
* @param condyArgs chars who's int value are the args to parse as condys, in order.
*/
public static CallSite nestedCondyInIndy(MethodHandles.Lookup lookup, String invocationName, MethodType invokeType, MethodHandle indyBsm, String condyArgs, Object... args) throws Throwable {
Objects.requireNonNull(lookup);
Objects.requireNonNull(invocationName);
Objects.requireNonNull(indyBsm);
Objects.requireNonNull(condyArgs);
char[] condyArgLst = (condyArgs).toCharArray();
List<Object> indyArgs = new ArrayList<>();
indyArgs.add(lookup);
indyArgs.add(invocationName);
indyArgs.add(invokeType);
for (int i = 0, j = 0; i < args.length; i++) {
if (j < condyArgLst.length && i == condyArgLst[j]) {
j++;
int[] iValue = new int[] {i};
indyArgs.add(getCondyValue(lookup, args, iValue));
i = iValue[0];
} else {
indyArgs.add(args[i]);
}
}
return (CallSite) indyBsm.invokeWithArguments(indyArgs);
}

private static Object getCondyValue(MethodHandles.Lookup lookup, Object[] args, int[] iValue) throws Throwable {
int i = iValue[0];
MethodHandle bsm = (MethodHandle) args[i++];
String name = (String) args[i++];
Class<?> desc = (Class<?>) args[i++];
int argCount = (int) args[i++] + 3;
char[] condyArgLst = ((String) args[i++]).toCharArray();
List<Object> condyArgs = new ArrayList<>();
condyArgs.add(lookup);
condyArgs.add(name);
condyArgs.add(desc);
for (int j = 0, k = 3; k < argCount; i++, k++) {
if (j < condyArgLst.length && i == condyArgLst[j]) {
j++;
iValue[0] = i;
condyArgs.add(getCondyValue(lookup, args, iValue));
i = iValue[0];
} else {
condyArgs.add(args[i]);
}
}
iValue[0] = --i;
return bsm.invokeWithArguments(condyArgs);
}

// var handle stuff

private static void checkClass(MethodHandles.Lookup lookup, Class<?> type) {
try {
lookup.accessClass(type);
} catch (IllegalAccessException e) {
throw new IllegalAccessError(e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private static void validateMemberName(String name) {

static J_L_C_ClassDesc of(String name) {
validateBinaryClassName(name);
return J_L_C_ClassDesc.ofDescriptor("L" + name + ";");
return J_L_C_ClassDesc.ofDescriptor("L" + name.replace('.', '/') + ";");
}

static J_L_C_ClassDesc of(String packageName, String className) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package xyz.wagyourtail.jvmdg.j12.stub.java_base;

import xyz.wagyourtail.jvmdg.version.Adapter;

import java.lang.invoke.ConstantBootstraps;

@Adapter("java/lang/constant/ConstantDescs")
public class J_L_C_ConstantDescs {

public static final String DEFAULT_NAME = "_";

public static final J_L_C_ClassDesc CD_Object = J_L_C_ClassDesc.of("java.lang.Object");
public static final J_L_C_ClassDesc CD_String = J_L_C_ClassDesc.of("java.lang.String");
public static final J_L_C_ClassDesc CD_Class = J_L_C_ClassDesc.of("java.lang.Class");
public static final J_L_C_ClassDesc CD_Number = J_L_C_ClassDesc.of("java.lang.Number");
public static final J_L_C_ClassDesc CD_Integer = J_L_C_ClassDesc.of("java.lang.Integer");
public static final J_L_C_ClassDesc CD_Long = J_L_C_ClassDesc.of("java.lang.Long");
public static final J_L_C_ClassDesc CD_Float = J_L_C_ClassDesc.of("java.lang.Float");
public static final J_L_C_ClassDesc CD_Double = J_L_C_ClassDesc.of("java.lang.Double");
public static final J_L_C_ClassDesc CD_Short = J_L_C_ClassDesc.of("java.lang.Short");
public static final J_L_C_ClassDesc CD_Byte = J_L_C_ClassDesc.of("java.lang.Byte");
public static final J_L_C_ClassDesc CD_Character = J_L_C_ClassDesc.of("java.lang.Character");
public static final J_L_C_ClassDesc CD_Boolean = J_L_C_ClassDesc.of("java.lang.Boolean");
public static final J_L_C_ClassDesc CD_Void = J_L_C_ClassDesc.of("java.lang.Void");
public static final J_L_C_ClassDesc CD_Throwable = J_L_C_ClassDesc.of("java.lang.Throwable");
public static final J_L_C_ClassDesc CD_Exception = J_L_C_ClassDesc.of("java.lang.Exception");
public static final J_L_C_ClassDesc CD_Enum = J_L_C_ClassDesc.of("java.lang.Enum");
// public static final J_L_C_ClassDesc CD_VarHandle = J_L_C_ClassDesc.of("java.lang.VarHandle");
public static final J_L_C_ClassDesc CD_MethodHandles = J_L_C_ClassDesc.of("java.lang.MethodHandles");
public static final J_L_C_ClassDesc CD_MethodHandles_Lookup = J_L_C_ClassDesc.of("java.lang.MethodHandles.Lookup");
public static final J_L_C_ClassDesc CD_MethodHandle = J_L_C_ClassDesc.of("java.lang.MethodHandle");
public static final J_L_C_ClassDesc CD_MethodType = J_L_C_ClassDesc.of("java.lang.MethodType");
public static final J_L_C_ClassDesc CD_CallSite = J_L_C_ClassDesc.of("java.lang.CallSite");
public static final J_L_C_ClassDesc CD_Collection = J_L_C_ClassDesc.of("java.lang.Collection");
public static final J_L_C_ClassDesc CD_List = J_L_C_ClassDesc.of("java.lang.List");
public static final J_L_C_ClassDesc CD_Set = J_L_C_ClassDesc.of("java.lang.Set");
public static final J_L_C_ClassDesc CD_Map = J_L_C_ClassDesc.of("java.lang.Map");
public static final J_L_C_ClassDesc CD_ConstantDesc = J_L_C_ClassDesc.of(J_L_C_ConstantDesc.class.getName());
public static final J_L_C_ClassDesc CD_ClassDesc = J_L_C_ClassDesc.of(J_L_C_ClassDesc.class.getName());
public static final J_L_C_ClassDesc CD_EnumDesc = J_L_C_ClassDesc.of(J_L_Enum$EnumDesc.class.getName());
public static final J_L_C_ClassDesc CD_MethodTypeDesc = J_L_C_ClassDesc.of(J_L_C_MethodTypeDesc.class.getName());
public static final J_L_C_ClassDesc CD_MethodHandleDesc = J_L_C_ClassDesc.of(J_L_C_MethodHandleDesc.class.getName());
public static final J_L_C_ClassDesc CD_DirectMethodHandleDesc = J_L_C_ClassDesc.of(J_L_C_DirectMethodHandleDesc.class.getName());
// public static final J_L_C_ClassDesc CD_VarHandleDesc
public static final J_L_C_ClassDesc CD_MethodHandleDesc_Kind = CD_MethodHandleDesc.nested("Kind");
public static final J_L_C_ClassDesc CD_DynamicConstantDesc = J_L_C_ClassDesc.of(J_L_C_DynamicConstantDesc.class.getName());
// public static final CD_DynamicCallSiteDesc
public static final J_L_C_ClassDesc CD_ConstantBootstraps = J_L_C_ClassDesc.of(ConstantBootstraps.class.getName());

private static final J_L_C_ClassDesc[] INDY_BSM = new J_L_C_ClassDesc[] {
CD_MethodHandles_Lookup,
CD_String,
CD_MethodType
};

private static final J_L_C_ClassDesc[] CONDY_BSM = new J_L_C_ClassDesc[] {
CD_MethodHandles_Lookup,
CD_String,
CD_Class
};

public static final J_L_C_DirectMethodHandleDesc BSM_PRIMITIVE_CLASS = ofConstantBootstrap(
CD_ConstantBootstraps,
"primitiveClass",
CD_Class
);

public static final J_L_C_DirectMethodHandleDesc BSM_ENUM_CONSTANT = ofConstantBootstrap(
CD_ConstantBootstraps,
"enumConstant",
CD_Enum
);

public static final J_L_C_DirectMethodHandleDesc BSM_GET_STATIC_FINAL = ofConstantBootstrap(
CD_ConstantBootstraps,
"getStaticFinal",
CD_Object,
CD_Class
);

public static final J_L_C_DirectMethodHandleDesc BSM_NULL_CONSTANT = ofConstantBootstrap(
CD_ConstantBootstraps,
"nullConstant",
CD_Object
);

// public static final J_L_C_DirectMethodHandleDesc BSM_VARHANDLE_FIELD

public static final J_L_C_DirectMethodHandleDesc BSM_INVOKE = ofConstantBootstrap(
CD_ConstantBootstraps,
"invoke",
CD_Object,
CD_MethodHandle,
CD_Object.arrayType()
);

public static final J_L_C_ClassDesc CD_int = J_L_C_ClassDesc.ofDescriptor("I");
public static final J_L_C_ClassDesc CD_long = J_L_C_ClassDesc.ofDescriptor("J");
public static final J_L_C_ClassDesc CD_float = J_L_C_ClassDesc.ofDescriptor("F");
public static final J_L_C_ClassDesc CD_double = J_L_C_ClassDesc.ofDescriptor("D");
public static final J_L_C_ClassDesc CD_short = J_L_C_ClassDesc.ofDescriptor("S");
public static final J_L_C_ClassDesc CD_byte = J_L_C_ClassDesc.ofDescriptor("B");
public static final J_L_C_ClassDesc CD_char = J_L_C_ClassDesc.ofDescriptor("C");
public static final J_L_C_ClassDesc CD_boolean = J_L_C_ClassDesc.ofDescriptor("Z");
public static final J_L_C_ClassDesc CD_void = J_L_C_ClassDesc.ofDescriptor("V");

public static final J_L_C_ConstantDesc NULL = J_L_C_DynamicConstantDesc.ofNamed(BSM_NULL_CONSTANT, "_", CD_Object);
public static final J_L_C_DynamicConstantDesc<Boolean> TRUE = J_L_C_DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "TRUE", CD_Boolean, CD_Boolean);
public static final J_L_C_DynamicConstantDesc<Boolean> FALSE = J_L_C_DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "FALSE", CD_Boolean, CD_Boolean);

static final J_L_C_DirectMethodHandleDesc AS_TYPE = J_L_C_MethodHandleDesc.ofMethod(
J_L_C_DirectMethodHandleDesc.Kind.VIRTUAL,
CD_MethodHandle,
"asType",
J_L_C_MethodTypeDesc.of(CD_MethodHandle, CD_MethodType)
);

public static J_L_C_DirectMethodHandleDesc ofCallsiteBootstrap(
J_L_C_ClassDesc owner,
String name,
J_L_C_ClassDesc returnType,
J_L_C_ClassDesc... args
) {
return J_L_C_MethodHandleDesc.ofMethod(
J_L_C_DirectMethodHandleDesc.Kind.STATIC,
owner,
name,
J_L_C_MethodTypeDesc.of(
returnType,
args
).insertParameterTypes(0, INDY_BSM)
);
}

public static J_L_C_DirectMethodHandleDesc ofConstantBootstrap(
J_L_C_ClassDesc owner,
String name,
J_L_C_ClassDesc returnType,
J_L_C_ClassDesc... params
) {
return J_L_C_MethodHandleDesc.ofMethod(
J_L_C_DirectMethodHandleDesc.Kind.STATIC,
owner,
name,
J_L_C_MethodTypeDesc.of(
returnType,
params
).insertParameterTypes(0, CONDY_BSM)
);
}

}
Loading

0 comments on commit 9541210

Please sign in to comment.