org.qbicc.plugin.reflection.ReflectionIntrinsics Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qbicc-plugin-reflection Show documentation
Show all versions of qbicc-plugin-reflection Show documentation
Support for reflection at build and run time
package org.qbicc.plugin.reflection;
import static org.qbicc.graph.atomic.AccessModes.SinglePlain;
import java.util.ArrayList;
import java.util.List;
import org.jboss.logging.Logger;
import org.qbicc.context.ClassContext;
import org.qbicc.context.CompilationContext;
import org.qbicc.graph.BasicBlock;
import org.qbicc.graph.BasicBlockBuilder;
import org.qbicc.graph.BlockEarlyTermination;
import org.qbicc.graph.BlockLabel;
import org.qbicc.graph.InstanceMethodElementHandle;
import org.qbicc.graph.ParameterValue;
import org.qbicc.graph.StaticMethodElementHandle;
import org.qbicc.graph.Value;
import org.qbicc.graph.ValueHandle;
import org.qbicc.graph.literal.LiteralFactory;
import org.qbicc.graph.literal.ObjectLiteral;
import org.qbicc.graph.schedule.Schedule;
import org.qbicc.interpreter.Thrown;
import org.qbicc.interpreter.Vm;
import org.qbicc.interpreter.VmObject;
import org.qbicc.plugin.intrinsics.InstanceIntrinsic;
import org.qbicc.plugin.intrinsics.Intrinsics;
import org.qbicc.plugin.intrinsics.StaticIntrinsic;
import org.qbicc.plugin.patcher.Patcher;
import org.qbicc.pointer.InstanceMethodPointer;
import org.qbicc.pointer.Pointer;
import org.qbicc.pointer.StaticMethodPointer;
import org.qbicc.type.InstanceMethodType;
import org.qbicc.type.InvokableType;
import org.qbicc.type.StaticMethodType;
import org.qbicc.type.TypeSystem;
import org.qbicc.type.ValueType;
import org.qbicc.type.VoidType;
import org.qbicc.type.definition.DefinedTypeDefinition;
import org.qbicc.type.definition.LoadedTypeDefinition;
import org.qbicc.type.definition.MethodBody;
import org.qbicc.type.definition.MethodBodyFactory;
import org.qbicc.type.definition.classfile.ClassFile;
import org.qbicc.type.definition.element.BasicElement;
import org.qbicc.type.definition.element.ConstructorElement;
import org.qbicc.type.definition.element.ExecutableElement;
import org.qbicc.type.definition.element.MethodElement;
import org.qbicc.type.descriptor.ArrayTypeDescriptor;
import org.qbicc.type.descriptor.BaseTypeDescriptor;
import org.qbicc.type.descriptor.ClassTypeDescriptor;
import org.qbicc.type.descriptor.MethodDescriptor;
import org.qbicc.type.descriptor.TypeDescriptor;
public final class ReflectionIntrinsics {
private static final Logger log = Logger.getLogger("org.qbicc.plugin.reflection");
private ReflectionIntrinsics() {}
public static void register(CompilationContext ctxt) {
Intrinsics intrinsics = Intrinsics.get(ctxt);
Patcher patcher = Patcher.get(ctxt);
ClassContext bootstrapClassContext = ctxt.getBootstrapClassContext();
String methodHandleInt = "java/lang/invoke/MethodHandle";
String varHandleInt = "java/lang/invoke/VarHandle";
ClassTypeDescriptor methodHandleDesc = ClassTypeDescriptor.synthesize(bootstrapClassContext, methodHandleInt);
ClassTypeDescriptor objDesc = ClassTypeDescriptor.synthesize(bootstrapClassContext, "java/lang/Object");
ClassTypeDescriptor internalErrorDesc = ClassTypeDescriptor.synthesize(bootstrapClassContext, "java/lang/InternalError");
ClassTypeDescriptor throwableDesc = ClassTypeDescriptor.synthesize(bootstrapClassContext, "java/lang/Throwable");
ArrayTypeDescriptor objArrayDesc = ArrayTypeDescriptor.of(bootstrapClassContext, objDesc);
MethodDescriptor objArrayToObj = MethodDescriptor.synthesize(bootstrapClassContext, objDesc, List.of(objArrayDesc));
MethodDescriptor objArrayToVoid = MethodDescriptor.synthesize(bootstrapClassContext, BaseTypeDescriptor.V, List.of(objArrayDesc));
MethodDescriptor objArrayToBool = MethodDescriptor.synthesize(bootstrapClassContext, BaseTypeDescriptor.Z, List.of(objArrayDesc));
MethodDescriptor throwableToVoid = MethodDescriptor.synthesize(bootstrapClassContext, BaseTypeDescriptor.V, List.of(throwableDesc));
// mh.invoke(...) → mh.asType(actualType).invokeExact(...)
InstanceIntrinsic invokeIntrinsic = (builder, instance, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
if (instance instanceof ObjectLiteral instanceLit) {
// perform a build-time check
MethodDescriptor callSiteDescriptor = target.getCallSiteDescriptor();
BasicBlockBuilder fb = builder.getFirstBuilder();
Vm vm = Vm.requireCurrent();
try {
ClassContext classContext = target.getElement().getEnclosingType().getContext();
VmObject realType = vm.createMethodType(classContext, callSiteDescriptor);
Value realHandle;
LoadedTypeDefinition mhDef = target.getExecutable().getEnclosingType().load();
int asTypeIdx = mhDef.findMethodIndex(me -> me.nameEquals("asType"));
MethodElement asType = mhDef.getMethod(asTypeIdx);
// get the target statically
realHandle = lf.literalOf((VmObject) vm.invokeVirtual(asType, instanceLit.getValue(), List.of(realType)));
// and transform to `invokeExact`
ValueHandle invokeExactHandle = fb.exactMethodOf(realHandle, methodHandleDesc, "invokeExact", callSiteDescriptor);
return fb.call(invokeExactHandle, arguments);
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.invoke intrinsic: %s", t);
log.warnf(t, "Failed to expand MethodHandle.invoke intrinsic");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
} else {
// do not expand intrinsic; let the method be called
return null;
}
};
intrinsics.registerIntrinsic(methodHandleDesc, "invoke", invokeIntrinsic);
// (non-intrinsic version)
InstanceIntrinsic invokeMethodBody = (builder, instance, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
MethodDescriptor callSiteDescriptor = target.getCallSiteDescriptor();
BasicBlockBuilder fb = builder.getFirstBuilder();
Vm vm = Vm.requireCurrent();
try {
ClassContext classContext = target.getElement().getEnclosingType().getContext();
VmObject realType = vm.createMethodType(classContext, callSiteDescriptor);
Value realHandle;
LoadedTypeDefinition mhDef = target.getExecutable().getEnclosingType().load();
int asTypeIdx = mhDef.findMethodIndex(me -> me.nameEquals("asType"));
MethodElement asType = mhDef.getMethod(asTypeIdx);
// get the target dynamically
ValueHandle asTypeHandle = fb.virtualMethodOf(instance, asType);
realHandle = fb.call(asTypeHandle, List.of(lf.literalOf(realType)));
// and transform to `invokeExact`
ValueHandle invokeExactHandle = fb.exactMethodOf(realHandle, methodHandleDesc, "invokeExact", callSiteDescriptor);
throw new BlockEarlyTermination(fb.tailCall(invokeExactHandle, arguments));
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.invoke method: %s", t);
log.warnf(t, "Failed to expand MethodHandle.invoke method");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
};
patcher.replaceMethodBody(bootstrapClassContext, methodHandleInt, "invoke", objArrayToObj, new InstanceIntrinsicMethodBodyFactory(invokeMethodBody), 0);
// mh.invokeExact(...) → mh.checkType(type); mh.invokeBasic(...)
InstanceIntrinsic invokeExactIntrinsic = (builder, instance, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
if (instance instanceof ObjectLiteral instanceLit) {
MethodDescriptor callSiteDescriptor = target.getCallSiteDescriptor();
BasicBlockBuilder fb = builder.getFirstBuilder();
Vm vm = Vm.requireCurrent();
try {
ClassContext classContext = target.getElement().getEnclosingType().getContext();
VmObject realType = vm.createMethodType(classContext, callSiteDescriptor);
LoadedTypeDefinition mhDef = target.getExecutable().getEnclosingType().load();
int checkTypeIdx = mhDef.findMethodIndex(me -> me.nameEquals("checkType"));
MethodElement checkType = mhDef.getMethod(checkTypeIdx);
// check the type now
vm.invokeExact(checkType, instanceLit.getValue(), List.of(realType));
// type is OK; now we can forward to invokeBasic(...) on this same instance
ValueHandle invokeBasicHandle = fb.exactMethodOf(instance, methodHandleDesc, "invokeBasic", callSiteDescriptor);
return fb.call(invokeBasicHandle, arguments);
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.invokeExact intrinsic: %s", t);
log.warnf(t, "Failed to expand MethodHandle.invokeExact intrinsic");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
} else {
// do not expand intrinsic; let the method be called
return null;
}
};
intrinsics.registerIntrinsic(methodHandleDesc, "invokeExact", invokeExactIntrinsic);
InstanceIntrinsic invokeExactMethodBody = (builder, instance, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
MethodDescriptor callSiteDescriptor = target.getCallSiteDescriptor();
BasicBlockBuilder fb = builder.getFirstBuilder();
Vm vm = Vm.requireCurrent();
try {
ClassContext classContext = target.getElement().getEnclosingType().getContext();
VmObject realType = vm.createMethodType(classContext, callSiteDescriptor);
LoadedTypeDefinition mhDef = target.getExecutable().getEnclosingType().load();
int checkTypeIdx = mhDef.findMethodIndex(me -> me.nameEquals("checkType"));
MethodElement checkType = mhDef.getMethod(checkTypeIdx);
ValueHandle checkTypeHandle = fb.exactMethodOf(instance, checkType);
// check the type dynamically at run time
fb.call(checkTypeHandle, List.of(lf.literalOf(realType)));
// and transform to `invokeBasic`
ValueHandle invokeBasicHandle = fb.exactMethodOf(instance, methodHandleDesc, "invokeBasic", callSiteDescriptor);
throw new BlockEarlyTermination(fb.tailCall(invokeBasicHandle, arguments));
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.invokeExact method: %s", t);
log.warnf(t, "Failed to expand MethodHandle.invokeExact method");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
};
patcher.replaceMethodBody(bootstrapClassContext, methodHandleInt, "invokeExact", objArrayToObj, new InstanceIntrinsicMethodBodyFactory(invokeExactMethodBody), 0);
// mh.invokeBasic(...) → (*mh.form.vmentry)(...)
InstanceIntrinsic invokeBasicIntrinsic = (builder, instance, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
if (instance instanceof ObjectLiteral instanceLit) {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
try {
VmObject methodHandle = instanceLit.getValue();
VmObject lambdaForm = methodHandle.getMemory().loadRef(methodHandle.indexOf(reflection.methodHandleLambdaFormField), SinglePlain);
VmObject memberName = lambdaForm.getMemory().loadRef(lambdaForm.indexOf(reflection.lambdaFormMemberNameField), SinglePlain);
Pointer methodPtr = memberName.getMemory().loadPointer(memberName.indexOf(reflection.memberNameExactDispatcherField), SinglePlain);
// pass the method handle to the lambda form
ArrayList newArgs = new ArrayList<>(arguments.size() + 1);
newArgs.add(instance);
newArgs.addAll(arguments);
if (methodPtr instanceof StaticMethodPointer smp) {
// call the static method directly
return fb.call(fb.staticMethod(smp.getStaticMethod()), newArgs);
} else if (methodPtr instanceof InstanceMethodPointer imp) {
// todo: for now, we're using static helpers only
// call the exact method directly
return fb.call(fb.exactMethodOf(arguments.get(0), imp.getInstanceMethod()), newArgs.subList(1, newArgs.size()));
} else {
// ???
ctxt.warning(fb.getLocation(), "Unknown method handle pointer type: %s", methodPtr.getClass());
return null;
}
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.invokeBasic intrinsic: %s", t);
log.warnf(t, "Failed to expand MethodHandle.invokeBasic intrinsic");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
} else {
// do not expand intrinsic; let the method be called
return null;
}
};
intrinsics.registerIntrinsic(methodHandleDesc, "invokeBasic", invokeBasicIntrinsic);
InstanceIntrinsic invokeBasicMethodBody = (builder, instance, target, arguments) -> {
TypeSystem ts = ctxt.getTypeSystem();
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
Value lambdaForm = fb.load(fb.instanceFieldOf(fb.referenceHandle(instance), reflection.methodHandleLambdaFormField));
Value memberName = fb.load(fb.instanceFieldOf(fb.referenceHandle(lambdaForm), reflection.lambdaFormMemberNameField));
Value methodPtr = fb.load(fb.instanceFieldOf(fb.referenceHandle(memberName), reflection.memberNameExactDispatcherField));
// pass the method handle to the lambda form
ArrayList newArgs = new ArrayList<>(arguments.size() + 1);
newArgs.add(instance);
newArgs.addAll(arguments);
// todo: assume a static method or static dispatch helper
InstanceMethodType methodType = (InstanceMethodType) target.getExecutable().getType();
List parameterTypes = methodType.getParameterTypes();
StaticMethodType dispatcherType = ts.getStaticMethodType(methodType.getReturnType(), parameterTypes).withFirstParameterType(methodType.getReceiverType());
// cast to the matching static method pointer type for this particular helper shape
Value castMethodPtr = fb.bitCast(methodPtr, dispatcherType.getPointer());
throw new BlockEarlyTermination(fb.tailCall(fb.pointerHandle(castMethodPtr), newArgs));
};
patcher.replaceMethodBody(bootstrapClassContext, methodHandleInt, "invokeBasic", objArrayToObj, new InstanceIntrinsicMethodBodyFactory(invokeBasicMethodBody), 0);
// MH.linkToStatic(..., memberName) → (static *memberName.vmentry)(...)
StaticIntrinsic linkToStaticIntrinsic = (builder, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
int lastArg = arguments.size() - 1;
Value memberNameValue = arguments.get(lastArg);
if (memberNameValue instanceof ObjectLiteral memberNameLit) {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
try {
VmObject memberName = memberNameLit.getValue();
Pointer methodPtr = memberName.getMemory().loadPointer(memberName.indexOf(reflection.memberNameExactDispatcherField), SinglePlain);
if (methodPtr instanceof StaticMethodPointer smp) {
// call the static method directly
return fb.call(fb.staticMethod(smp.getStaticMethod()), arguments.subList(0, lastArg));
} else {
// ???
ctxt.warning(fb.getLocation(), "Unknown method handle pointer type: %s", methodPtr.getClass());
return null;
}
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.linkToStatic intrinsic: %s", t);
log.warnf(t, "Failed to expand MethodHandle.linkToStatic intrinsic");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
} else {
// do not expand intrinsic; let the method be called
return null;
}
};
intrinsics.registerIntrinsic(methodHandleDesc, "linkToStatic", linkToStaticIntrinsic);
StaticIntrinsic linkToStaticMethodBody = (builder, target, arguments) -> {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
int lastArg = arguments.size() - 1;
Value memberName = arguments.get(lastArg);
Value methodPtr = fb.load(fb.instanceFieldOf(fb.referenceHandle(memberName), reflection.memberNameExactDispatcherField));
StaticMethodType methodType = (StaticMethodType) target.getExecutable().getType();
// cast to the matching static method pointer type for this particular shape
Value castMethodPtr = fb.bitCast(methodPtr, methodType.trimLastParameter().getPointer());
throw new BlockEarlyTermination(fb.tailCall(fb.pointerHandle(castMethodPtr), arguments.subList(0, lastArg)));
};
patcher.replaceMethodBody(bootstrapClassContext, methodHandleInt, "linkToStatic", objArrayToObj, new StaticIntrinsicMethodBodyFactory(linkToStaticMethodBody), 0);
// MH.linkToInterface(..., memberName) → (static *memberName.vmentry)(...)
StaticIntrinsic linkToInterfaceIntrinsic = (builder, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
int lastArg = arguments.size() - 1;
Value memberNameValue = arguments.get(lastArg);
if (memberNameValue instanceof ObjectLiteral memberNameLit) {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
try {
VmObject memberName = memberNameLit.getValue();
Pointer methodPtr = memberName.getMemory().loadPointer(memberName.indexOf(reflection.memberNameExactDispatcherField), SinglePlain);
if (methodPtr instanceof StaticMethodPointer smp) {
// call the static helper method directly
return fb.call(fb.staticMethod(smp.getStaticMethod()), arguments.subList(0, lastArg));
} else {
// ???
ctxt.warning(fb.getLocation(), "Unknown method handle pointer type: %s", methodPtr.getClass());
return null;
}
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.linkToInterface intrinsic: %s", t);
log.warnf(t, "Failed to expand MethodHandle.linkToInterface intrinsic");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
} else {
// do not expand intrinsic; let the method be called
return null;
}
};
intrinsics.registerIntrinsic(methodHandleDesc, "linkToInterface", linkToInterfaceIntrinsic);
StaticIntrinsic linkToInterfaceMethodBody = (builder, target, arguments) -> {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
int lastArg = arguments.size() - 1;
Value memberName = arguments.get(lastArg);
Value methodPtr = fb.load(fb.instanceFieldOf(fb.referenceHandle(memberName), reflection.memberNameExactDispatcherField));
StaticMethodType methodType = (StaticMethodType) target.getExecutable().getType();
// cast to the matching static helper method pointer type for this particular shape
Value castMethodPtr = fb.bitCast(methodPtr, methodType.trimLastParameter().getPointer());
throw new BlockEarlyTermination(fb.tailCall(fb.pointerHandle(castMethodPtr), arguments.subList(0, lastArg)));
};
patcher.replaceMethodBody(bootstrapClassContext, methodHandleInt, "linkToInterface", objArrayToObj, new StaticIntrinsicMethodBodyFactory(linkToInterfaceMethodBody), 0);
StaticIntrinsic linkToSpecialIntrinsic = (builder, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
int lastArg = arguments.size() - 1;
Value memberNameValue = arguments.get(lastArg);
if (memberNameValue instanceof ObjectLiteral memberNameLit) {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
try {
VmObject memberName = memberNameLit.getValue();
Pointer methodPtr = memberName.getMemory().loadPointer(memberName.indexOf(reflection.memberNameExactDispatcherField), SinglePlain);
if (methodPtr instanceof StaticMethodPointer smp) {
// call the static helper method directly
return fb.call(fb.staticMethod(smp.getStaticMethod()), arguments.subList(0, lastArg));
} else {
// ???
ctxt.warning(fb.getLocation(), "Unknown method handle pointer type: %s", methodPtr.getClass());
return null;
}
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.linkToSpecial intrinsic: %s", t);
log.warnf(t, "Failed to expand MethodHandle.linkToSpecial intrinsic");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
} else {
// do not expand intrinsic; let the method be called
return null;
}
};
intrinsics.registerIntrinsic(methodHandleDesc, "linkToSpecial", linkToSpecialIntrinsic);
StaticIntrinsic linkToSpecialMethodBody = (builder, target, arguments) -> {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
int lastArg = arguments.size() - 1;
Value memberName = arguments.get(lastArg);
Value methodPtr = fb.load(fb.instanceFieldOf(fb.referenceHandle(memberName), reflection.memberNameExactDispatcherField));
StaticMethodType methodType = (StaticMethodType) target.getExecutable().getType();
// cast to the matching static helper method pointer type for this particular shape
Value castMethodPtr = fb.bitCast(methodPtr, methodType.trimLastParameter().getPointer());
throw new BlockEarlyTermination(fb.tailCall(fb.pointerHandle(castMethodPtr), arguments.subList(0, lastArg)));
};
patcher.replaceMethodBody(bootstrapClassContext, methodHandleInt, "linkToSpecial", objArrayToObj, new StaticIntrinsicMethodBodyFactory(linkToSpecialMethodBody), 0);
StaticIntrinsic linkToVirtualIntrinsic = (builder, target, arguments) -> {
LiteralFactory lf = ctxt.getLiteralFactory();
int lastArg = arguments.size() - 1;
Value memberNameValue = arguments.get(lastArg);
if (memberNameValue instanceof ObjectLiteral memberNameLit) {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
try {
VmObject memberName = memberNameLit.getValue();
Pointer methodPtr = memberName.getMemory().loadPointer(memberName.indexOf(reflection.memberNameExactDispatcherField), SinglePlain);
if (methodPtr instanceof StaticMethodPointer smp) {
// call the static helper method directly
return fb.call(fb.staticMethod(smp.getStaticMethod()), arguments.subList(0, lastArg));
} else {
// ???
ctxt.warning(fb.getLocation(), "Unknown method handle pointer type: %s", methodPtr.getClass());
return null;
}
} catch (Thrown t) {
ctxt.warning(fb.getLocation(), "Failed to expand MethodHandle.linkToVirtual intrinsic: %s", t);
log.warnf(t, "Failed to expand MethodHandle.linkToVirtual intrinsic");
Value ie = fb.new_(internalErrorDesc);
fb.call(fb.constructorOf(ie, internalErrorDesc, throwableToVoid), List.of(lf.literalOf(t.getThrowable())));
throw new BlockEarlyTermination(fb.throw_(ie));
}
} else {
// do not expand intrinsic; let the method be called
return null;
}
};
intrinsics.registerIntrinsic(methodHandleDesc, "linkToVirtual", linkToVirtualIntrinsic);
StaticIntrinsic linkToVirtualMethodBody = (builder, target, arguments) -> {
Reflection reflection = Reflection.get(ctxt);
BasicBlockBuilder fb = builder.getFirstBuilder();
int lastArg = arguments.size() - 1;
Value memberName = arguments.get(lastArg);
Value methodPtr = fb.load(fb.instanceFieldOf(fb.referenceHandle(memberName), reflection.memberNameExactDispatcherField));
StaticMethodType methodType = (StaticMethodType) target.getExecutable().getType();
// cast to the matching static helper method pointer type for this particular shape
Value castMethodPtr = fb.bitCast(methodPtr, methodType.trimLastParameter().getPointer());
throw new BlockEarlyTermination(fb.tailCall(fb.pointerHandle(castMethodPtr), arguments.subList(0, lastArg)));
};
patcher.replaceMethodBody(bootstrapClassContext, methodHandleInt, "linkToVirtual", objArrayToObj, new StaticIntrinsicMethodBodyFactory(linkToVirtualMethodBody), 0);
// VarHandle
LoadedTypeDefinition wmteDef = bootstrapClassContext.findDefinedType("java/lang/invoke/WrongMethodTypeException").load();
ConstructorElement wmteCtor = wmteDef.requireSingleConstructor(ce -> ce.getParameters().isEmpty());
final class VarHandleBodyIntrinsic implements InstanceIntrinsic {
@Override
public Value emitIntrinsic(BasicBlockBuilder builder, Value instance, InstanceMethodElementHandle target, List arguments) {
MethodElement methodElement = target.getExecutable();
MethodDescriptor descriptor = methodElement.getDescriptor();
DefinedTypeDefinition enclosingType = methodElement.getEnclosingType();
if (Reflection.isErased(descriptor)) {
// base method implementation with erased type throws WrongMethodTypeException; overridden in subclasses
Value ex = builder.new_((ClassTypeDescriptor) wmteDef.getDescriptor());
builder.call(builder.constructorOf(ex, wmteCtor), List.of());
throw new BlockEarlyTermination(builder.throw_(ex));
} else {
// not erased; delegate to erased version
ClassContext classContext = target.getExecutable().getEnclosingType().getContext();
MethodDescriptor erased = Reflection.erase(classContext, descriptor);
TypeDescriptor returnTypeDesc = descriptor.getReturnType();
if (Reflection.isErased(returnTypeDesc)) {
// no cast needed
throw new BlockEarlyTermination(builder.tailCall(builder.virtualMethodOf(instance, enclosingType.getDescriptor(), methodElement.getName(), erased), arguments));
} else {
Value result = builder.call(builder.virtualMethodOf(instance, enclosingType.getDescriptor(), methodElement.getName(), erased), arguments);
throw new BlockEarlyTermination(builder.return_(builder.checkcast(result, returnTypeDesc)));
}
}
}
}
InstanceIntrinsicMethodBodyFactory varHandleBodyFactory = new InstanceIntrinsicMethodBodyFactory(new VarHandleBodyIntrinsic());
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "get", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "set", objArrayToVoid, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getVolatile", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "setVolatile", objArrayToVoid, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAcquire", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "setRelease", objArrayToVoid, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getOpaque", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "setOpaque", objArrayToVoid, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "compareAndSet", objArrayToBool, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "compareAndExchange", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "compareAndExchangeAcquire", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "compareAndExchangeRelease", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "weakCompareAndSetPlain", objArrayToBool, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "weakCompareAndSet", objArrayToBool, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "weakCompareAndSetAcquire", objArrayToBool, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "weakCompareAndSetRelease", objArrayToBool, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndSet", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndSetAcquire", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndSetRelease", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndAdd", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndAddAcquire", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndAddRelease", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseOr", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseOrRelease", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseOrAcquire", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseAnd", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseAndRelease", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseAndAcquire", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseXor", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseXorRelease", objArrayToObj, varHandleBodyFactory, 0);
patcher.replaceMethodBody(bootstrapClassContext, varHandleInt, "getAndBitwiseXorAcquire", objArrayToObj, varHandleBodyFactory, 0);
}
/**
* A convenience class that allows a method body to be expressed using the intrinsic API.
*/
static final class StaticIntrinsicMethodBodyFactory implements MethodBodyFactory {
private final StaticIntrinsic methodBodyIntrinsic;
StaticIntrinsicMethodBodyFactory(StaticIntrinsic methodBodyIntrinsic) {
this.methodBodyIntrinsic = methodBodyIntrinsic;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public MethodBody createMethodBody(int index, ExecutableElement element) {
// hack the method to be hidden
((BasicElement)element).setModifierFlags(ClassFile.I_ACC_HIDDEN);
// assume that the descriptor has *changed*
InvokableType type = element.getType();
DefinedTypeDefinition enclosingType = element.getEnclosingType();
ClassContext classContext = enclosingType.getContext();
BasicBlockBuilder bbb = classContext.newBasicBlockBuilder(element);
List paramValues = new ArrayList<>(type.getParameterCount());
int cnt = type.getParameterCount();
for (int i = 0; i < cnt; i ++) {
paramValues.add(bbb.parameter(type.getParameterType(i), "p", i));
}
bbb.startMethod(paramValues);
// build the entry block
BlockLabel entryLabel = new BlockLabel();
bbb.begin(entryLabel);
// expand the "intrinsic"
try {
Value retVal = methodBodyIntrinsic.emitIntrinsic(bbb, (StaticMethodElementHandle) bbb.staticMethod((MethodElement) element), (List) (List) paramValues);
if (retVal == null) {
throw new IllegalStateException("Failed to emit method body");
}
if (type.getReturnType() instanceof VoidType) {
bbb.return_();
} else {
bbb.return_(retVal);
}
} catch (BlockEarlyTermination ignored) {}
bbb.finish();
BasicBlock entryBlock = BlockLabel.getTargetOf(entryLabel);
Schedule schedule = Schedule.forMethod(entryBlock);
return MethodBody.of(entryBlock, schedule, null, paramValues);
}
}
/**
* A convenience class that allows a method body to be expressed using the intrinsic API.
*/
static final class InstanceIntrinsicMethodBodyFactory implements MethodBodyFactory {
private final InstanceIntrinsic methodBodyIntrinsic;
InstanceIntrinsicMethodBodyFactory(InstanceIntrinsic methodBodyIntrinsic) {
this.methodBodyIntrinsic = methodBodyIntrinsic;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public MethodBody createMethodBody(int index, ExecutableElement element) {
// hack the method to be hidden
((BasicElement)element).setModifierFlags(ClassFile.I_ACC_HIDDEN);
// assume that the descriptor has *changed*
InvokableType type = element.getType();
DefinedTypeDefinition enclosingType = element.getEnclosingType();
ClassContext classContext = enclosingType.getContext();
BasicBlockBuilder bbb = classContext.newBasicBlockBuilder(element);
ParameterValue this_ = bbb.parameter(element.getEnclosingType().load().getObjectType().getReference(), "this", 0);
List paramValues = new ArrayList<>(type.getParameterCount());
int cnt = type.getParameterCount();
for (int i = 0; i < cnt; i ++) {
paramValues.add(bbb.parameter(type.getParameterType(i), "p", i));
}
bbb.startMethod(paramValues);
// build the entry block
BlockLabel entryLabel = new BlockLabel();
bbb.begin(entryLabel);
// expand the "intrinsic"
try {
Value retVal = methodBodyIntrinsic.emitIntrinsic(bbb, this_, (InstanceMethodElementHandle) bbb.exactMethodOf(this_, (MethodElement) element), (List) (List) paramValues);
if (retVal == null) {
throw new IllegalStateException("Failed to emit method body");
}
if (type.getReturnType() instanceof VoidType) {
bbb.return_();
} else {
bbb.return_(retVal);
}
} catch (BlockEarlyTermination ignored) {}
bbb.finish();
BasicBlock entryBlock = BlockLabel.getTargetOf(entryLabel);
Schedule schedule = Schedule.forMethod(entryBlock);
return MethodBody.of(entryBlock, schedule, this_, paramValues);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy