/
Primitive.java
114 lines (96 loc) · 3.89 KB
/
Primitive.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package som.interpreter;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeUtil;
import som.compiler.MethodBuilder;
import som.interpreter.actors.ResolvePromiseNode;
import som.interpreter.nodes.ExpressionNode;
import som.interpreter.nodes.SOMNode;
import som.primitives.ObjectPrims.HaltPrim;
import som.vmobjects.SInvokable;
public final class Primitive extends Invokable {
public Primitive(final String name, final ExpressionNode primitive,
final FrameDescriptor frameDescriptor,
final ExpressionNode uninitialized, final boolean isAtomic,
final SomLanguage lang) {
super(name, null, frameDescriptor, primitive, uninitialized, isAtomic, lang);
}
@Override
public ExpressionNode inline(final MethodBuilder builder, final SInvokable outer) {
// Note for completeness: for primitives, we use eager specialization,
// which is essentially much simpler inlining
throw new UnsupportedOperationException(
"Primitives are currently not directly inlined. Only block methods are.");
}
@Override
public Node deepCopy() {
assert getFrameDescriptor().getSize() == 0;
return new Primitive(name, NodeUtil.cloneNode(uninitializedBody),
getFrameDescriptor(), uninitializedBody, isAtomic,
SomLanguage.getLanguage(this));
}
@Override
public Invokable createAtomic() {
assert !isAtomic : "We should only ask non-atomic invokables for their atomic version";
ExpressionNode atomic = NodeUtil.cloneNode(uninitializedBody);
ExpressionNode uninitAtomic = NodeUtil.cloneNode(atomic);
return new Primitive(name, atomic, getFrameDescriptor(), uninitAtomic, true,
SomLanguage.getLanguage(this));
}
@Override
public String toString() {
ExpressionNode n = SOMNode.unwrapIfNecessary(expressionOrSequence);
String nodeType = n.getClass().getSimpleName();
if (n != expressionOrSequence) {
nodeType += " (wrapped)"; // indicate that it is wrapped
}
return nodeType + "\t@" + Integer.toHexString(hashCode());
}
@Override
public void propagateLoopCountThroughoutMethodScope(final long count) {
propagateLoopCount(count);
}
/**
* Primitive operations are not instrumentable. They are not user-level
* behavior, and thus, are supposed to remain opaque.
*/
@Override
protected boolean isInstrumentable() {
return expressionOrSequence instanceof HaltPrim
|| expressionOrSequence instanceof ResolvePromiseNode;
}
private static Method getNextMethodOnStack() {
return Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<Method>() {
@Override
public Method visitFrame(final FrameInstance frameInstance) {
RootCallTarget ct = (RootCallTarget) frameInstance.getCallTarget();
Invokable m = (Invokable) ct.getRootNode();
if (m instanceof Primitive) {
return null;
} else {
return (Method) m;
}
}
});
}
public static void propagateLoopCount(final long count) {
CompilerAsserts.neverPartOfCompilation("Primitive.pLC(.)");
// we need to skip the primitive and get to the method that called the primitive
FrameInstance caller = Truffle.getRuntime().getCallerFrame();
RootCallTarget ct = (RootCallTarget) caller.getCallTarget(); // caller method
Invokable m = (Invokable) ct.getRootNode();
if (m instanceof Primitive) {
// the caller is a primitive, that doesn't help, we need to skip it and
// find a proper method
m = getNextMethodOnStack();
}
if (m != null && !(m instanceof Primitive)) {
m.propagateLoopCountThroughoutMethodScope(count);
}
}
}