This repository was archived by the owner on Jul 12, 2023. It is now read-only.
forked from polyglot-compiler/JLang
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJLangCallExt.java
237 lines (198 loc) · 9.33 KB
/
JLangCallExt.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
//Copyright (C) 2018 Cornell University
package jlang.extension;
import jlang.ast.JLangExt;
import jlang.extension.JLangTryExt.ExceptionFrame;
import jlang.util.Constants;
import jlang.visit.LLVMTranslator;
import jlang.visit.LLVMTranslator.DispatchInfo;
import org.bytedeco.javacpp.LLVM.*;
import polyglot.ast.Call;
import polyglot.ast.Node;
import polyglot.ast.Special;
import polyglot.types.*;
import polyglot.util.Copy;
import polyglot.util.SerialVersionUID;
import polyglot.visit.TypeChecker;
import java.lang.Override;
import java.util.LinkedHashSet;
import java.util.Set;
import static jlang.extension.JLangSynchronizedExt.buildMonitorFunc;
import static org.bytedeco.javacpp.LLVM.*;
public class JLangCallExt extends JLangProcedureCallExt {
private static final long serialVersionUID = SerialVersionUID.generate();
/**
* Indicates whether this call can be dispatched directly, without using a dispatch table.
* This is set to true to optimize calls when possible, and also to ensure that
* direct calls remain direct after desugar transformations (e.g., qualified super
* can be desugared to field accesses, so the fact that the call is direct is otherwise lost).
*/
private boolean direct = false;
@Override
public Node leaveTranslateLLVM(LLVMTranslator v) {
// Add a placeholder translation marking success for methods that
// return `void`, since all expressions must have some translation.
if (node().methodInstance().returnType().isVoid())
v.addTranslation(node(), new Object());
ProcedureInstance pi = node().procedureInstance();
if (pi.flags().isSynchronized()) {
// Handle synchronization at the caller site.
//
// It will emit the following code:
// try { MonitorEnter(target); target.func(arg1, arg2); }
// finally { MonitorExit(target); }
// Two possible control flows for the following try-finally code:
// - lock -> function call -> unlock -> End
// - lock -> function call with an exception thrown -> landing pad -> unlock -> rethrow exception
// Declare blocks and some useful variables.
LLVMBasicBlockRef lpad = v.utils.buildBlock("lpad");
LLVMBasicBlockRef end = v.utils.buildBlock("end");
LLVMBasicBlockRef lpadOuter = v.currLandingPad();
ExceptionFrame frame = new ExceptionFrame(v, lpad, null);
////////////////////
// Flow 1
////////////////////
LLVMValueRef syncVar;
if (pi.flags().isStatic()) {
assert pi.container().isClass();
v.utils.buildClassLoadCheck(pi.container().toClass());
syncVar = v.utils.loadClassObject(pi.container().toClass());
} else {
syncVar = v.getTranslation(node().target());
}
// Push the exception frame after translating syncVar to make sure we always
// have defined syncVar in all possible paths.
v.pushExceptionFrame(frame);
buildMonitorFunc(v, Constants.MONITOR_ENTER, syncVar);
Node retNode = super.leaveTranslateLLVM(v);
buildMonitorFunc(v, Constants.MONITOR_EXIT, syncVar);
LLVMBuildBr(v.builder, end);
////////////////////
// Landing Pad (Flow 2)
////////////////////
LLVMPositionBuilderAtEnd(v.builder, lpad);
LLVMTypeRef lpadT = v.utils.structType(v.utils.i8Ptr(), v.utils.i32());
LLVMValueRef nullBytePtr = LLVMConstNull(v.utils.i8Ptr());
LLVMValueRef personalityFunc = v.utils.getFunction(
Constants.PERSONALITY_FUNC,
v.utils.functionType(LLVMInt32TypeInContext(v.context)));
LLVMValueRef lpadFinallyRes = LLVMBuildLandingPad(v.builder, lpadT, personalityFunc, 1, "lpad.finally.res");
LLVMAddClause(lpadFinallyRes, nullBytePtr);
LLVMValueRef exception = LLVMBuildExtractValue(v.builder, lpadFinallyRes, 0, "exn");
// Prevent the current exceptionFrame from being used in the future translation.
v.popExceptionFrame();
buildMonitorFunc(v, Constants.MONITOR_EXIT, syncVar);
// Rethrow exception
LLVMValueRef throwExnFunc = v.utils.getFunction(Constants.THROW_EXCEPTION,
v.utils.functionType(LLVMVoidTypeInContext(v.context), v.utils.i8Ptr()));
v.utils.buildProcCall(lpadOuter, throwExnFunc, exception);
LLVMBuildUnreachable(v.builder);
LLVMPositionBuilderAtEnd(v.builder, end);
return retNode;
} else {
// Most of the translation happens here in this call.
return super.leaveTranslateLLVM(v);
}
}
/**
* Sets {@link this#direct} appropriately.
*/
public Call determineIfDirect(Call c) {
JLangCallExt ext = (JLangCallExt) JLangExt.ext(c);
if (ext.direct) return c; // Should always remain direct once set.
boolean direct = false;
// Static, private, and final methods are direct.
Flags methodFlags = c.methodInstance().flags();
if (methodFlags.isStatic() || methodFlags.isPrivate() || methodFlags.isFinal())
direct = true;
// Calls through super are direct.
if (c.target() instanceof Special)
if (((Special) c.target()).kind().equals(Special.SUPER))
direct = true;
// Calls to methods of a final class are direct.
ReferenceType container = c.methodInstance().container();
if (container.isClass() && container.toClass().flags().isFinal())
direct = true;
// Copy and return.
if (!direct) return c;
if (c == node) {
c = Copy.Util.copy(c);
ext = (JLangCallExt) JLangExt.ext(c);
}
ext.direct = true;
return c;
}
@Override
public Node typeCheck(TypeChecker tc) throws SemanticException {
Call c = (Call) super.typeCheck(tc);
return determineIfDirect(c);
}
@Override
protected LLVMValueRef buildFuncPtr(LLVMTranslator v, LLVMTypeRef funcType) {
Call n = node();
MethodInstance mi = n.methodInstance();
if (direct) {
// Direct (static, final, private, etc.) call.
return super.buildFuncPtr(v, funcType);
} else {
ReferenceType recvTy = n.target().type().toReference();
if (recvTy.isClass() && recvTy.toClass().flags().isInterface()) {
// Interface method call.
return buildInterfaceMethodPtr(v, mi, funcType);
} else {
// Class instance method call.
return buildInstanceMethodPtr(v, mi);
}
}
}
protected LLVMValueRef buildInstanceMethodPtr(LLVMTranslator v, MethodInstance mi) {
Call n = node();
LLVMValueRef recv = v.getTranslation(n.target());
ReferenceType recvTy = n.target().type().toReference();
LLVMValueRef cdvPtrPtr = v.obj.buildDispatchVectorElementPtr(recv, recvTy);
LLVMValueRef cdvPtr = LLVMBuildLoad(v.builder, cdvPtrPtr, "load.dv");
LLVMValueRef funcPtrPtr = v.dv.buildFuncElementPtr(cdvPtr, recvTy, mi);
return LLVMBuildLoad(v.builder, funcPtrPtr, "load.dv.method");
}
protected LLVMValueRef buildInterfaceMethodPtr(
LLVMTranslator v, MethodInstance mi, LLVMTypeRef funcType) {
Call n = node();
LLVMValueRef recv = v.getTranslation(n.target());
ReferenceType recvTy = n.target().type().toReference();
DispatchInfo dispInfo = v.dispatchInfo(recvTy, mi);
ClassType intf = dispInfo.intfErasure();
LLVMValueRef intf_id_global = v.classObjs.toTypeIdentity(intf);
LLVMValueRef obj_bitcast = LLVMBuildBitCast(v.builder, recv, v.utils.i8Ptr(), "cast.obj");
int hash = v.utils.intfHash(intf);
LLVMValueRef intf_id_hash_const = LLVMConstInt(
LLVMInt32TypeInContext(v.context), hash,
/* sign-extend */ 0);
LLVMTypeRef get_intf_method_func_ty = v.utils.functionType(
v.utils.i8Ptr(), // void* return type
v.utils.i8Ptr(), // jobject*
LLVMInt32TypeInContext(v.context), // int
v.utils.i8Ptr(), // void*
LLVMInt32TypeInContext(v.context) // int
);
LLVMValueRef get_intf_method_func = v.utils.getFunction(
"__getInterfaceMethod", get_intf_method_func_ty);
LLVMValueRef offset_local = LLVMConstInt(
LLVMInt32TypeInContext(v.context), dispInfo.methodIndex(),
/* sign-extend */ 0);
LLVMValueRef funcPtr = v.utils.buildFunCall(
get_intf_method_func, // ptr to method code
obj_bitcast, // the object
intf_id_hash_const, // id hash code
intf_id_global, // id
offset_local); // method index
LLVMTypeRef funcPtrT = v.utils.ptrTypeRef(funcType);
return LLVMBuildBitCast(v.builder, funcPtr, funcPtrT, "cast.interface.method");
}
@Override
protected LLVMValueRef buildReceiverArg(LLVMTranslator v) {
return v.getTranslation(node().target());
}
@Override
public Call node() {
return (Call) super.node();
}
}