-
Notifications
You must be signed in to change notification settings - Fork 30
/
OuterObjectRead.java
310 lines (261 loc) · 10.5 KB
/
OuterObjectRead.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
package som.interpreter.nodes;
import java.math.BigInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.profiles.ValueProfile;
import som.compiler.MixinBuilder.MixinDefinitionId;
import som.interpreter.actors.SFarReference;
import som.interpreter.nodes.nary.ExprWithTagsNode;
import som.interpreter.objectstorage.ClassFactory;
import som.interpreter.processes.SChannel;
import som.interpreter.processes.SChannel.SChannelInput;
import som.interpreter.processes.SChannel.SChannelOutput;
import som.primitives.actors.ActorClasses;
import som.primitives.processes.ChannelPrimitives;
import som.primitives.threading.TaskThreads.SomForkJoinTask;
import som.primitives.threading.TaskThreads.SomThreadTask;
import som.primitives.threading.ThreadingModule;
import som.vm.VmSettings;
import som.vm.constants.KernelObj;
import som.vmobjects.SArray;
import som.vmobjects.SBlock;
import som.vmobjects.SClass;
import som.vmobjects.SObjectWithClass;
import som.vmobjects.SSymbol;
/**
* The OuterObjectRead is responsible for obtaining the object enclosing the current one.
*
* <p>
* Two mixin identities define the lexical elements with respect to which the outer object read
* should be performed. Outer reads are lexically scoped, thus, they refer to the outer object
* of to the class that surrounds the read in the source code.
* The outer class of {@code self} can be different, because self might be a subclass
* of the class an which the method with this outer read is defined.
*
* <p>
* To find the relevant class/superclass of {@code self}, we use the {@code mixinId}.
* {@code enclosingMixinId} describes the lexical class of the object that we wish to find.
*/
@ImportStatic({ActorClasses.class, ThreadingModule.class,
ChannelPrimitives.class})
@NodeChild(value = "receiver", type = ExpressionNode.class)
public abstract class OuterObjectRead
extends ExprWithTagsNode implements ISpecialSend {
protected static final int INLINE_CACHE_SIZE = VmSettings.DYNAMIC_METRICS ? 100 : 3;
/**
* Mixin id for {@code self} (the receiver) or of one its superclasses.
*/
protected final MixinDefinitionId mixinId;
/**
* The identity of the lexical class that we want to find, which
* encloses either {@code self} or one of its superclasses. {@code mixinId} is used
* to distinguish the two where necessary.
*/
private final MixinDefinitionId enclosingMixinId;
private final ValueProfile enclosingObj;
public OuterObjectRead(final MixinDefinitionId mixinId,
final MixinDefinitionId enclosingMixinId) {
this.mixinId = mixinId;
this.enclosingMixinId = enclosingMixinId;
this.enclosingObj = ValueProfile.createIdentityProfile();
}
public MixinDefinitionId getMixinId() {
return mixinId;
}
@Override
public MixinDefinitionId getEnclosingMixinId() {
return enclosingMixinId;
}
@Override
public boolean isSuperSend() {
return false;
}
public abstract ExpressionNode getReceiver();
protected abstract Object executeEvaluated(Object receiver);
public Object computeOuter(final Object receiver) {
ExpressionNode rcvr = getReceiver();
Object current = receiver;
// if we have a chain of outer nodes, we need to traverse it
// otherwise, we are at the point where a ready have the pre-computed receiver
if (rcvr instanceof OuterObjectRead) {
current = ((OuterObjectRead) rcvr).computeOuter(receiver);
}
return executeEvaluated(current);
}
/**
* The enclosing class can be either the class of the given receiver
* or any of its superclasses. The receiver can denote either a class
* or a mixin and, consequently, we need to check both the inheritance
* chain and any mixins applied to that class (or one of its superclasses).
* The class and its superclasses are queried first, and if no
* class was found then all mixins applied along the inheritance chain are
* queried.
*
* Note that this method should always find a class for the given receiver
* and that the return value must be either the receiver's class or one its
* superclasses (and not the class of a mixin).
*/
protected final SClass getEnclosingClass(final SObjectWithClass rcvr) {
SClass rcvrClass = rcvr.getSOMClass();
SClass lexicalClass = rcvrClass.lookupClass(mixinId);
if (lexicalClass == null) {
lexicalClass = rcvrClass.lookupClassWithMixinApplied(mixinId);
}
assert lexicalClass != null;
return lexicalClass;
}
private Object getEnclosingObject(final SClass lexicalClass) {
SObjectWithClass enclosing = lexicalClass.getEnclosingObject();
return enclosingObj.profile(enclosing);
}
protected static final SClass getEnclosingClassWithPotentialFailure(
final SObjectWithClass rcvr, final int superclassIdx) {
SClass lexicalClass = rcvr.getSOMClass().lookupClass(superclassIdx);
return lexicalClass;
}
@Specialization(limit = "INLINE_CACHE_SIZE",
guards = {"receiver.getSOMClass() == rcvrClass"})
public final Object doForFurtherOuter(final SObjectWithClass receiver,
@Cached("receiver.getSOMClass()") final SClass rcvrClass,
@Cached("getEnclosingClass(receiver)") final SClass lexicalClass) {
return getEnclosingObject(lexicalClass);
}
protected final int getIdx(final SObjectWithClass rcvr) {
return rcvr.getSOMClass().getIdxForClassCorrespondingTo(mixinId);
}
protected boolean isSameEnclosingGroup(final SObjectWithClass receiver,
final int superclassIdx, final ClassFactory factory) {
SClass current = getEnclosingClassWithPotentialFailure(receiver, superclassIdx);
if (current == null) {
return false;
}
return current.getInstanceFactory() == factory;
}
@Specialization(guards = {"isSameEnclosingGroup(receiver, superclassIdx, factory)"},
replaces = "doForFurtherOuter")
public final Object fixedLookup(final SObjectWithClass receiver,
@Cached("getIdx(receiver)") final int superclassIdx,
@Cached("getEnclosingClass(receiver).getInstanceFactory()") final ClassFactory factory) {
assert factory != null;
return getEnclosingObject(getEnclosingClassWithPotentialFailure(receiver, superclassIdx));
}
@Specialization(replaces = "fixedLookup")
public final Object fallback(final SObjectWithClass receiver) {
return getEnclosingObject(getEnclosingClass(receiver));
}
/**
* Need to get the outer scope for FarReference, while in the Actors module.
*/
@Specialization(guards = {"mixinId == FarRefId"})
public Object doFarReferenceInActorModuleScope(final SFarReference receiver) {
assert ActorClasses.ActorModule != null;
return ActorClasses.ActorModule;
}
/**
* Need to get the outer scope for FarReference, but it is not the actors module.
* Since there are only super classes in Kernel, we know it is going to be the Kernel.
*/
@Specialization(guards = {"mixinId != FarRefId"})
public Object doFarReferenceInKernelModuleScope(final SFarReference receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doBool(final boolean receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doLong(final long receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doString(final String receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doBigInteger(final BigInteger receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doDouble(final double receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doSSymbol(final SSymbol receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doSArray(final SArray receiver) {
return KernelObj.kernel;
}
@Specialization
public Object doSBlock(final SBlock receiver) {
return KernelObj.kernel;
}
@Specialization(guards = {"mixinId == ThreadClassId"})
public Object doThread(final SomThreadTask receiver) {
assert ThreadingModule.ThreadingModule != null;
return ThreadingModule.ThreadingModule;
}
@Specialization(guards = {"mixinId == ConditionClassId"})
public Object doCondition(final Condition receiver) {
assert ThreadingModule.ThreadingModule != null;
return ThreadingModule.ThreadingModule;
}
@Specialization(guards = {"mixinId == MutexClassId"})
public Object doMutex(final ReentrantLock receiver) {
assert ThreadingModule.ThreadingModule != null;
return ThreadingModule.ThreadingModule;
}
@Specialization(guards = {"mixinId == TaskClassId"})
public Object doTask(final SomForkJoinTask receiver) {
assert ThreadingModule.ThreadingModule != null;
return ThreadingModule.ThreadingModule;
}
@Specialization(guards = {"mixinId == ChannelId"})
public Object doChannel(final SChannel receiver) {
assert ChannelPrimitives.ProcessesModule != null;
return ChannelPrimitives.ProcessesModule;
}
@Specialization(guards = {"mixinId == InId"})
public Object doChannel(final SChannelInput receiver) {
assert ChannelPrimitives.ProcessesModule != null;
return ChannelPrimitives.ProcessesModule;
}
@Specialization(guards = {"mixinId == OutId"})
public Object doChannel(final SChannelOutput receiver) {
assert ChannelPrimitives.ProcessesModule != null;
return ChannelPrimitives.ProcessesModule;
}
@Specialization(guards = {"mixinId != ThreadClassId"})
public Object doThreadInKernelScope(final SomThreadTask receiver) {
return KernelObj.kernel;
}
@Specialization(guards = {"mixinId != ConditionClassId"})
public Object doConditionInKernelScope(final Condition receiver) {
return KernelObj.kernel;
}
@Specialization(guards = {"mixinId != MutexClassId"})
public Object doMutexInKernelScope(final ReentrantLock receiver) {
return KernelObj.kernel;
}
@Specialization(guards = {"mixinId != TaskClassId"})
public Object doTaskInKernelScope(final SomForkJoinTask receiver) {
return KernelObj.kernel;
}
@Specialization(guards = {"mixinId != ChannelId"})
public Object doChannelInKernelScope(final SChannel receiver) {
return KernelObj.kernel;
}
@Specialization(guards = {"mixinId != InId"})
public Object doChannelInKernelScope(final SChannelInput receiver) {
return KernelObj.kernel;
}
@Specialization(guards = {"mixinId != OutId"})
public Object doChannelInKernelScope(final SChannelOutput receiver) {
return KernelObj.kernel;
}
}