Skip to content

Commit 9659e8f

Browse files
committed
Removed a support for self replacement.
1 parent bd3dec5 commit 9659e8f

File tree

6 files changed

+22
-264
lines changed

6 files changed

+22
-264
lines changed

truffle/src/com.oracle.truffle.api.library.test/src/com/oracle/truffle/api/library/test/GenerateLibraryTest.java

Lines changed: 1 addition & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949

5050
import com.oracle.truffle.api.dsl.Cached;
5151
import com.oracle.truffle.api.frame.VirtualFrame;
52-
import com.oracle.truffle.api.library.CachedLibrary;
5352
import com.oracle.truffle.api.library.ExportLibrary;
5453
import com.oracle.truffle.api.library.ExportMessage;
5554
import com.oracle.truffle.api.library.GenerateLibrary;
@@ -622,6 +621,7 @@ public boolean isType(Object receiver) {
622621
return false;
623622
}
624623

624+
@ExpectError("The 'replacementMethod' attribute is only valid when 'replacementOf' is also specified.")
625625
@Abstract(replacementMethod = "isType")
626626
public Object replacedErr(Object receiver) {
627627
return receiver;
@@ -640,130 +640,6 @@ public boolean replace2(Object receiver) {
640640
}
641641
}
642642

643-
@GenerateLibrary
644-
public abstract static class SelfReplacementsLibraryA extends Library {
645-
646-
public void noop(Object receiver) {
647-
}
648-
649-
public boolean canComputeFactorial(Object receiver) {
650-
return false;
651-
}
652-
653-
@Abstract(ifExported = "canComputeFactorial")
654-
public double multiply(Object receiver, double a, double b) {
655-
throw new UnsupportedOperationException();
656-
}
657-
658-
@Abstract(ifExportedAsWarning = "canComputeFactorial", replacementMethod = "factorialFixed")
659-
public double factorial(Object receiver, int n) {
660-
return n;
661-
}
662-
663-
// Replaces factorial() only when factorial() is not exported
664-
// and canComputeFactorial() is exported.
665-
protected final double factorialFixed(Object receiver, int n) {
666-
double f = n;
667-
for (int i = 2; i < n; i++) {
668-
f = multiply(receiver, f, i);
669-
}
670-
return f;
671-
}
672-
}
673-
674-
@GenerateLibrary
675-
public abstract static class SelfReplacementsLibraryB extends Library {
676-
677-
public boolean canComputeFactorial(Object receiver) {
678-
return false;
679-
}
680-
681-
@Abstract(ifExported = "canComputeFactorial")
682-
public double multiply(Object receiver, double a, double b) {
683-
throw new UnsupportedOperationException();
684-
}
685-
686-
@Abstract(ifExportedAsWarning = "canComputeFactorial", replacementMethod = "factorialFixed")
687-
public double factorial(Object receiver, int n) {
688-
return n;
689-
}
690-
691-
// Replaces factorial() only when factorial() is not exported
692-
// and canComputeFactorial() is exported.
693-
@SuppressWarnings("static-method")
694-
protected final double factorialFixed(Object receiver, int n, @CachedLibrary(limit = "2") SelfReplacementsLibraryB helperLibrary) {
695-
if (helperLibrary.canComputeFactorial(n)) {
696-
double f = helperLibrary.factorial(n, n);
697-
return f;
698-
} else {
699-
return -n;
700-
}
701-
}
702-
}
703-
704-
@ExportLibrary(SelfReplacementsLibraryA.class)
705-
public static final class SelfReplacementsLibraryImplA1 extends Object {
706-
707-
// Only to prevent from warning: Exported library has no effect.
708-
@ExportMessage
709-
void noop() {
710-
}
711-
712-
// canComputeFactorial() is not implemented,
713-
// we have only the default impl of factorial() that returns `n`.
714-
}
715-
716-
@ExportLibrary(SelfReplacementsLibraryA.class)
717-
@SuppressWarnings("static-method")
718-
public static final class SelfReplacementsLibraryImplA3 extends Object {
719-
720-
@ExportMessage
721-
boolean canComputeFactorial() {
722-
return true;
723-
}
724-
725-
@ExportMessage
726-
double multiply(double a, double b) {
727-
return a * b;
728-
}
729-
730-
@ExportMessage
731-
double factorial(int n) {
732-
return 2 * n;
733-
}
734-
}
735-
736-
@ExportLibrary(SelfReplacementsLibraryB.class)
737-
@SuppressWarnings({"static-method", "truffle-abstract-export"})
738-
public static final class SelfReplacementsLibraryImplB3 extends Object {
739-
740-
@ExportMessage
741-
boolean canComputeFactorial() {
742-
return true;
743-
}
744-
745-
@ExportMessage
746-
double multiply(double a, double b) {
747-
return a * b;
748-
}
749-
}
750-
751-
@ExpectError({"The following message(s) of library SelfReplacementsLibraryB are abstract and should be exported using:%"})
752-
@ExportLibrary(SelfReplacementsLibraryB.class)
753-
@SuppressWarnings("static-method")
754-
public static final class SelfReplacementsLibraryImplBErr extends Object {
755-
756-
@ExportMessage
757-
boolean canComputeFactorial() {
758-
return true;
759-
}
760-
761-
@ExportMessage
762-
double multiply(double a, double b) {
763-
return a * b;
764-
}
765-
}
766-
767643
interface ExportsType {
768644
}
769645

