8341548: More concise use of classfile API

Reviewed-by: liach
This commit is contained in:
Shaojin Wen 2024-10-08 20:35:14 +00:00
parent 7312eea382
commit 62acc9c174
5 changed files with 323 additions and 342 deletions

View File

@ -394,10 +394,9 @@ import sun.invoke.util.Wrapper;
.invokespecial(CD_Object, INIT_NAME, MTD_void); .invokespecial(CD_Object, INIT_NAME, MTD_void);
int parameterCount = factoryType.parameterCount(); int parameterCount = factoryType.parameterCount();
for (int i = 0; i < parameterCount; i++) { for (int i = 0; i < parameterCount; i++) {
cob.aload(0); cob.aload(0)
Class<?> argType = factoryType.parameterType(i); .loadLocal(TypeKind.from(factoryType.parameterType(i)), cob.parameterSlot(i))
cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i)); .putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
cob.putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
} }
cob.return_(); cob.return_();
} }

View File

@ -891,10 +891,9 @@ class InvokerBytecodeGenerator {
emitStaticInvoke(cob, invokeBasicName); emitStaticInvoke(cob, invokeBasicName);
// goto L_done // goto L_done
cob.goto_w(L_done); cob.goto_w(L_done)
// L_fallback:
// L_fallback: .labelBinding(L_fallback);
cob.labelBinding(L_fallback);
// invoke selectAlternativeName.arguments[2] // invoke selectAlternativeName.arguments[2]
System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length); System.arraycopy(preForkClasses, 0, localClasses, 0, preForkClasses.length);
@ -945,26 +944,23 @@ class InvokerBytecodeGenerator {
.dropParameterTypes(0,1) .dropParameterTypes(0,1)
.changeReturnType(returnType); .changeReturnType(returnType);
cob.exceptionCatch(L_startBlock, L_endBlock, L_handler, CD_Throwable); cob.exceptionCatch(L_startBlock, L_endBlock, L_handler, CD_Throwable)
// Normal case
// Normal case .labelBinding(L_startBlock);
cob.labelBinding(L_startBlock);
// load target // load target
emitPushArgument(cob, invoker, 0); emitPushArgument(cob, invoker, 0);
emitPushArguments(cob, args, 1); // skip 1st argument: method handle emitPushArguments(cob, args, 1); // skip 1st argument: method handle
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType())); cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType()))
cob.labelBinding(L_endBlock); .labelBinding(L_endBlock)
cob.goto_w(L_done); .goto_w(L_done)
// Exceptional case
// Exceptional case .labelBinding(L_handler)
cob.labelBinding(L_handler); // Check exception's type
.dup();
// Check exception's type
cob.dup();
// load exception class // load exception class
emitPushArgument(cob, invoker, 1); emitPushArgument(cob, invoker, 1);
cob.swap(); cob.swap()
cob.invokevirtual(CD_Class, "isInstance", MTD_boolean_Object); .invokevirtual(CD_Class, "isInstance", MTD_boolean_Object);
Label L_rethrow = cob.newLabel(); Label L_rethrow = cob.newLabel();
cob.ifeq(L_rethrow); cob.ifeq(L_rethrow);
@ -974,13 +970,11 @@ class InvokerBytecodeGenerator {
cob.swap(); cob.swap();
emitPushArguments(cob, args, 1); // skip 1st argument: method handle emitPushArguments(cob, args, 1); // skip 1st argument: method handle
MethodType catcherType = type.insertParameterTypes(0, Throwable.class); MethodType catcherType = type.insertParameterTypes(0, Throwable.class);
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(catcherType.basicType())); cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(catcherType.basicType()))
cob.goto_w(L_done); .goto_w(L_done)
.labelBinding(L_rethrow)
cob.labelBinding(L_rethrow); .athrow()
cob.athrow(); .labelBinding(L_done);
cob.labelBinding(L_done);
return result; return result;
} }
@ -1075,8 +1069,8 @@ class InvokerBytecodeGenerator {
cob.labelBinding(lFrom); cob.labelBinding(lFrom);
emitPushArgument(cob, invoker, 0); // load target emitPushArgument(cob, invoker, 0); // load target
emitPushArguments(cob, args, 1); // load args (skip 0: method handle) emitPushArguments(cob, args, 1); // load args (skip 0: method handle)
cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType())); cob.invokevirtual(CD_MethodHandle, "invokeBasic", methodDesc(type.basicType()))
cob.labelBinding(lTo); .labelBinding(lTo);
// FINALLY_NORMAL: // FINALLY_NORMAL:
int index = extendLocalsMap(new Class<?>[]{ returnType }); int index = extendLocalsMap(new Class<?>[]{ returnType });
@ -1084,17 +1078,16 @@ class InvokerBytecodeGenerator {
emitStoreInsn(cob, basicReturnType.basicTypeKind(), index); emitStoreInsn(cob, basicReturnType.basicTypeKind(), index);
} }
emitPushArgument(cob, invoker, 1); // load cleanup emitPushArgument(cob, invoker, 1); // load cleanup
cob.loadConstant(null); cob.aconst_null();
if (isNonVoid) { if (isNonVoid) {
emitLoadInsn(cob, basicReturnType.basicTypeKind(), index); emitLoadInsn(cob, basicReturnType.basicTypeKind(), index);
} }
emitPushArguments(cob, args, 1); // load args (skip 0: method handle) emitPushArguments(cob, args, 1); // load args (skip 0: method handle)
cob.invokevirtual(CD_MethodHandle, "invokeBasic", cleanupDesc); cob.invokevirtual(CD_MethodHandle, "invokeBasic", cleanupDesc)
cob.goto_w(lDone); .goto_w(lDone)
// CATCH:
// CATCH: .labelBinding(lCatch)
cob.labelBinding(lCatch); .dup();
cob.dup();
// FINALLY_EXCEPTIONAL: // FINALLY_EXCEPTIONAL:
emitPushArgument(cob, invoker, 1); // load cleanup emitPushArgument(cob, invoker, 1); // load cleanup
@ -1107,10 +1100,9 @@ class InvokerBytecodeGenerator {
if (isNonVoid) { if (isNonVoid) {
emitPopInsn(cob, basicReturnType); emitPopInsn(cob, basicReturnType);
} }
cob.athrow(); cob.athrow()
// DONE:
// DONE: .labelBinding(lDone);
cob.labelBinding(lDone);
return result; return result;
} }
@ -1147,26 +1139,24 @@ class InvokerBytecodeGenerator {
} }
emitPushArgument(cob, invoker, 0); // push switch input emitPushArgument(cob, invoker, 0); // push switch input
cob.tableswitch(0, numCases - 1, defaultLabel, cases); cob.tableswitch(0, numCases - 1, defaultLabel, cases)
.labelBinding(defaultLabel);
cob.labelBinding(defaultLabel);
emitPushArgument(cob, invoker, 1); // push default handle emitPushArgument(cob, invoker, 1); // push default handle
emitPushArguments(cob, args, 1); // again, skip collector emitPushArguments(cob, args, 1); // again, skip collector
cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor); cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor)
cob.goto_(endLabel); .goto_(endLabel);
for (int i = 0; i < numCases; i++) { for (int i = 0; i < numCases; i++) {
cob.labelBinding(cases.get(i).target()); cob.labelBinding(cases.get(i).target());
// Load the particular case: // Load the particular case:
emitLoadInsn(cob, TypeKind.REFERENCE, casesLocal); emitLoadInsn(cob, TypeKind.REFERENCE, casesLocal);
cob.loadConstant(i); cob.loadConstant(i)
cob.aaload(); .aaload();
// invoke it: // invoke it:
emitPushArguments(cob, args, 1); // again, skip collector emitPushArguments(cob, args, 1); // again, skip collector
cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor); cob.invokevirtual(CD_MethodHandle, "invokeBasic", caseDescriptor)
.goto_(endLabel);
cob.goto_(endLabel);
} }
cob.labelBinding(endLabel); cob.labelBinding(endLabel);
@ -1335,16 +1325,14 @@ class InvokerBytecodeGenerator {
// invoke fini // invoke fini
emitLoopHandleInvoke(cob, invoker, finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex, emitLoopHandleInvoke(cob, invoker, finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex,
firstLoopStateIndex); firstLoopStateIndex);
cob.goto_w(lDone); cob.goto_w(lDone)
// this is the beginning of the next loop clause
// this is the beginning of the next loop clause .labelBinding(lNext);
cob.labelBinding(lNext);
} }
cob.goto_w(lLoop); cob.goto_w(lLoop)
// DONE:
// DONE: .labelBinding(lDone);
cob.labelBinding(lDone);
return result; return result;
} }
@ -1370,8 +1358,8 @@ class InvokerBytecodeGenerator {
int firstLoopStateSlot) { int firstLoopStateSlot) {
// load handle for clause // load handle for clause
emitPushClauseArray(cob, clauseDataSlot, handles); emitPushClauseArray(cob, clauseDataSlot, handles);
cob.loadConstant(clause); cob.loadConstant(clause)
cob.aaload(); .aaload();
// load loop state (preceding the other arguments) // load loop state (preceding the other arguments)
if (pushLocalState) { if (pushLocalState) {
for (int s = 0; s < loopLocalStateTypes.length; ++s) { for (int s = 0; s < loopLocalStateTypes.length; ++s) {
@ -1385,8 +1373,8 @@ class InvokerBytecodeGenerator {
private void emitPushClauseArray(CodeBuilder cob, int clauseDataSlot, int which) { private void emitPushClauseArray(CodeBuilder cob, int clauseDataSlot, int which) {
emitLoadInsn(cob, TypeKind.REFERENCE, clauseDataSlot); emitLoadInsn(cob, TypeKind.REFERENCE, clauseDataSlot);
cob.loadConstant(which - 1); cob.loadConstant(which - 1)
cob.aaload(); .aaload();
} }
private void emitZero(CodeBuilder cob, BasicType type) { private void emitZero(CodeBuilder cob, BasicType type) {
@ -1519,14 +1507,14 @@ class InvokerBytecodeGenerator {
@Override @Override
public void accept(CodeBuilder cob) { public void accept(CodeBuilder cob) {
// create parameter array // create parameter array
cob.loadConstant(invokerType.parameterCount()); cob.loadConstant(invokerType.parameterCount())
cob.anewarray(CD_Object); .anewarray(CD_Object);
// fill parameter array // fill parameter array
for (int i = 0; i < invokerType.parameterCount(); i++) { for (int i = 0; i < invokerType.parameterCount(); i++) {
Class<?> ptype = invokerType.parameterType(i); Class<?> ptype = invokerType.parameterType(i);
cob.dup(); cob.dup()
cob.loadConstant(i); .loadConstant(i);
emitLoadInsn(cob, basicType(ptype).basicTypeKind(), i); emitLoadInsn(cob, basicType(ptype).basicTypeKind(), i);
// box if primitive type // box if primitive type
if (ptype.isPrimitive()) { if (ptype.isPrimitive()) {
@ -1535,10 +1523,10 @@ class InvokerBytecodeGenerator {
cob.aastore(); cob.aastore();
} }
// invoke // invoke
cob.aload(0); cob.aload(0)
cob.getfield(CD_MethodHandle, "form", CD_LambdaForm); .getfield(CD_MethodHandle, "form", CD_LambdaForm)
cob.swap(); // swap form and array; avoid local variable .swap() // swap form and array; avoid local variable
cob.invokevirtual(CD_LambdaForm, "interpretWithArguments", MethodTypeDescImpl.ofValidated(CD_Object, CD_Object_array)); .invokevirtual(CD_LambdaForm, "interpretWithArguments", MethodTypeDescImpl.ofValidated(CD_Object, CD_Object_array));
// maybe unbox // maybe unbox
Class<?> rtype = invokerType.returnType(); Class<?> rtype = invokerType.returnType();
@ -1592,9 +1580,9 @@ class InvokerBytecodeGenerator {
// Load arguments from array // Load arguments from array
for (int i = 0; i < dstType.parameterCount(); i++) { for (int i = 0; i < dstType.parameterCount(); i++) {
cob.aload(1); cob.aload(1)
cob.loadConstant(i); .loadConstant(i)
cob.aaload(); .aaload();
// Maybe unbox // Maybe unbox
Class<?> dptype = dstType.parameterType(i); Class<?> dptype = dstType.parameterType(i);
@ -1645,9 +1633,9 @@ class InvokerBytecodeGenerator {
clb.withMethodBody("dummy", MTD_void, ACC_STATIC, new Consumer<>() { clb.withMethodBody("dummy", MTD_void, ACC_STATIC, new Consumer<>() {
@Override @Override
public void accept(CodeBuilder cob) { public void accept(CodeBuilder cob) {
cob.ldc(os.toString()); cob.ldc(os.toString())
cob.pop(); .pop()
cob.return_(); .return_();
} }
}); });
} }

View File

@ -373,46 +373,43 @@ public class MethodHandleProxies {
String methodName, List<MethodInfo> methods) { String methodName, List<MethodInfo> methods) {
return ClassFile.of(ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(loader))) return ClassFile.of(ClassHierarchyResolverOption.of(ClassHierarchyResolver.ofClassLoading(loader)))
.build(proxyDesc, clb -> { .build(proxyDesc, clb -> {
clb.withSuperclass(CD_Object); clb.withSuperclass(CD_Object)
clb.withFlags(ACC_FINAL | ACC_SYNTHETIC); .withFlags(ACC_FINAL | ACC_SYNTHETIC)
clb.withInterfaceSymbols(ifaceDesc); .withInterfaceSymbols(ifaceDesc)
// static and instance fields
// static and instance fields .withField(TYPE_NAME, CD_Class, ACC_PRIVATE | ACC_STATIC | ACC_FINAL)
clb.withField(TYPE_NAME, CD_Class, ACC_PRIVATE | ACC_STATIC | ACC_FINAL); .withField(TARGET_NAME, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL);
clb.withField(TARGET_NAME, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL);
for (var mi : methods) { for (var mi : methods) {
clb.withField(mi.fieldName, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL); clb.withField(mi.fieldName, CD_MethodHandle, ACC_PRIVATE | ACC_FINAL);
} }
// <clinit> // <clinit>
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> { clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, cob -> {
cob.loadConstant(ifaceDesc); cob.loadConstant(ifaceDesc)
cob.putstatic(proxyDesc, TYPE_NAME, CD_Class); .putstatic(proxyDesc, TYPE_NAME, CD_Class)
cob.return_(); .return_();
}); });
// <init>(Lookup, MethodHandle target, MethodHandle callerBoundTarget) // <init>(Lookup, MethodHandle target, MethodHandle callerBoundTarget)
clb.withMethodBody(INIT_NAME, MTD_void_Lookup_MethodHandle_MethodHandle, 0, cob -> { clb.withMethodBody(INIT_NAME, MTD_void_Lookup_MethodHandle_MethodHandle, 0, cob -> {
cob.aload(0); cob.aload(0)
cob.invokespecial(CD_Object, INIT_NAME, MTD_void); .invokespecial(CD_Object, INIT_NAME, MTD_void)
// call ensureOriginalLookup to verify the given Lookup has access
// call ensureOriginalLookup to verify the given Lookup has access .aload(1)
cob.aload(1); .invokestatic(proxyDesc, ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup)
cob.invokestatic(proxyDesc, "ensureOriginalLookup", MTD_void_Lookup); // this.target = target;
.aload(0)
// this.target = target; .aload(2)
cob.aload(0); .putfield(proxyDesc, TARGET_NAME, CD_MethodHandle);
cob.aload(2);
cob.putfield(proxyDesc, TARGET_NAME, CD_MethodHandle);
// method handles adjusted to the method type of each method // method handles adjusted to the method type of each method
for (var mi : methods) { for (var mi : methods) {
// this.m<i> = callerBoundTarget.asType(xxType); // this.m<i> = callerBoundTarget.asType(xxType);
cob.aload(0); cob.aload(0)
cob.aload(3); .aload(3)
cob.loadConstant(mi.desc); .loadConstant(mi.desc)
cob.invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType); .invokevirtual(CD_MethodHandle, "asType", MTD_MethodHandle_MethodType)
cob.putfield(proxyDesc, mi.fieldName, CD_MethodHandle); .putfield(proxyDesc, mi.fieldName, CD_MethodHandle);
} }
// complete // complete
@ -425,26 +422,26 @@ public class MethodHandleProxies {
clb.withMethodBody(ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup, ACC_PRIVATE | ACC_STATIC, cob -> { clb.withMethodBody(ENSURE_ORIGINAL_LOOKUP, MTD_void_Lookup, ACC_PRIVATE | ACC_STATIC, cob -> {
var failLabel = cob.newLabel(); var failLabel = cob.newLabel();
// check lookupClass // check lookupClass
cob.aload(0); cob.aload(0)
cob.invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class); .invokevirtual(CD_MethodHandles_Lookup, "lookupClass", MTD_Class)
cob.loadConstant(proxyDesc); .loadConstant(proxyDesc)
cob.if_acmpne(failLabel); .if_acmpne(failLabel)
// check original access // check original access
cob.aload(0); .aload(0)
cob.invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int); .invokevirtual(CD_MethodHandles_Lookup, "lookupModes", MTD_int)
cob.loadConstant(Lookup.ORIGINAL); .loadConstant(Lookup.ORIGINAL)
cob.iand(); .iand()
cob.ifeq(failLabel); .ifeq(failLabel)
// success // success
cob.return_(); .return_()
// throw exception // throw exception
cob.labelBinding(failLabel); .labelBinding(failLabel)
cob.new_(CD_IllegalAccessException); .new_(CD_IllegalAccessException)
cob.dup(); .dup()
cob.aload(0); // lookup .aload(0) // lookup
cob.invokevirtual(CD_Object, "toString", MTD_String); .invokevirtual(CD_Object, "toString", MTD_String)
cob.invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String); .invokespecial(CD_IllegalAccessException, INIT_NAME, MTD_void_String)
cob.athrow(); .athrow();
}); });
// implementation methods // implementation methods
@ -453,14 +450,14 @@ public class MethodHandleProxies {
clb.withMethodBody(methodName, mi.desc, ACC_PUBLIC, cob -> cob clb.withMethodBody(methodName, mi.desc, ACC_PUBLIC, cob -> cob
.trying(bcb -> { .trying(bcb -> {
// return this.handleField.invokeExact(arguments...); // return this.handleField.invokeExact(arguments...);
bcb.aload(0); bcb.aload(0)
bcb.getfield(proxyDesc, mi.fieldName, CD_MethodHandle); .getfield(proxyDesc, mi.fieldName, CD_MethodHandle);
for (int j = 0; j < mi.desc.parameterCount(); j++) { for (int j = 0; j < mi.desc.parameterCount(); j++) {
bcb.loadLocal(TypeKind.from(mi.desc.parameterType(j)), bcb.loadLocal(TypeKind.from(mi.desc.parameterType(j)),
bcb.parameterSlot(j)); bcb.parameterSlot(j));
} }
bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc); bcb.invokevirtual(CD_MethodHandle, "invokeExact", mi.desc)
bcb.return_(TypeKind.from(mi.desc.returnType())); .return_(TypeKind.from(mi.desc.returnType()));
}, ctb -> ctb }, ctb -> ctb
// catch (Error | RuntimeException | Declared ex) { throw ex; } // catch (Error | RuntimeException | Declared ex) { throw ex; }
.catchingMulti(mi.thrown, CodeBuilder::athrow) .catchingMulti(mi.thrown, CodeBuilder::athrow)

View File

@ -29,7 +29,6 @@ import java.lang.Enum.EnumDesc;
import java.lang.classfile.CodeBuilder; import java.lang.classfile.CodeBuilder;
import java.lang.constant.ClassDesc; import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDesc; import java.lang.constant.ConstantDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc; import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.CallSite; import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite; import java.lang.invoke.ConstantCallSite;
@ -55,6 +54,7 @@ import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.misc.PreviewFeatures; import jdk.internal.misc.PreviewFeatures;
import jdk.internal.vm.annotation.Stable; import jdk.internal.vm.annotation.Stable;
import static java.lang.constant.ConstantDescs.*;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
import java.util.Arrays; import java.util.Arrays;
@ -86,15 +86,15 @@ public class SwitchBootstraps {
private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;"); private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;");
private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR = private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR =
MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, ConstantDescs.CD_int, ConstantDescs.CD_int); MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_int);
private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(CD_int,
ConstantDescs.CD_Object, CD_Object,
ConstantDescs.CD_int); CD_int);
private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(CD_int,
ConstantDescs.CD_Object, CD_Object,
ConstantDescs.CD_int, CD_int,
CD_BiPredicate, CD_BiPredicate,
ConstantDescs.CD_List); CD_List);
private static final MethodType MT_TYPE_SWITCH_EXTRA = MethodType.methodType(int.class, private static final MethodType MT_TYPE_SWITCH_EXTRA = MethodType.methodType(int.class,
Object.class, Object.class,
int.class, int.class,
@ -484,19 +484,19 @@ public class SwitchBootstraps {
return cb -> { return cb -> {
// Objects.checkIndex(RESTART_IDX, labelConstants + 1) // Objects.checkIndex(RESTART_IDX, labelConstants + 1)
cb.iload(RESTART_IDX); cb.iload(RESTART_IDX)
cb.loadConstant(labelConstants.length + 1); .loadConstant(labelConstants.length + 1)
cb.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR); .invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR)
cb.pop(); .pop()
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ);
Label nonNullLabel = cb.newLabel(); Label nonNullLabel = cb.newLabel();
cb.ifnonnull(nonNullLabel); cb.ifnonnull(nonNullLabel)
cb.iconst_m1(); .iconst_m1()
cb.ireturn(); .ireturn()
cb.labelBinding(nonNullLabel); .labelBinding(nonNullLabel);
if (labelConstants.length == 0) { if (labelConstants.length == 0) {
cb.loadConstant(0) cb.loadConstant(0)
.ireturn(); .ireturn();
return; return;
} }
cb.iload(RESTART_IDX); cb.iload(RESTART_IDX);
@ -535,132 +535,132 @@ public class SwitchBootstraps {
if (!selectorType.isPrimitive() && !Wrapper.isWrapperNumericOrBooleanType(selectorType)) { if (!selectorType.isPrimitive() && !Wrapper.isWrapperNumericOrBooleanType(selectorType)) {
// Object o = ... // Object o = ...
// o instanceof Wrapped(float) // o instanceof Wrapped(float)
cb.aload(SELECTOR_OBJ); cb.aload(SELECTOR_OBJ)
cb.instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor()); .instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor())
cb.ifeq(next); .ifeq(next);
} else if (!unconditionalExactnessCheck(Wrapper.asPrimitiveType(selectorType), classLabel)) { } else if (!unconditionalExactnessCheck(Wrapper.asPrimitiveType(selectorType), classLabel)) {
// Integer i = ... or int i = ... // Integer i = ... or int i = ...
// o instanceof float // o instanceof float
Label notNumber = cb.newLabel(); Label notNumber = cb.newLabel();
cb.aload(SELECTOR_OBJ); cb.aload(SELECTOR_OBJ)
cb.instanceOf(ConstantDescs.CD_Number); .instanceOf(CD_Number);
if (selectorType == long.class || selectorType == float.class || selectorType == double.class || if (selectorType == long.class || selectorType == float.class || selectorType == double.class ||
selectorType == Long.class || selectorType == Float.class || selectorType == Double.class) { selectorType == Long.class || selectorType == Float.class || selectorType == Double.class) {
cb.ifeq(next); cb.ifeq(next);
} else { } else {
cb.ifeq(notNumber); cb.ifeq(notNumber);
} }
cb.aload(SELECTOR_OBJ); cb.aload(SELECTOR_OBJ)
cb.checkcast(ConstantDescs.CD_Number); .checkcast(CD_Number);
if (selectorType == long.class || selectorType == Long.class) { if (selectorType == long.class || selectorType == Long.class) {
cb.invokevirtual(ConstantDescs.CD_Number, cb.invokevirtual(CD_Number,
"longValue", "longValue",
MethodTypeDesc.of(ConstantDescs.CD_long)); MethodTypeDesc.of(CD_long));
} else if (selectorType == float.class || selectorType == Float.class) { } else if (selectorType == float.class || selectorType == Float.class) {
cb.invokevirtual(ConstantDescs.CD_Number, cb.invokevirtual(CD_Number,
"floatValue", "floatValue",
MethodTypeDesc.of(ConstantDescs.CD_float)); MethodTypeDesc.of(CD_float));
} else if (selectorType == double.class || selectorType == Double.class) { } else if (selectorType == double.class || selectorType == Double.class) {
cb.invokevirtual(ConstantDescs.CD_Number, cb.invokevirtual(CD_Number,
"doubleValue", "doubleValue",
MethodTypeDesc.of(ConstantDescs.CD_double)); MethodTypeDesc.of(CD_double));
} else { } else {
Label compare = cb.newLabel(); Label compare = cb.newLabel();
cb.invokevirtual(ConstantDescs.CD_Number, cb.invokevirtual(CD_Number,
"intValue", "intValue",
MethodTypeDesc.of(ConstantDescs.CD_int)); MethodTypeDesc.of(CD_int))
cb.goto_(compare); .goto_(compare)
cb.labelBinding(notNumber); .labelBinding(notNumber)
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.instanceOf(ConstantDescs.CD_Character); .instanceOf(CD_Character)
cb.ifeq(next); .ifeq(next)
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.checkcast(ConstantDescs.CD_Character); .checkcast(CD_Character)
cb.invokevirtual(ConstantDescs.CD_Character, .invokevirtual(CD_Character,
"charValue", "charValue",
MethodTypeDesc.of(ConstantDescs.CD_char)); MethodTypeDesc.of(CD_char))
cb.labelBinding(compare); .labelBinding(compare);
} }
TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel); TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel);
String methodName = TypePairs.typePairToName.get(typePair); String methodName = TypePairs.typePairToName.get(typePair);
cb.invokestatic(referenceClassDesc(ExactConversionsSupport.class), cb.invokestatic(referenceClassDesc(ExactConversionsSupport.class),
methodName, methodName,
MethodTypeDesc.of(ConstantDescs.CD_boolean, classDesc(typePair.from))); MethodTypeDesc.of(CD_boolean, classDesc(typePair.from)))
cb.ifeq(next); .ifeq(next);
} }
} else { } else {
Optional<ClassDesc> classLabelConstableOpt = classLabel.describeConstable(); Optional<ClassDesc> classLabelConstableOpt = classLabel.describeConstable();
if (classLabelConstableOpt.isPresent()) { if (classLabelConstableOpt.isPresent()) {
cb.aload(SELECTOR_OBJ); cb.aload(SELECTOR_OBJ)
cb.instanceOf(classLabelConstableOpt.orElseThrow()); .instanceOf(classLabelConstableOpt.orElseThrow())
cb.ifeq(next); .ifeq(next);
} else { } else {
cb.aload(EXTRA_CLASS_LABELS); cb.aload(EXTRA_CLASS_LABELS)
cb.loadConstant(extraClassLabels.size()); .loadConstant(extraClassLabels.size())
cb.invokeinterface(ConstantDescs.CD_List, .invokeinterface(CD_List,
"get", "get",
MethodTypeDesc.of(ConstantDescs.CD_Object, MethodTypeDesc.of(CD_Object,
ConstantDescs.CD_int)); CD_int))
cb.checkcast(ConstantDescs.CD_Class); .checkcast(CD_Class)
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.invokevirtual(ConstantDescs.CD_Class, .invokevirtual(CD_Class,
"isInstance", "isInstance",
MethodTypeDesc.of(ConstantDescs.CD_boolean, MethodTypeDesc.of(CD_boolean,
ConstantDescs.CD_Object)); CD_Object))
cb.ifeq(next); .ifeq(next);
extraClassLabels.add(classLabel); extraClassLabels.add(classLabel);
} }
} }
} else if (caseLabel instanceof EnumDesc<?> enumLabel) { } else if (caseLabel instanceof EnumDesc<?> enumLabel) {
int enumIdx = enumDescs.size(); int enumIdx = enumDescs.size();
enumDescs.add(enumLabel); enumDescs.add(enumLabel);
cb.aload(ENUM_CACHE); cb.aload(ENUM_CACHE)
cb.loadConstant(enumIdx); .loadConstant(enumIdx)
cb.invokestatic(ConstantDescs.CD_Integer, .invokestatic(CD_Integer,
"valueOf", "valueOf",
MethodTypeDesc.of(ConstantDescs.CD_Integer, MethodTypeDesc.of(CD_Integer,
ConstantDescs.CD_int)); CD_int))
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.invokeinterface(CD_BiPredicate, .invokeinterface(CD_BiPredicate,
"test", "test",
MethodTypeDesc.of(ConstantDescs.CD_boolean, MethodTypeDesc.of(CD_boolean,
ConstantDescs.CD_Object, CD_Object,
ConstantDescs.CD_Object)); CD_Object))
cb.ifeq(next); .ifeq(next);
} else if (caseLabel instanceof String stringLabel) { } else if (caseLabel instanceof String stringLabel) {
cb.ldc(stringLabel); cb.ldc(stringLabel)
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.invokevirtual(ConstantDescs.CD_Object, .invokevirtual(CD_Object,
"equals", "equals",
MethodTypeDesc.of(ConstantDescs.CD_boolean, MethodTypeDesc.of(CD_boolean,
ConstantDescs.CD_Object)); CD_Object))
cb.ifeq(next); .ifeq(next);
} else if (caseLabel instanceof Integer integerLabel) { } else if (caseLabel instanceof Integer integerLabel) {
Label compare = cb.newLabel(); Label compare = cb.newLabel();
Label notNumber = cb.newLabel(); Label notNumber = cb.newLabel();
cb.aload(SELECTOR_OBJ); cb.aload(SELECTOR_OBJ)
cb.instanceOf(ConstantDescs.CD_Number); .instanceOf(CD_Number)
cb.ifeq(notNumber); .ifeq(notNumber)
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.checkcast(ConstantDescs.CD_Number); .checkcast(CD_Number)
cb.invokevirtual(ConstantDescs.CD_Number, .invokevirtual(CD_Number,
"intValue", "intValue",
MethodTypeDesc.of(ConstantDescs.CD_int)); MethodTypeDesc.of(CD_int))
cb.goto_(compare); .goto_(compare)
cb.labelBinding(notNumber); .labelBinding(notNumber)
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.instanceOf(ConstantDescs.CD_Character); .instanceOf(CD_Character)
cb.ifeq(next); .ifeq(next)
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.checkcast(ConstantDescs.CD_Character); .checkcast(CD_Character)
cb.invokevirtual(ConstantDescs.CD_Character, .invokevirtual(CD_Character,
"charValue", "charValue",
MethodTypeDesc.of(ConstantDescs.CD_char)); MethodTypeDesc.of(CD_char))
cb.labelBinding(compare); .labelBinding(compare)
cb.loadConstant(integerLabel); .loadConstant(integerLabel)
cb.if_icmpne(next); .if_icmpne(next);
} else if ((caseLabel instanceof Long || } else if ((caseLabel instanceof Long ||
caseLabel instanceof Float || caseLabel instanceof Float ||
caseLabel instanceof Double || caseLabel instanceof Double ||
@ -674,23 +674,23 @@ public class SwitchBootstraps {
cb.invokestatic(caseLabelWrapper.wrapperClassDescriptor(), cb.invokestatic(caseLabelWrapper.wrapperClassDescriptor(),
"valueOf", "valueOf",
MethodTypeDesc.of(caseLabelWrapper.wrapperClassDescriptor(), MethodTypeDesc.of(caseLabelWrapper.wrapperClassDescriptor(),
caseLabelWrapper.basicClassDescriptor())); caseLabelWrapper.basicClassDescriptor()))
cb.aload(SELECTOR_OBJ); .aload(SELECTOR_OBJ)
cb.invokevirtual(ConstantDescs.CD_Object, .invokevirtual(CD_Object,
"equals", "equals",
MethodTypeDesc.of(ConstantDescs.CD_boolean, MethodTypeDesc.of(CD_boolean,
ConstantDescs.CD_Object)); CD_Object))
cb.ifeq(next); .ifeq(next);
} else { } else {
throw new InternalError("Unsupported label type: " + throw new InternalError("Unsupported label type: " +
caseLabel.getClass()); caseLabel.getClass());
} }
cb.loadConstant(idx); cb.loadConstant(idx)
cb.ireturn(); .ireturn();
} }
cb.labelBinding(dflt); cb.labelBinding(dflt)
cb.loadConstant(labelConstants.length); .loadConstant(labelConstants.length)
cb.ireturn(); .ireturn();
}; };
} }

View File

@ -193,11 +193,10 @@ public class BindingSpecializer {
CallingSequence callingSequence, ABIDescriptor abi) { CallingSequence callingSequence, ABIDescriptor abi) {
String className = callingSequence.forDowncall() ? CLASS_NAME_DOWNCALL : CLASS_NAME_UPCALL; String className = callingSequence.forDowncall() ? CLASS_NAME_DOWNCALL : CLASS_NAME_UPCALL;
byte[] bytes = ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> { byte[] bytes = ClassFile.of().build(ClassDesc.ofInternalName(className), clb -> {
clb.withFlags(ACC_PUBLIC + ACC_FINAL + ACC_SUPER); clb.withFlags(ACC_PUBLIC + ACC_FINAL + ACC_SUPER)
clb.withSuperclass(CD_Object); .withSuperclass(CD_Object)
clb.withVersion(CLASSFILE_VERSION, 0); .withVersion(CLASSFILE_VERSION, 0)
.withMethodBody(METHOD_NAME, methodTypeDesc(callerMethodType), ACC_PUBLIC | ACC_STATIC,
clb.withMethodBody(METHOD_NAME, methodTypeDesc(callerMethodType), ACC_PUBLIC | ACC_STATIC,
cb -> new BindingSpecializer(cb, callerMethodType, callingSequence, abi, leafType).specialize()); cb -> new BindingSpecializer(cb, callerMethodType, callingSequence, abi, leafType).specialize());
}); });
@ -275,8 +274,8 @@ public class BindingSpecializer {
if (shouldAcquire(i)) { if (shouldAcquire(i)) {
int scopeLocal = cb.allocateLocal(REFERENCE); int scopeLocal = cb.allocateLocal(REFERENCE);
initialScopeSlots[numScopes++] = scopeLocal; initialScopeSlots[numScopes++] = scopeLocal;
cb.loadConstant(null); cb.aconst_null()
cb.storeLocal(REFERENCE, scopeLocal); // need to initialize all scope locals here in case an exception occurs .astore(scopeLocal); // need to initialize all scope locals here in case an exception occurs
} }
} }
scopeSlots = Arrays.copyOf(initialScopeSlots, numScopes); // fit to size scopeSlots = Arrays.copyOf(initialScopeSlots, numScopes); // fit to size
@ -285,15 +284,15 @@ public class BindingSpecializer {
// create a Binding.Context for this call // create a Binding.Context for this call
if (callingSequence.allocationSize() != 0) { if (callingSequence.allocationSize() != 0) {
cb.loadConstant(callingSequence.allocationSize()); cb.loadConstant(callingSequence.allocationSize())
cb.invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA); .invokestatic(CD_SharedUtils, "newBoundedArena", MTD_NEW_BOUNDED_ARENA);
} else if (callingSequence.forUpcall() && needsSession()) { } else if (callingSequence.forUpcall() && needsSession()) {
cb.invokestatic(CD_SharedUtils, "newEmptyArena", MTD_NEW_EMPTY_ARENA); cb.invokestatic(CD_SharedUtils, "newEmptyArena", MTD_NEW_EMPTY_ARENA);
} else { } else {
cb.getstatic(CD_SharedUtils, "DUMMY_ARENA", CD_Arena); cb.getstatic(CD_SharedUtils, "DUMMY_ARENA", CD_Arena);
} }
contextIdx = cb.allocateLocal(REFERENCE); contextIdx = cb.allocateLocal(REFERENCE);
cb.storeLocal(REFERENCE, contextIdx); cb.astore(contextIdx);
// in case the call needs a return buffer, allocate it here. // in case the call needs a return buffer, allocate it here.
// for upcalls the VM wrapper stub allocates the buffer. // for upcalls the VM wrapper stub allocates the buffer.
@ -301,7 +300,7 @@ public class BindingSpecializer {
emitLoadInternalAllocator(); emitLoadInternalAllocator();
emitAllocateCall(callingSequence.returnBufferSize(), 1); emitAllocateCall(callingSequence.returnBufferSize(), 1);
returnBufferIdx = cb.allocateLocal(REFERENCE); returnBufferIdx = cb.allocateLocal(REFERENCE);
cb.storeLocal(REFERENCE, returnBufferIdx); cb.astore(returnBufferIdx);
} }
Label tryStart = cb.newLabel(); Label tryStart = cb.newLabel();
@ -324,7 +323,7 @@ public class BindingSpecializer {
// for downcalls, recipes have an input value, which we set up here // for downcalls, recipes have an input value, which we set up here
if (callingSequence.needsReturnBuffer() && i == 0) { if (callingSequence.needsReturnBuffer() && i == 0) {
assert returnBufferIdx != -1; assert returnBufferIdx != -1;
cb.loadLocal(REFERENCE, returnBufferIdx); cb.aload(returnBufferIdx);
pushType(MemorySegment.class); pushType(MemorySegment.class);
} else { } else {
emitGetInput(); emitGetInput();
@ -340,7 +339,7 @@ public class BindingSpecializer {
// return buffer ptr is wrapped in a MemorySegment above, but not passed to the leaf handle // return buffer ptr is wrapped in a MemorySegment above, but not passed to the leaf handle
popType(MemorySegment.class); popType(MemorySegment.class);
returnBufferIdx = cb.allocateLocal(REFERENCE); returnBufferIdx = cb.allocateLocal(REFERENCE);
cb.storeLocal(REFERENCE, returnBufferIdx); cb.astore(returnBufferIdx);
} else { } else {
// for upcalls the recipe result is an argument to the leaf handle // for upcalls the recipe result is an argument to the leaf handle
emitSetOutput(typeStack.pop()); emitSetOutput(typeStack.pop());
@ -355,7 +354,7 @@ public class BindingSpecializer {
if (callingSequence.forDowncall()) { if (callingSequence.forDowncall()) {
cb.loadConstant(CLASS_DATA_DESC); cb.loadConstant(CLASS_DATA_DESC);
} else { } else {
cb.loadLocal(REFERENCE, 0); // load target arg cb.aload(0); // load target arg
} }
cb.checkcast(CD_MethodHandle); cb.checkcast(CD_MethodHandle);
// load all the leaf args // load all the leaf args
@ -496,8 +495,8 @@ public class BindingSpecializer {
} }
private void emitAcquireScope() { private void emitAcquireScope() {
cb.checkcast(CD_AbstractMemorySegmentImpl); cb.checkcast(CD_AbstractMemorySegmentImpl)
cb.invokevirtual(CD_AbstractMemorySegmentImpl, "sessionImpl", MTD_SESSION_IMPL); .invokevirtual(CD_AbstractMemorySegmentImpl, "sessionImpl", MTD_SESSION_IMPL);
Label skipAcquire = cb.newLabel(); Label skipAcquire = cb.newLabel();
Label end = cb.newLabel(); Label end = cb.newLabel();
@ -505,23 +504,22 @@ public class BindingSpecializer {
assert curScopeLocalIdx != -1; assert curScopeLocalIdx != -1;
boolean hasOtherScopes = curScopeLocalIdx != 0; boolean hasOtherScopes = curScopeLocalIdx != 0;
for (int i = 0; i < curScopeLocalIdx; i++) { for (int i = 0; i < curScopeLocalIdx; i++) {
cb.dup(); // dup for comparison cb.dup() // dup for comparison
cb.loadLocal(REFERENCE, scopeSlots[i]); .aload(scopeSlots[i])
cb.if_acmpeq(skipAcquire); .if_acmpeq(skipAcquire);
} }
// 1 scope to acquire on the stack // 1 scope to acquire on the stack
cb.dup(); cb.dup();
int nextScopeLocal = scopeSlots[curScopeLocalIdx++]; int nextScopeLocal = scopeSlots[curScopeLocalIdx++];
// call acquire first here. So that if it fails, we don't call release // call acquire first here. So that if it fails, we don't call release
cb.invokevirtual(CD_MemorySessionImpl, "acquire0", MTD_ACQUIRE0); // call acquire on the other cb.invokevirtual(CD_MemorySessionImpl, "acquire0", MTD_ACQUIRE0) // call acquire on the other
cb.storeLocal(REFERENCE, nextScopeLocal); // store off one to release later .astore(nextScopeLocal); // store off one to release later
if (hasOtherScopes) { // avoid ASM generating a bunch of nops for the dead code if (hasOtherScopes) { // avoid ASM generating a bunch of nops for the dead code
cb.goto_(end); cb.goto_(end)
.labelBinding(skipAcquire)
cb.labelBinding(skipAcquire); .pop(); // drop scope
cb.pop(); // drop scope
} }
cb.labelBinding(end); cb.labelBinding(end);
@ -529,10 +527,10 @@ public class BindingSpecializer {
private void emitReleaseScopes() { private void emitReleaseScopes() {
for (int scopeLocal : scopeSlots) { for (int scopeLocal : scopeSlots) {
cb.loadLocal(REFERENCE, scopeLocal); cb.aload(scopeLocal)
cb.ifThen(Opcode.IFNONNULL, ifCb -> { .ifThen(Opcode.IFNONNULL, ifCb -> {
ifCb.loadLocal(REFERENCE, scopeLocal); ifCb.aload(scopeLocal)
ifCb.invokevirtual(CD_MemorySessionImpl, "release0", MTD_RELEASE0); .invokevirtual(CD_MemorySessionImpl, "release0", MTD_RELEASE0);
}); });
} }
} }
@ -551,28 +549,28 @@ public class BindingSpecializer {
private void emitLoadInternalSession() { private void emitLoadInternalSession() {
assert contextIdx != -1; assert contextIdx != -1;
cb.loadLocal(REFERENCE, contextIdx); cb.aload(contextIdx)
cb.checkcast(CD_Arena); .checkcast(CD_Arena)
cb.invokeinterface(CD_Arena, "scope", MTD_SCOPE); .invokeinterface(CD_Arena, "scope", MTD_SCOPE)
cb.checkcast(CD_MemorySessionImpl); .checkcast(CD_MemorySessionImpl);
} }
private void emitLoadInternalAllocator() { private void emitLoadInternalAllocator() {
assert contextIdx != -1; assert contextIdx != -1;
cb.loadLocal(REFERENCE, contextIdx); cb.aload(contextIdx);
} }
private void emitCloseContext() { private void emitCloseContext() {
assert contextIdx != -1; assert contextIdx != -1;
cb.loadLocal(REFERENCE, contextIdx); cb.aload(contextIdx)
cb.checkcast(CD_Arena); .checkcast(CD_Arena)
cb.invokeinterface(CD_Arena, "close", MTD_CLOSE); .invokeinterface(CD_Arena, "close", MTD_CLOSE);
} }
private void emitBoxAddress(BoxAddress boxAddress) { private void emitBoxAddress(BoxAddress boxAddress) {
popType(long.class); popType(long.class);
cb.loadConstant(boxAddress.size()); cb.loadConstant(boxAddress.size())
cb.loadConstant(boxAddress.align()); .loadConstant(boxAddress.align());
if (needsSession()) { if (needsSession()) {
emitLoadInternalSession(); emitLoadInternalSession();
cb.invokestatic(CD_Utils, "longToAddress", MTD_LONG_TO_ADDRESS_SCOPE); cb.invokestatic(CD_Utils, "longToAddress", MTD_LONG_TO_ADDRESS_SCOPE);
@ -585,7 +583,7 @@ public class BindingSpecializer {
private void emitAllocBuffer(Allocate binding) { private void emitAllocBuffer(Allocate binding) {
if (callingSequence.forDowncall()) { if (callingSequence.forDowncall()) {
assert returnAllocatorIdx != -1; assert returnAllocatorIdx != -1;
cb.loadLocal(REFERENCE, returnAllocatorIdx); cb.aload(returnAllocatorIdx);
} else { } else {
emitLoadInternalAllocator(); emitLoadInternalAllocator();
} }
@ -607,8 +605,8 @@ public class BindingSpecializer {
cb.storeLocal(storeTypeKind, valueIdx); cb.storeLocal(storeTypeKind, valueIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType);
cb.loadConstant(offset); cb.loadConstant(offset)
cb.loadLocal(storeTypeKind, valueIdx); .loadLocal(storeTypeKind, valueIdx);
MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)); MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType));
cb.invokeinterface(CD_MemorySegment, "set", descriptor); cb.invokeinterface(CD_MemorySegment, "set", descriptor);
} else { } else {
@ -619,9 +617,9 @@ public class BindingSpecializer {
assert storeType == long.class; // chunking only for int and long assert storeType == long.class; // chunking only for int and long
} }
int longValueIdx = cb.allocateLocal(LONG); int longValueIdx = cb.allocateLocal(LONG);
cb.storeLocal(LONG, longValueIdx); cb.lstore(longValueIdx);
int writeAddrIdx = cb.allocateLocal(REFERENCE); int writeAddrIdx = cb.allocateLocal(REFERENCE);
cb.storeLocal(REFERENCE, writeAddrIdx); cb.astore(writeAddrIdx);
int remaining = byteWidth; int remaining = byteWidth;
int chunkOffset = 0; int chunkOffset = 0;
@ -648,25 +646,25 @@ public class BindingSpecializer {
//int writeChunk = (int) (((0xFFFF_FFFFL << shiftAmount) & longValue) >>> shiftAmount); //int writeChunk = (int) (((0xFFFF_FFFFL << shiftAmount) & longValue) >>> shiftAmount);
int shiftAmount = chunkOffset * Byte.SIZE; int shiftAmount = chunkOffset * Byte.SIZE;
mask = mask << shiftAmount; mask = mask << shiftAmount;
cb.loadLocal(LONG, longValueIdx); cb.lload(longValueIdx)
cb.loadConstant(mask); .loadConstant(mask)
cb.land(); .land();
if (shiftAmount != 0) { if (shiftAmount != 0) {
cb.loadConstant(shiftAmount); cb.loadConstant(shiftAmount)
cb.lushr(); .lushr();
} }
cb.l2i(); cb.l2i();
TypeKind chunkStoreTypeKind = TypeKind.from(chunkStoreType); TypeKind chunkStoreTypeKind = TypeKind.from(chunkStoreType);
int chunkIdx = cb.allocateLocal(chunkStoreTypeKind); int chunkIdx = cb.allocateLocal(chunkStoreTypeKind);
cb.storeLocal(chunkStoreTypeKind, chunkIdx); cb.storeLocal(chunkStoreTypeKind, chunkIdx)
// chunk done, now write it // chunk done, now write it
//writeAddress.set(JAVA_SHORT_UNALIGNED, offset, writeChunk); //writeAddress.set(JAVA_SHORT_UNALIGNED, offset, writeChunk);
cb.loadLocal(REFERENCE, writeAddrIdx); .aload(writeAddrIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkStoreType); ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkStoreType);
long writeOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); long writeOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize);
cb.loadConstant(writeOffset); cb.loadConstant(writeOffset)
cb.loadLocal(chunkStoreTypeKind, chunkIdx); .loadLocal(chunkStoreTypeKind, chunkIdx);
MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(chunkStoreType)); MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(chunkStoreType));
cb.invokeinterface(CD_MemorySegment, "set", descriptor); cb.invokeinterface(CD_MemorySegment, "set", descriptor);
@ -690,16 +688,16 @@ public class BindingSpecializer {
if (!callingSequence.needsReturnBuffer()) { if (!callingSequence.needsReturnBuffer()) {
emitSaveReturnValue(storeType); emitSaveReturnValue(storeType);
} else { } else {
int valueIdx = cb.allocateLocal(storeTypeKind);
cb.storeLocal(storeTypeKind, valueIdx); // store away the stored value, need it later
assert returnBufferIdx != -1; assert returnBufferIdx != -1;
cb.loadLocal(REFERENCE, returnBufferIdx); int valueIdx = cb.allocateLocal(storeTypeKind);
cb.storeLocal(storeTypeKind, valueIdx) // store away the stored value, need it later
.aload(returnBufferIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType);
cb.loadConstant(retBufOffset); cb.loadConstant(retBufOffset)
cb.loadLocal(storeTypeKind, valueIdx); .loadLocal(storeTypeKind, valueIdx)
MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)); .invokeinterface(CD_MemorySegment,
cb.invokeinterface(CD_MemorySegment, "set", descriptor); "set",
MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)));
retBufOffset += abi.arch.typeSize(vmStore.storage().type()); retBufOffset += abi.arch.typeSize(vmStore.storage().type());
} }
} }
@ -714,11 +712,12 @@ public class BindingSpecializer {
emitRestoreReturnValue(loadType); emitRestoreReturnValue(loadType);
} else { } else {
assert returnBufferIdx != -1; assert returnBufferIdx != -1;
cb.loadLocal(REFERENCE, returnBufferIdx); cb.aload(returnBufferIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType);
cb.loadConstant(retBufOffset); cb.loadConstant(retBufOffset)
MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long); .invokeinterface(CD_MemorySegment,
cb.invokeinterface(CD_MemorySegment, "get", descriptor); "get",
MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long));
retBufOffset += abi.arch.typeSize(vmLoad.storage().type()); retBufOffset += abi.arch.typeSize(vmLoad.storage().type());
pushType(loadType); pushType(loadType);
} }
@ -736,15 +735,15 @@ public class BindingSpecializer {
private void emitShiftLeft(ShiftLeft shiftLeft) { private void emitShiftLeft(ShiftLeft shiftLeft) {
popType(long.class); popType(long.class);
cb.loadConstant(shiftLeft.shiftAmount() * Byte.SIZE); cb.loadConstant(shiftLeft.shiftAmount() * Byte.SIZE)
cb.lshl(); .lshl();
pushType(long.class); pushType(long.class);
} }
private void emitShiftRight(ShiftRight shiftRight) { private void emitShiftRight(ShiftRight shiftRight) {
popType(long.class); popType(long.class);
cb.loadConstant(shiftRight.shiftAmount() * Byte.SIZE); cb.loadConstant(shiftRight.shiftAmount() * Byte.SIZE)
cb.lushr(); .lushr();
pushType(long.class); pushType(long.class);
} }
@ -758,11 +757,10 @@ public class BindingSpecializer {
// implement least significant byte non-zero test // implement least significant byte non-zero test
// select first byte // select first byte
cb.loadConstant(0xFF); cb.loadConstant(0xFF)
cb.iand(); .iand()
// convert to boolean
// convert to boolean .invokestatic(CD_Utils, "byteToBoolean", MTD_BYTE_TO_BOOLEAN);
cb.invokestatic(CD_Utils, "byteToBoolean", MTD_BYTE_TO_BOOLEAN);
} }
case INT_TO_BYTE -> cb.i2b(); case INT_TO_BYTE -> cb.i2b();
case INT_TO_CHAR -> cb.i2c(); case INT_TO_CHAR -> cb.i2c();
@ -782,8 +780,8 @@ public class BindingSpecializer {
private void emitSegmentBase() { private void emitSegmentBase() {
popType(MemorySegment.class); popType(MemorySegment.class);
cb.checkcast(CD_AbstractMemorySegmentImpl); cb.checkcast(CD_AbstractMemorySegmentImpl)
cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE); .invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE);
pushType(Object.class); pushType(Object.class);
} }
@ -791,11 +789,11 @@ public class BindingSpecializer {
popType(MemorySegment.class); popType(MemorySegment.class);
if (!segmentOffset.allowHeap()) { if (!segmentOffset.allowHeap()) {
cb.dup(); cb.dup()
cb.invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE); .invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE);
} }
cb.checkcast(CD_AbstractMemorySegmentImpl); cb.checkcast(CD_AbstractMemorySegmentImpl)
cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET); .invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET);
pushType(long.class); pushType(long.class);
} }
@ -809,17 +807,17 @@ public class BindingSpecializer {
if (SharedUtils.isPowerOfTwo(byteWidth)) { if (SharedUtils.isPowerOfTwo(byteWidth)) {
ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType);
cb.loadConstant(offset); cb.loadConstant(offset)
MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long); .invokeinterface(CD_MemorySegment,
cb.invokeinterface(CD_MemorySegment, "get", descriptor); "get",
MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long));
} else { } else {
// chunked // chunked
int readAddrIdx = cb.allocateLocal(REFERENCE); int readAddrIdx = cb.allocateLocal(REFERENCE);
cb.storeLocal(REFERENCE, readAddrIdx); cb.astore(readAddrIdx)
.loadConstant(0L); // result
cb.loadConstant(0L); // result
int resultIdx = cb.allocateLocal(LONG); int resultIdx = cb.allocateLocal(LONG);
cb.storeLocal(LONG, resultIdx); cb.lstore(resultIdx);
int remaining = byteWidth; int remaining = byteWidth;
int chunkOffset = 0; int chunkOffset = 0;
@ -848,30 +846,30 @@ public class BindingSpecializer {
throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize); throw new IllegalStateException("Unexpected chunk size for chunked write: " + chunkSize);
} }
// read from segment // read from segment
cb.loadLocal(REFERENCE, readAddrIdx); cb.aload(readAddrIdx);
ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkType); ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkType);
MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(chunkType), valueLayoutType, CD_long); MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(chunkType), valueLayoutType, CD_long);
long readOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); long readOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize);
cb.loadConstant(readOffset); cb.loadConstant(readOffset)
cb.invokeinterface(CD_MemorySegment, "get", descriptor); .invokeinterface(CD_MemorySegment, "get", descriptor)
cb.invokestatic(toULongHolder, "toUnsignedLong", toULongDescriptor); .invokestatic(toULongHolder, "toUnsignedLong", toULongDescriptor);
// shift to right offset // shift to right offset
int shiftAmount = chunkOffset * Byte.SIZE; int shiftAmount = chunkOffset * Byte.SIZE;
if (shiftAmount != 0) { if (shiftAmount != 0) {
cb.loadConstant(shiftAmount); cb.loadConstant(shiftAmount)
cb.lshl(); .lshl();
} }
// add to result // add to result
cb.loadLocal(LONG, resultIdx); cb.lload(resultIdx)
cb.lor(); .lor()
cb.storeLocal(LONG, resultIdx); .lstore(resultIdx);
remaining -= chunkSize; remaining -= chunkSize;
chunkOffset += chunkSize; chunkOffset += chunkSize;
} while (remaining != 0); } while (remaining != 0);
cb.loadLocal(LONG, resultIdx); cb.lload(resultIdx);
if (loadType == int.class) { if (loadType == int.class) {
cb.l2i(); cb.l2i();
} else { } else {
@ -898,19 +896,18 @@ public class BindingSpecializer {
emitAllocateCall(size, alignment); emitAllocateCall(size, alignment);
cb.dup(); cb.dup();
int storeIdx = cb.allocateLocal(REFERENCE); int storeIdx = cb.allocateLocal(REFERENCE);
cb.storeLocal(REFERENCE, storeIdx); cb.astore(storeIdx)
cb.loadConstant(0L); .loadConstant(0L)
cb.loadConstant(size); .loadConstant(size)
cb.invokestatic(CD_MemorySegment, "copy", MTD_COPY, true); .invokestatic(CD_MemorySegment, "copy", MTD_COPY, true)
.aload(storeIdx);
cb.loadLocal(REFERENCE, storeIdx);
pushType(MemorySegment.class); pushType(MemorySegment.class);
} }
private void emitAllocateCall(long size, long alignment) { private void emitAllocateCall(long size, long alignment) {
cb.loadConstant(size); cb.loadConstant(size)
cb.loadConstant(alignment); .loadConstant(alignment)
cb.invokeinterface(CD_SegmentAllocator, "allocate", MTD_ALLOCATE); .invokeinterface(CD_SegmentAllocator, "allocate", MTD_ALLOCATE);
} }
private ClassDesc emitLoadLayoutConstant(Class<?> type) { private ClassDesc emitLoadLayoutConstant(Class<?> type) {