Skip to content

Commit 7311afa

Browse files
committed
Use fixed trampoline function
This greatly simplifies the bounce handle.
1 parent 5991085 commit 7311afa

File tree

3 files changed

+39
-72
lines changed

3 files changed

+39
-72
lines changed

rt4core/src/main/java/uk/co/farowl/vsj4/kernel/Representation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ public MethodHandle op_pow() {
791791
* @return handle on {@code __neg__} with signature
792792
* {@link Signature#UNARY}.
793793
*/
794-
public MethodHandle op_neg() { return op_neg; }
794+
public final MethodHandle op_neg() { return op_neg; }
795795

796796
private MethodHandle op_neg;
797797

rt4core/src/main/java/uk/co/farowl/vsj4/kernel/SharedRepresentation.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
// Copyright (c)2025 Jython Developers.
1+
// Copyright (c)2026 Jython Developers.
22
// Licensed to PSF under a contributor agreement.
33
package uk.co.farowl.vsj4.kernel;
44

5-
import static uk.co.farowl.vsj4.core.ClassShorthand.T;
6-
import static uk.co.farowl.vsj4.support.JavaClassShorthand.O;
7-
8-
import java.lang.invoke.MethodHandle;
9-
import java.lang.invoke.MethodHandles;
10-
import java.lang.invoke.MethodHandles.Lookup;
11-
import java.lang.invoke.MethodType;
12-
135
import uk.co.farowl.vsj4.core.PyType;
146
import uk.co.farowl.vsj4.support.InterpreterError;
157
import uk.co.farowl.vsj4.types.WithClass;

rt4core/src/main/java/uk/co/farowl/vsj4/kernel/SpecialMethod.java

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import java.lang.invoke.MethodHandles.Lookup;
1111
import java.lang.invoke.MethodType;
1212
import java.lang.invoke.VarHandle;
13-
import java.lang.invoke.VarHandle.AccessMode;
1413
import java.util.Collections;
1514
import java.util.HashMap;
1615
import java.util.Map;
@@ -1311,43 +1310,12 @@ public static final class SMUtil {
13111310
*/
13121311
static final MethodHandle asJavaBoolean;
13131312

1314-
/**
1315-
* Method handle on {@link BaseType#cast(PyType)}, which checks
1316-
* a type is a {@code BaseType}, therefore "one of ours". This
1317-
* may raise {@code TypeError}.
1318-
*/
1319-
static final MethodHandle asBaseType;
1320-
1321-
/**
1322-
* Method handle applicable to a {@code SpecialMethod} and a
1323-
* {@link BaseType}, that retrieves the cached method handle
1324-
* from the provided type. It is equivalent to
1325-
* {@link SpecialMethod#handle(Representation)}, except it does
1326-
* not check whether the cache exists for the
1327-
* {@code SpecialMethod}. (If {@code sm.hasCache()} is false,
1328-
* you should invoke {@code sm.generic}. It is used to form
1329-
* {@code sm.bounce}.
1330-
*/
1331-
static final MethodHandle getCache;
1332-
1333-
private static final Class<BaseType> BT = BaseType.class;
1334-
private static final Class<Representation> REP =
1335-
Representation.class;
1336-
private static final Class<MethodHandle> MH =
1337-
MethodHandle.class;
1338-
13391313
static {
13401314
try {
13411315
asJavaInt = LOOKUP.findStatic(PyLong.class, "asInt",
13421316
MethodType.methodType(I, O));
13431317
asJavaBoolean = LOOKUP.findStatic(Abstract.class,
13441318
"isTrue", MethodType.methodType(B, O));
1345-
asBaseType = LOOKUP.findStatic(BT, "cast",
1346-
MethodType.methodType(BT, T));
1347-
// MethodType here has to match actual of sm.cache
1348-
getCache = MethodHandles.varHandleExactInvoker(
1349-
AccessMode.GET, MethodType.methodType(MH, REP));
1350-
13511319
} catch (NoSuchMethodException | IllegalAccessException e) {
13521320
// Handle lookup fails somewhere
13531321
throw new InterpreterError(e,
@@ -1449,55 +1417,47 @@ static MethodHandle slotMH(SpecialMethod sm) {
14491417
}
14501418

14511419
/**
1452-
* Helper for {@link SpecialMethod} providing a method handle
1453-
* that accesses the special method cache on the type of
1454-
* {@code self}, and invokes the handle it finds there.
1420+
* Helper for {@link SpecialMethod} providing a method handle on
1421+
* the corresponding trampoline method (e.g.
1422+
* {@link #op_neg(BaseType, Object)}) invokes the special method
1423+
* cache on the type of {@code self}. We place this type of
1424+
* handle in a {@link SharedRepresentation}, and the type is
1425+
* always a {@link ReplaceableType}.
14551426
*
14561427
* @param sm to access on the type of {@code self}
14571428
* @return a handle that looks up and calls {@code sm}
14581429
*/
14591430
static MethodHandle bounceMH(SpecialMethod sm) {
14601431

14611432
// We aim to create:
1462-
// bounce = λ(s, ...): sm.cache(type(s)).invoke(s,...)
1433+
// bounce = λ(s, ...): trampoline(sm)(type(s), s, ...)
14631434
try {
1435+
/*
1436+
* Find the trampoline method handle smt. The signature
1437+
* is that of the special method, with PyType inserted
1438+
* first.
1439+
*/
1440+
// smt = λ(t,s): BaseType.cast(t,s,...)
1441+
MethodHandle smt = LOOKUP.findStatic(
1442+
SpecialMethod.class, sm.name(),
1443+
sm.signature.type.insertParameterTypes(0, T));
1444+
14641445
/*
14651446
* As bounce is only published from shared
1466-
* representations, we can use WithClass.getType().
1447+
* representations, we can rely on WithClass.getType().
14671448
*/
1468-
// type = λ(s): (Representation) BaseType.cast(type(s))
1449+
// type = λ(s): BaseType.cast(type(s))
14691450
MethodHandle type = LOOKUP.findVirtual(WithClass.class,
14701451
"getType", MethodType.methodType(T));
1471-
type = MethodHandles.filterReturnValue(type,
1472-
asBaseType);
14731452
/*
14741453
* It will be safe to cast from Object to WithClass as
14751454
* the self-class was mapped to a SharedRepresentation.
1476-
* Also from BaseType to Representation, obviously.
14771455
*/
1478-
type = type.asType(MethodType.methodType(REP, O));
1456+
type = type.asType(MethodType.methodType(T, O));
14791457

1480-
/*
1481-
* Use the sm.cache VarHandle to make a method that will
1482-
* access the sm cache on type(self).
1483-
*/
1484-
// getter = λ(s): sm.cache.get(type(s))
1485-
assert sm.hasCache();
1486-
MethodHandle getter = MethodHandles.filterArguments(
1487-
getCache.bindTo(sm.cache), 0, type);
1488-
1489-
/*
1490-
* Create a handle to invoke the handle we shall get
1491-
* from type(self) with the arguments originally
1492-
* supplied.
1493-
*/
1494-
// invoker = λ(h, s,...): h.invoke(s,...)
1495-
MethodHandle invoker =
1496-
MethodHandles.invoker(sm.signature.type);
1497-
1498-
// bounce = λ(s,...): getter(type(s)).invoke(s,...)
1458+
// bounce = λ(s,...): smt(type(s),s,...)
14991459
MethodHandle bounce =
1500-
MethodHandles.foldArguments(invoker, getter);
1460+
MethodHandles.foldArguments(smt, type);
15011461

15021462
assert bounce.type() == sm.signature.type;
15031463
return bounce;
@@ -1508,6 +1468,7 @@ static MethodHandle bounceMH(SpecialMethod sm) {
15081468
}
15091469
}
15101470

1471+
15111472
/**
15121473
* Helper for {@link SpecialMethod} and thereby for call sites
15131474
* providing a method handle that raises a Python exception when
@@ -1749,4 +1710,18 @@ PyBaseException attributeError(PyType type) {
17491710

17501711
private static final String UNSUPPORTED_TYPES =
17511712
"unsupported operand type(s) for %s: '%.100s' and '%.100s'";
1713+
1714+
// Trampolines ---------------------------------------------------
1715+
/*
1716+
* These methods are referenced in SMUtil.bounceMH to create the
1717+
* bounce handle of corresponding special methods for which a cache
1718+
* is allocated on Representation objects. Their signature is always
1719+
* that of the special method, with PyType inserted first.
1720+
*/
1721+
@SuppressWarnings("unused")
1722+
private static Object op_neg(PyType type, Object self)
1723+
throws Throwable {
1724+
return BaseType.cast(type).op_neg().invokeExact(self);
1725+
}
1726+
17521727
}

0 commit comments

Comments
 (0)