truffle/src/com.oracle.truffle.api.library/src/com/oracle/truffle/api/library/GenerateLibrary.java

Lines changed: 14 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -378,26 +378,20 @@
378378
String replacementOf() default "";
379379

380380
/**
381-
* Specifies a method that provides a replacement implementation for a message.
381+
* Specifies a custom replacement method to handle delegation for a message declared with
382+
* {@link #replacementOf()}.
382383
* <p>
383-
* This annotation serves two related purposes, depending on how it is used:
384-
* <ol>
385-
* <li><b>Custom replacement for a {@link #replacementOf()} message:</b> Used when a
386-
* deprecated message cannot be automatically delegated to its replacement due to
387-
* differences in argument semantics, type conversions, or behavioral requirements. In this
388-
* mode, the specified method implements the conversion or adaptation logic between the
389-
* deprecated and replacement messages. The method must have a compatible signature and be
390-
* accessible from the annotated message.</li>
391-
* <li><b>Self-replacement method:</b> Used to provide a fallback implementation for the
392-
* annotated message itself. The self-replacement method is invoked only when the annotated
393-
* message is not exported, but one or more messages listed in {@link #ifExported()} or
394-
* {@link #ifExportedAsWarning()} are exported. This allows non-exported messages to
395-
* participate in message relationships without requiring explicit implementation by the
396-
* user.</li>
397-
* </ol>
384+
* This attribute provides a way to manually implement delegation logic when automatic
385+
* delegation from the deprecated message to its replacement cannot be generated correctly.
386+
* Typical reasons include differences in argument semantics, necessary type conversions, or
387+
* behavioral changes that cannot be inferred automatically.
388+
* <p>
389+
* This element is only valid when {@link #replacementOf()} is also set. Using it without
390+
* {@code replacementOf} will result in a compilation error. The specified method must have
391+
* a compatible signature and be accessible from the annotated message.
398392
*
399393
* <p>
400-
* <b>Example - Custom replacement for {@link #replacementOf()}:</b>
394+
* <b>Example:</b>
401395
*
402396
* <pre>
403397
* &#64;Abstract(ifExported = "isArray", replacementOf = "read(Object, int)", replacementMethod = "readLegacy")
@@ -411,44 +405,9 @@
411405
* }
412406
* </pre>
413407
*
414-
* In this example, automatic conversion between {@code int} and {@code long} indices would
415-
* yield incorrect results because the index is treated as unsigned. The custom
416-
* {@code readLegacy} method therefore provides the correct delegation logic.
417-
*
418-
* <p>
419-
* <b>Example - Self-replacement method:</b>
420-
*
421-
* <pre>
422-
* &#64;GenerateLibrary
423-
* public abstract static class SelfReplacementLibrary extends Library {
424-
*
425-
* public boolean canComputeFactorial(Object receiver) {
426-
* return false;
427-
* }
428-
*
429-
* &#64;Abstract(ifExported = "canComputeFactorial")
430-
* public double multiply(Object receiver, double a, double b) {
431-
* throw new UnsupportedOperationException();
432-
* }
433-
*
434-
* &#64;Abstract(ifExportedAsWarning = "canComputeFactorial", replacementMethod = "factorialFixed")
435-
* public double factorial(Object receiver, int n) {
436-
* throw new UnsupportedOperationException();
437-
* }
438-
*
439-
* // Used only when factorial() is not exported but canComputeFactorial() is.
440-
* protected final double factorialFixed(Object receiver, int n) {
441-
* double f = n;
442-
* for (int i = 2; i &lt; n; i++) {
443-
* f = multiply(receiver, f, i);
444-
* }
445-
* return f;
446-
* }
447-
* }
448-
* </pre>
449-
*
450-
* In this example, {@code factorialFixed} serves as a fallback implementation for
451-
* {@code factorial()} when it is not exported but another related message is.
408+
* In this example, the deprecated {@code read(Object, int)} message cannot be automatically
409+
* delegated to {@code read(Object, long)} because the index must be treated as unsigned.
410+
* The custom {@code readLegacy} method therefore provides the correct conversion logic.
452411
*
453412
* @see #replacementOf()
454413
* @since 25.1

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/library/ExportMessageData.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,6 @@ public class ExportMessageData extends MessageContainer {
6262

6363
private final Element element;
6464
private final AnnotationMirror annotation;
65-
/**
66-
* The type that serves as the target of a self replacement.
67-
*/
68-
private TypeMirror selfReplacementTarget;
6965
private NodeData specializedNode;
7066

