Skip to content

Commit 3b61f7c

Browse files
committed
Added tail call optimization to TruffleMumbler.
1 parent 018c362 commit 3b61f7c

File tree

7 files changed

+77
-6
lines changed

7 files changed

+77
-6
lines changed

graal/src/mumbler/truffle/Reader.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ private MumblerNode toSpecialForm() {
120120
for (Convertible bodyConv : this.list.subList(2, this.list.size())) {
121121
bodyNodes.add(bodyConv.convert());
122122
}
123+
bodyNodes.get(bodyNodes.size() - 1).setIsTail();
123124
frameDescriptors.pop();
124125
MumblerFunction function = MumblerFunction.create(
125126
formalParameters.toArray(new FrameSlot[] {}),

graal/src/mumbler/truffle/TruffleMumblerMain.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import mumbler.truffle.node.builtin.NowBuiltinNodeFactory;
1616
import mumbler.truffle.node.builtin.PrintlnBuiltinNodeFactory;
1717
import mumbler.truffle.node.builtin.SubBuiltinNodeFactory;
18+
import mumbler.truffle.node.call.TailCallException;
1819
import mumbler.truffle.type.MumblerFunction;
1920
import mumbler.truffle.type.MumblerList;
2021

@@ -73,9 +74,14 @@ private static Object execute(MumblerList<MumblerNode> nodes,
7374
frameDescriptor);
7475
DirectCallNode directCallNode = Truffle.getRuntime()
7576
.createDirectCallNode(function.callTarget);
76-
return directCallNode.call(
77-
topFrame,
78-
new Object[] {topFrame.materialize()});
77+
78+
try {
79+
return directCallNode.call(
80+
topFrame,
81+
new Object[] {topFrame.materialize()});
82+
} catch (TailCallException e) {
83+
return e.call(topFrame);
84+
}
7985
}
8086

8187
private static VirtualFrame createTopFrame(FrameDescriptor frameDescriptor) {

graal/src/mumbler/truffle/node/MumblerNode.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import mumbler.truffle.type.MumblerList;
99
import mumbler.truffle.type.MumblerSymbol;
1010

11+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
1112
import com.oracle.truffle.api.dsl.TypeSystemReference;
1213
import com.oracle.truffle.api.frame.VirtualFrame;
1314
import com.oracle.truffle.api.nodes.Node;
@@ -17,6 +18,17 @@
1718
@TypeSystemReference(MumblerTypes.class)
1819
@NodeInfo(language = "Mumbler Language", description = "The abstract base node for all expressions")
1920
public abstract class MumblerNode extends Node {
21+
@CompilationFinal
22+
private boolean isTail = false;
23+
24+
public boolean isTail() {
25+
return this.isTail;
26+
}
27+
28+
public void setIsTail() {
29+
this.isTail = true;
30+
}
31+
2032
public abstract Object execute(VirtualFrame virtualFrame);
2133

2234
public long executeLong(VirtualFrame virtualFrame)

graal/src/mumbler/truffle/node/MumblerRootNode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Arrays;
44

5+
import mumbler.truffle.node.call.TailCallException;
56
import mumbler.truffle.node.special.DefineNodeFactory;
67

78
import com.oracle.truffle.api.CompilerAsserts;

graal/src/mumbler/truffle/node/call/InvokeNode.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,25 @@ public Object execute(VirtualFrame virtualFrame) {
3939

4040
if (this.callNode == null) {
4141
CompilerDirectives.transferToInterpreterAndInvalidate();
42-
this.callNode = this.insert(Truffle.getRuntime().createDirectCallNode(function.callTarget));
42+
this.callNode = this.insert(Truffle.getRuntime()
43+
.createDirectCallNode(function.callTarget));
4344
}
4445

4546
if (function.callTarget != this.callNode.getCallTarget()) {
4647
CompilerDirectives.transferToInterpreterAndInvalidate();
47-
throw new UnsupportedOperationException("need to implement a proper inline cache.");
48+
throw new UnsupportedOperationException(
49+
"Need to implement a proper inline cache.");
4850
}
4951

50-
return this.callNode.call(virtualFrame, argumentValues);
52+
if (this.isTail()) {
53+
throw new TailCallException(this.callNode, argumentValues);
54+
} else {
55+
try {
56+
return this.callNode.call(virtualFrame, argumentValues);
57+
} catch (TailCallException e) {
58+
return e.call(virtualFrame);
59+
}
60+
}
5161
}
5262

5363
private MumblerFunction evaluateFunction(VirtualFrame virtualFrame) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package mumbler.truffle.node.call;
2+
3+
import com.oracle.truffle.api.frame.VirtualFrame;
4+
import com.oracle.truffle.api.nodes.ControlFlowException;
5+
import com.oracle.truffle.api.nodes.DirectCallNode;
6+
7+
public class TailCallException extends ControlFlowException {
8+
private static final long serialVersionUID = 1L;
9+
10+
private final DirectCallNode callNode;
11+
private final Object[] arguments;
12+
public boolean outOfFunction = false;
13+
14+
public TailCallException(DirectCallNode callNode, Object[] arguments) {
15+
this.callNode = callNode;
16+
this.arguments = arguments;
17+
}
18+
19+
public Object call(VirtualFrame virtualFrame) {
20+
TailCallException tailCall = null;
21+
try {
22+
return this.callNode.call(virtualFrame, this.arguments);
23+
} catch (TailCallException e) {
24+
tailCall = e;
25+
}
26+
do {
27+
try {
28+
return tailCall.callNode.call(virtualFrame, tailCall.arguments);
29+
} catch (TailCallException e) {
30+
tailCall = e;
31+
}
32+
} while (true);
33+
}
34+
}

graal/src/mumbler/truffle/node/special/IfNode.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ public Object execute(VirtualFrame virtualFrame) {
3131
}
3232
}
3333

34+
@Override
35+
public void setIsTail() {
36+
super.setIsTail();
37+
this.thenNode.setIsTail();
38+
this.elseNode.setIsTail();
39+
}
40+
3441
private boolean testResult(VirtualFrame virtualFrame) {
3542
try {
3643
return this.testNode.executeBoolean(virtualFrame);

0 commit comments

Comments
 (0)