package com.oracle.svm.methodhandles;
import static com.oracle.svm.core.annotate.TargetElement.CONSTRUCTOR_NAME;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.Inject;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import com.oracle.svm.core.annotate.TargetElement;
@TargetClass(className = "java.lang.invoke.BoundMethodHandle", onlyWith = MethodHandlesSupported.class)
final class Target_java_lang_invoke_BoundMethodHandle {
@Alias static Target_java_lang_invoke_BoundMethodHandle_Specializer SPECIALIZER;
@Alias
@TargetElement(name = CONSTRUCTOR_NAME)
native void constructor(MethodType type, Target_java_lang_invoke_LambdaForm form);
@Alias
static native Target_java_lang_invoke_BoundMethodHandle_SpeciesData speciesDataFor(Target_java_lang_invoke_LambdaForm form);
}
@TargetClass(className = "java.lang.invoke.SimpleMethodHandle", onlyWith = MethodHandlesSupported.class)
final class Target_java_lang_invoke_SimpleMethodHandle {
@Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)
Target_java_lang_invoke_BoundMethodHandle_SpeciesData speciesData;
@Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)
Object[] args;
@Substitute
Target_java_lang_invoke_SimpleMethodHandle(MethodType type, Target_java_lang_invoke_LambdaForm form) {
SubstrateUtil.cast(this, Target_java_lang_invoke_BoundMethodHandle.class).constructor(type, form);
}
@Substitute
Target_java_lang_invoke_BoundMethodHandle_SpeciesData speciesData() {
if (speciesData == null) {
speciesData = Target_java_lang_invoke_BoundMethodHandle.speciesDataFor(SubstrateUtil.cast(this, Target_java_lang_invoke_MethodHandle.class).internalForm());
}
return speciesData;
}
@Substitute
Target_java_lang_invoke_BoundMethodHandle copyWithExtendL(MethodType type, Target_java_lang_invoke_LambdaForm form, Object newArg) {
return BoundMethodHandleUtils.make(type, form, BoundMethodHandleUtils.speciesKey(this) + "L", BoundMethodHandleUtils.appendArgs(args, newArg));
}
@Substitute
Target_java_lang_invoke_BoundMethodHandle copyWithExtendI(MethodType type, Target_java_lang_invoke_LambdaForm form, int newArg) {
return BoundMethodHandleUtils.make(type, form, BoundMethodHandleUtils.speciesKey(this) + "I", BoundMethodHandleUtils.appendArgs(args, newArg));
}
@Substitute
Target_java_lang_invoke_BoundMethodHandle copyWithExtendJ(MethodType type, Target_java_lang_invoke_LambdaForm form, long newArg) {
return BoundMethodHandleUtils.make(type, form, BoundMethodHandleUtils.speciesKey(this) + "J", BoundMethodHandleUtils.appendArgs(args, newArg));
}
@Substitute
Target_java_lang_invoke_BoundMethodHandle copyWithExtendF(MethodType type, Target_java_lang_invoke_LambdaForm form, float newArg) {
return BoundMethodHandleUtils.make(type, form, BoundMethodHandleUtils.speciesKey(this) + "F", BoundMethodHandleUtils.appendArgs(args, newArg));
}
@Substitute
Target_java_lang_invoke_BoundMethodHandle copyWithExtendD(MethodType type, Target_java_lang_invoke_LambdaForm form, double newArg) {
return BoundMethodHandleUtils.make(type, form, BoundMethodHandleUtils.speciesKey(this) + "D", BoundMethodHandleUtils.appendArgs(args, newArg));
}
@Substitute
Target_java_lang_invoke_BoundMethodHandle copyWith(MethodType type, Target_java_lang_invoke_LambdaForm form) {
return BoundMethodHandleUtils.make(type, form, BoundMethodHandleUtils.speciesKey(this), args);
}
}
@TargetClass(className = "java.lang.invoke.BoundMethodHandle", innerClass = "Species_L", onlyWith = MethodHandlesSupported.class)
final class Target_java_lang_invoke_BoundMethodHandle_Species_L {
@Substitute
static Target_java_lang_invoke_BoundMethodHandle make(MethodType mt, Target_java_lang_invoke_LambdaForm lf, Object argL0) {
return BoundMethodHandleUtils.make(mt, lf, "L", argL0);
}
}
@TargetClass(className = "java.lang.invoke.BoundMethodHandle", innerClass = "SpeciesData", onlyWith = MethodHandlesSupported.class)
final class Target_java_lang_invoke_BoundMethodHandle_SpeciesData {
}
@TargetClass(className = "java.lang.invoke.BoundMethodHandle", innerClass = "Specializer", onlyWith = MethodHandlesSupported.class)
final class Target_java_lang_invoke_BoundMethodHandle_Specializer {
}
final class BoundMethodHandleUtils {
static Target_java_lang_invoke_BoundMethodHandle make(MethodType type, Target_java_lang_invoke_LambdaForm form, String species, Object... args) {
Target_java_lang_invoke_SimpleMethodHandle bmh = new Target_java_lang_invoke_SimpleMethodHandle(type, form);
bmh.speciesData = SubstrateUtil.cast(Target_java_lang_invoke_BoundMethodHandle.SPECIALIZER, Target_java_lang_invoke_ClassSpecializer.class).findSpecies(species);
bmh.args = (args != null) ? Arrays.copyOf(args, args.length) : new Object[0];
return SubstrateUtil.cast(bmh, Target_java_lang_invoke_BoundMethodHandle.class);
}
static Object[] appendArgs(Object[] args, Object newArg) {
if (args == null) {
return new Object[]{newArg};
}
Object[] newArgs = new Object[args.length + 1];
System.arraycopy(args, 0, newArgs, 0, args.length);
newArgs[args.length] = newArg;
return newArgs;
}
static String speciesKey(Target_java_lang_invoke_SimpleMethodHandle bmh) {
return SubstrateUtil.cast(bmh.speciesData(), Target_java_lang_invoke_ClassSpecializer_SpeciesData.class).key();
}
}