7167
private boolean overriden;
@@ -126,25 +122,7 @@ public boolean isMethod() {
126122
return !isClass();
127123
}
128124

129-
public boolean isSelfReplacement() {
130-
return selfReplacementTarget != null;
131-
}
132-
133-
/**
134-
* Marks this {@link ExportMessageData} as a self replacement.
135-
* <p>
136-
* The corresponding self replacement method is invoked as if it were static: the receiver is
137-
* passed as the first argument, even though the method itself is not static. The target method
138-
* owner is the <em>exported library instance</em>, not to the object that exports the library.
139-
*/
140-
void setSelfReplacement() {
141-
this.selfReplacementTarget = exports.getReceiverType();
142-
}
143-
144125
public TypeMirror getReceiverType() {
145-
if (selfReplacementTarget != null) {
146-
return selfReplacementTarget;
147-
}
148126
if (element == null || exports.isExplicitReceiver()) {
149127
return exports.getReceiverType();
150128
}

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/library/ExportsParser.java

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -269,42 +269,6 @@ protected ExportsData parse(Element element, List<AnnotationMirror> elementMirro
269269
replacedExport.addError(error);
270270
}
271271
}
272-
for (LibraryMessage message : library.getLibrary().getAllMethods()) {
273-
ExecutableElement replacementMethod = message.getReplacementMethod();
274-
if (replacementMethod != null && message.getReplacementOf() == null) {
275-
// Replacing this message, if not exported
276-
if (!exportedMessages.containsKey(message.getName())) {
277-
// Exported messages do not contain this message
278-
// We'll generate the replacement when some message from isExported is
279-
// exported
280-
boolean shouldReplace = false;
281-
for (LibraryMessage expMessage : message.getAbstractIfExportedAsWarning()) {
282-
ExportMessageData messageData = exportedMessages.get(expMessage.getName());
283-
if (messageData != null) {
284-
shouldReplace = true;
285-
break;
286-
}
287-
}
288-
if (shouldReplace) {
289-
// We need to add an @ExportMessage annotation for the generated message
290-
AnnotationMirror exportAnnotation = new CodeAnnotationMirror(ProcessorContext.getInstance().getTypes().ExportMessage);
291-
CodeExecutableElement replaceWithClone = CodeExecutableElement.clone(replacementMethod);
292-
if (library.isExplicitReceiver()) {
293-
replaceWithClone.getModifiers().add(STATIC);
294-
}
295-
Element enclosing = ElementUtils.castTypeElement(library.getReceiverType());
296-
replaceWithClone.setEnclosingElement(enclosing);
297-
replacementMethod = replaceWithClone;
298-
ExportMessageData exportData = new ExportMessageData(library, message, replacementMethod, exportAnnotation);
299-
exportData.setSelfReplacement();
300-
exportedElements.add(exportData);
301-
exportedMessages.put(message.getName(), exportData);
302-
Set<LibraryMessage> generatedNames = generatedLibraryMessages.computeIfAbsent(library, (lib) -> new HashSet<>());
303-
generatedNames.add(message);
304-
}
305-
}
306-
}
307-
}
308272
}
309273

