Skip to content

Commit 331707f

Browse files
author
AndreiDiaconu1
committed
Framework for the translation of compiler elements
Added a framework for the translation of compiler generated elements, so that the process of adding a new desugaring process is almost mechanical. The files in `internal` serve as the superclasses for all the compiler generated elements. The file `Common.qll` captures common patterns for the compiler generated code to improve code sharing (by pattern I mean an element that appears in multiple desugarings). For example the `try...finally` pattern appears in the desugaring process of both the `lock` and the `foreach` stmts, so a class the provides a blueprint for this pattern is exposed. Several other patterns are present. The expected output has also been updated (after a rebase) and it should be ignored.
1 parent 80b7512 commit 331707f

File tree

7 files changed

+484
-0
lines changed

7 files changed

+484
-0
lines changed
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
/**
2+
* Exposes several patterns for the compiler generated code, so as to improve code sharing between files that
3+
* deal with the desugaring process.
4+
* For example, we expose the `try ... finally` pattern, which is shared by the desugaring of both the
5+
* `ForeachStmt`, `UsingStmt` and `LockStmt`.
6+
*/
7+
8+
import csharp
9+
10+
private import semmle.code.csharp.ir.implementation.Opcode
11+
private import semmle.code.csharp.ir.implementation.internal.OperandTag
12+
private import semmle.code.csharp.ir.internal.TempVariableTag
13+
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
14+
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction
15+
private import semmle.code.csharp.ir.implementation.raw.internal.InstructionTag
16+
17+
private import internal.TranslatedCompilerGeneratedStmt
18+
private import internal.TranslatedCompilerGeneratedExpr
19+
private import internal.TranslatedCompilerGeneratedCondition
20+
private import internal.TranslatedCompilerGeneratedCall
21+
private import internal.TranslatedCompilerGeneratedElement
22+
private import internal.TranslatedCompilerGeneratedDeclaration
23+
24+
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBlueprint
25+
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedExprBlueprint
26+
27+
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
28+
29+
30+
/**
31+
* The general form of a compiler generated try stmt.
32+
* The concrete implementation needs to specify the body of the try and the
33+
* finally block.
34+
*/
35+
abstract class TranslatedCompilerGeneratedTry extends TranslatedCompilerGeneratedStmt {
36+
override Stmt generatedBy;
37+
38+
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
39+
Type resultType, boolean isLValue) {
40+
none()
41+
}
42+
43+
override Instruction getInstructionSuccessor(InstructionTag tag,
44+
EdgeKind kind) {
45+
none()
46+
}
47+
48+
override TranslatedElement getChild(int id) {
49+
id = 0 and result = getBody() or
50+
id = 1 and result = getFinally()
51+
}
52+
53+
override Instruction getFirstInstruction() {
54+
result = getBody().getFirstInstruction()
55+
}
56+
57+
override Instruction getChildSuccessor(TranslatedElement child) {
58+
child = getBody() and result = getFinally().getFirstInstruction() or
59+
child = getFinally() and result = getParent().getChildSuccessor(this)
60+
}
61+
62+
override Instruction getExceptionSuccessorInstruction() {
63+
result = getParent().getExceptionSuccessorInstruction()
64+
}
65+
66+
/**
67+
* Gets the finally block.
68+
*/
69+
abstract TranslatedElement getFinally();
70+
71+
/**
72+
* Gets the body of the try stmt.
73+
*/
74+
abstract TranslatedElement getBody();
75+
}
76+
77+
/**
78+
* The general form of a compiler generated constant expression.
79+
* The concrete implementation needs to specify the immediate operand that represents the constant.
80+
*/
81+
abstract class TranslatedCompilerGeneratedConstant extends TranslatedCompilerGeneratedExpr {
82+
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
83+
Type resultType, boolean isLValue) {
84+
opcode instanceof Opcode::Constant and
85+
tag = OnlyInstructionTag() and
86+
resultType = getResultType() and
87+
isLValue = false
88+
}
89+
90+
override Instruction getInstructionSuccessor(InstructionTag tag,
91+
EdgeKind kind) {
92+
tag = OnlyInstructionTag() and
93+
kind instanceof GotoEdge and
94+
result = getParent().getChildSuccessor(this)
95+
}
96+
97+
override Instruction getFirstInstruction() {
98+
result = getInstruction(OnlyInstructionTag())
99+
}
100+
101+
override TranslatedElement getChild(int id) {
102+
none()
103+
}
104+
105+
override Instruction getChildSuccessor(TranslatedElement child) {
106+
none()
107+
}
108+
}
109+
110+
/**
111+
* The general form of a compiler generated block stmt.
112+
* The concrete implementation needs to specify the statements that
113+
* compose the block.
114+
*/
115+
abstract class TranslatedCompilerGeneratedBlock extends TranslatedCompilerGeneratedStmt {
116+
override TranslatedElement getChild(int id) {
117+
result = getStmt(id)
118+
}
119+
120+
override Instruction getFirstInstruction() {
121+
result = getStmt(0).getFirstInstruction()
122+
}
123+
124+
abstract TranslatedElement getStmt(int index);
125+
126+
private int getStmtCount() {
127+
result = count(getStmt(_))
128+
}
129+
130+
override Instruction getChildSuccessor(TranslatedElement child) {
131+
exists(int index |
132+
child = getStmt(index) and
133+
if index = (getStmtCount() - 1) then
134+
result = getParent().getChildSuccessor(this)
135+
else
136+
result = getStmt(index + 1).getFirstInstruction()
137+
)
138+
}
139+
140+
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
141+
Type resultType, boolean isLValue) {
142+
none()
143+
}
144+
145+
override Instruction getInstructionSuccessor(InstructionTag tag,
146+
EdgeKind kind) {
147+
none()
148+
}
149+
}
150+
151+
/**
152+
* The general form of a compiler generated if stmt.
153+
* The concrete implementation needs to specify the condition,
154+
* the body of the `then` and the body of the `else`.
155+
*/
156+
abstract class TranslatedCompilerGeneratedIfStmt extends TranslatedCompilerGeneratedStmt,
157+
ConditionContext {
158+
override Instruction getFirstInstruction() {
159+
result = getCondition().getFirstInstruction()
160+
}
161+
162+
override TranslatedElement getChild(int id) {
163+
id = 0 and result = getCondition() or
164+
id = 1 and result = getThen() or
165+
id = 2 and result = getElse()
166+
}
167+
168+
abstract TranslatedCompilerGeneratedValueCondition getCondition();
169+
170+
abstract TranslatedCompilerGeneratedElement getThen();
171+
172+
abstract TranslatedCompilerGeneratedElement getElse();
173+
174+
private predicate hasElse() {
175+
exists(getElse())
176+
}
177+
178+
override Instruction getInstructionSuccessor(InstructionTag tag,
179+
EdgeKind kind) {
180+
none()
181+
}
182+
183+
override Instruction getChildTrueSuccessor(ConditionBlueprint child) {
184+
child = getCondition() and
185+
result = getThen().getFirstInstruction()
186+
}
187+
188+
override Instruction getChildFalseSuccessor(ConditionBlueprint child) {
189+
child = getCondition() and
190+
if hasElse() then
191+
result = getElse().getFirstInstruction()
192+
else
193+
result = getParent().getChildSuccessor(this)
194+
}
195+
196+
override Instruction getChildSuccessor(TranslatedElement child) {
197+
(child = getThen() or child = getElse()) and
198+
result = getParent().getChildSuccessor(this)
199+
}
200+
201+
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
202+
Type resultType, boolean isLValue) {
203+
none()
204+
}
205+
}
206+
207+
/**
208+
* The general form of a compiler generated variable access.
209+
* The concrete implementation needs to specify the immediate
210+
* operand for the `VariableAddress` instruction and if the
211+
* access needs a `Load` instruction or not (eg. `ref` params do not)
212+
*/
213+
abstract class TranslatedCompilerGeneratedVariableAccess extends TranslatedCompilerGeneratedExpr {
214+
override Instruction getFirstInstruction() {
215+
result = getInstruction(AddressTag())
216+
}
217+
218+
override TranslatedElement getChild(int id) {
219+
none()
220+
}
221+
222+
override Instruction getChildSuccessor(TranslatedElement child) {
223+
none()
224+
}
225+
226+
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
227+
Type resultType, boolean isLValue) {
228+
(
229+
tag = AddressTag() and
230+
opcode instanceof Opcode::VariableAddress and
231+
resultType = getResultType() and
232+
isLValue = true
233+
) or
234+
(
235+
needsLoad() and
236+
tag = LoadTag() and
237+
opcode instanceof Opcode::Load and
238+
resultType = getResultType() and
239+
isLValue = false
240+
)
241+
}
242+
243+
override Instruction getInstructionSuccessor(InstructionTag tag,
244+
EdgeKind kind) {
245+
(
246+
needsLoad() and
247+
tag = LoadTag() and
248+
result = getParent().getChildSuccessor(this) and
249+
kind instanceof GotoEdge
250+
) or
251+
(
252+
tag = AddressTag() and
253+
kind instanceof GotoEdge and
254+
if needsLoad() then
255+
result = getInstruction(LoadTag())
256+
else
257+
result = getParent().getChildSuccessor(this)
258+
)
259+
}
260+
261+
override Instruction getResult() {
262+
if needsLoad() then
263+
result = getInstruction(LoadTag())
264+
else
265+
result = getInstruction(AddressTag())
266+
}
267+
268+
override Instruction getInstructionOperand(InstructionTag tag,
269+
OperandTag operandTag) {
270+
needsLoad() and
271+
tag = LoadTag() and
272+
(
273+
(
274+
operandTag instanceof AddressOperandTag and
275+
result = getInstruction(AddressTag())
276+
) or
277+
(
278+
operandTag instanceof LoadOperandTag and
279+
result = getTranslatedFunction(getFunction()).getUnmodeledDefinitionInstruction()
280+
)
281+
)
282+
}
283+
284+
/**
285+
* Holds if the variable access should be followed by a `Load` instruction.
286+
*/
287+
abstract predicate needsLoad();
288+
}
289+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Contains an abstract class that is the super class of the classes that deal with compiler generated calls.
3+
*/
4+
5+
import csharp
6+
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
7+
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedFunction
8+
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedCallBlueprint
9+
private import TranslatedCompilerGeneratedElement
10+
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
11+
12+
abstract class TranslatedCompilerGeneratedCall extends TranslatedCallBlueprint,
13+
TranslatedCompilerGeneratedElement {
14+
override final string toString() {
15+
result = "compiler generated call (" + generatedBy.toString() + ")"
16+
}
17+
18+
override Instruction getUnmodeledDefinitionInstruction() {
19+
result = getTranslatedFunction(this.getFunction()).getUnmodeledDefinitionInstruction()
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Contains an abstract class that is the super class of the classes that deal with compiler generated conditions.
3+
*/
4+
5+
import csharp
6+
private import semmle.code.csharp.ir.implementation.raw.internal.TranslatedElement
7+
private import semmle.code.csharp.ir.implementation.raw.internal.common.TranslatedConditionBlueprint
8+
private import TranslatedCompilerGeneratedElement
9+
private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language
10+
11+
abstract class TranslatedCompilerGeneratedValueCondition extends TranslatedCompilerGeneratedElement,
12+
ValueConditionBlueprint {
13+
override final string toString() {
14+
result = "compiler generated condition (" + generatedBy.toString() + ")"
15+
}
16+
}

0 commit comments

Comments
 (0)