310274
/*
@@ -1376,13 +1340,9 @@ private void initializeExportedMethod(Map<String, NodeData> parsedNodeCache, Exp
13761340
}
13771341

13781342
boolean isStaticMethod = element.getModifiers().contains(Modifier.STATIC);
1379-
boolean isForcedStatic = exportedElement.isSelfReplacement();
1380-
boolean isStatic = isStaticMethod || isForcedStatic;
1381-
if (!isStatic) {
1343+
if (!isStaticMethod) {
13821344
element.getParameters().add(0, new CodeVariableElement(exportedElement.getReceiverType(), "this"));
13831345
element.getModifiers().add(Modifier.STATIC);
1384-
} else if (exportedElement.isSelfReplacement()) {
1385-
element.getParameters().set(0, new CodeVariableElement(exportedElement.getReceiverType(), "receiver"));
13861346
}
13871347

13881348
if (message.getName().equals("accepts")) {
@@ -1487,8 +1447,7 @@ private NodeData parseNode(Map<String, NodeData> parsedNodeCache, TypeElement no
14871447
NodeData parsedNodeData = NodeParser.createExportParser(
14881448
exportedMessage.getExportsLibrary().getLibrary().getTemplateType().asType(),
14891449
exportedMessage.getExportsLibrary().getTemplateType(),
1490-
exportedMessage.getExportsLibrary().hasExportDelegation(),
1491-
!exportedMessage.isSelfReplacement()).parse(clonedType, false);
1450+
exportedMessage.getExportsLibrary().hasExportDelegation()).parse(clonedType, false);
14921451

14931452
parsedNodeCache.put(nodeTypeId, parsedNodeData);
14941453

@@ -1536,7 +1495,7 @@ private static boolean verifyMethodSignature(TypeElement type, LibraryMessage me
15361495
return false;
15371496
}
15381497

1539-
boolean explicitReceiver = exportedMethod.getModifiers().contains(Modifier.STATIC) || exportedMessage.isSelfReplacement();
1498+
boolean explicitReceiver = exportedMethod.getModifiers().contains(Modifier.STATIC);
15401499
int paramOffset = !explicitReceiver ? 1 : 0;
15411500
List<? extends VariableElement> expectedParameters = libraryMethod.getParameters().subList(paramOffset, libraryMethod.getParameters().size());
15421501
List<? extends VariableElement> exportedParameters = exportedMethod.getParameters().subList(0, realParameterCount);
@@ -1567,7 +1526,7 @@ private static boolean verifyMethodSignature(TypeElement type, LibraryMessage me
15671526
VariableElement exportedArg = exportedParameters.get(i);
15681527
VariableElement libraryArg = expectedParameters.get(i);
15691528
TypeMirror exportedArgType = exportedArg.asType();
1570-
TypeMirror libraryArgType = (explicitReceiver && !exportedMessage.isSelfReplacement() && i == 0) ? receiverType : libraryArg.asType();
1529+
TypeMirror libraryArgType = (explicitReceiver && i == 0) ? receiverType : libraryArg.asType();
15711530
if (!typeEquals(exportedArgType, libraryArgType)) {
15721531
if (emitErrors) {
15731532
exportedMessage.addError(exportedArg, "Invalid parameter type. Expected '%s' but was '%s'. Expected signature:%n %s",

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/library/LibraryParser.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,7 @@ protected LibraryData parse(Element element, List<AnnotationMirror> mirrors) {
291291
ExecutableElement replacementMethod = parseAbstractReplacementWith(message, replaced, abstractMirror, "replacementMethod", allMethods);
292292

293293
if (replacementMethod != null && replaced == null) {
294-
Set<LibraryMessage> ifExported = new HashSet<>(message.getAbstractIfExported());
295-
ifExported.addAll(message.getAbstractIfExportedAsWarning());
296-
message.setReplacementOf(null, replacementMethod);
294+
message.addError("The 'replacementMethod' attribute is only valid when 'replacementOf' is also specified.");
297295
}
298296
if (replaced != null) {
299297
if (!replacedMessages.add(replaced)) {

0 commit comments

Comments
 (0)