@@ -26,15 +26,15 @@ ArrayType getArrayOfDim(int dim, Type type) {
2626}
2727
2828private predicate canCreateCompilerGeneratedElement ( Element generatedBy , int nth ) {
29- generatedBy instanceof ForeachStmt and nth in [ 0 .. ForeachElements:: noGeneratedElements ( ) ]
29+ generatedBy instanceof ForeachStmt and nth in [ 0 .. ForeachElements:: noGeneratedElements ( ) - 1 ]
3030 or
31- generatedBy instanceof LockStmt and nth in [ 0 .. LockElements:: noGeneratedElements ( ) ]
31+ generatedBy instanceof LockStmt and nth in [ 0 .. LockElements:: noGeneratedElements ( ) - 1 ]
3232 or
3333 generatedBy instanceof DelegateCreation and
34- nth in [ 0 .. DelegateElements:: noGeneratedElements ( generatedBy ) ]
34+ nth in [ 0 .. DelegateElements:: noGeneratedElements ( generatedBy ) - 1 ]
3535 or
3636 generatedBy instanceof DelegateCall and
37- nth in [ 0 .. DelegateElements:: noGeneratedElements ( generatedBy ) ]
37+ nth in [ 0 .. DelegateElements:: noGeneratedElements ( generatedBy ) - 1 ]
3838}
3939
4040/**
@@ -75,7 +75,12 @@ private predicate ignoreExprAndDescendants(Expr expr) {
7575 expr instanceof LocalVariableDeclExpr and
7676 expr .getParent ( ) instanceof ForeachStmt
7777 or
78- ignoreExprAndDescendants ( getRealParent ( expr ) ) // recursive case
78+ // recursive case
79+ ignoreExprAndDescendants ( getRealParent ( expr ) ) and
80+ // The two children of an `AssignOperation` should not be ignored, but since they are also
81+ // descendants of an orphan node (the expanded form of the `AssignOperation` is also retrieved by
82+ // the extractor, which is rooted in an AST node without parents) they would be
83+ not expr .getParent ( ) instanceof AssignOperation
7984}
8085
8186/**
@@ -167,6 +172,63 @@ private predicate usedAsCondition(Expr expr) {
167172 )
168173}
169174
175+ /**
176+ * Holds if we should have a `Load` instruction for `expr` when generating the IR.
177+ */
178+ private predicate mayNeedLoad ( Expr expr ) {
179+ expr instanceof AssignableRead
180+ or
181+ // We need an extra load for the `PointerIndirectionExpr`
182+ expr instanceof PointerIndirectionExpr and
183+ // If the dereferencing happens on the lhs of an
184+ // assignment we shouldn't have a load instruction
185+ not exists ( Assignment a | a .getLValue ( ) = expr )
186+ }
187+
188+ predicate needsLoad ( Expr expr ) {
189+ mayNeedLoad ( expr ) and
190+ not ignoreLoad ( expr )
191+ }
192+
193+ /**
194+ * Holds if we should ignore the `Load` instruction for `expr` when generating IR.
195+ */
196+ private predicate ignoreLoad ( Expr expr ) {
197+ // No load needed for the qualifier
198+ // in an array access
199+ expr = any ( ArrayAccess aa ) .getQualifier ( )
200+ or
201+ // No load is needed for the lvalue in an assignment such as:
202+ // Eg. `Object obj = oldObj`;
203+ expr = any ( Assignment a ) .getLValue ( ) and
204+ expr .getType ( ) instanceof RefType
205+ or
206+ // Since the loads for a crement operation is handled by the translation
207+ // of the operation, we ignore the load here
208+ expr .getParent ( ) instanceof MutatorOperation
209+ or
210+ // The `&` operator does not need a load, since the
211+ // address is the final value of the expression
212+ expr .getParent ( ) instanceof AddressOfExpr
213+ or
214+ // If expr is a variable access used as the qualifier for a field access and
215+ // its target variable is a value type variable,
216+ // ignore the load since the address of a variable that is a value type is
217+ // given by a single `VariableAddress` instruction.
218+ expr = any ( FieldAccess fa ) .getQualifier ( ) and
219+ expr = any ( VariableAccess va |
220+ va .getType ( ) .isValueType ( ) and
221+ not va .getTarget ( ) = any ( Parameter p | p .isOutOrRef ( ) or p .isIn ( ) )
222+ )
223+ or
224+ // If expr is passed as an `out,`ref` or `in` argument,
225+ // no load should take place since we pass the address, not the
226+ // value of the variable
227+ expr .( AssignableAccess ) .isOutOrRefArgument ( )
228+ or
229+ expr .( AssignableAccess ) .isInArgument ( )
230+ }
231+
170232newtype TTranslatedElement =
171233 // An expression that is not being consumed as a condition
172234 TTranslatedValueExpr ( Expr expr ) {
@@ -182,17 +244,8 @@ newtype TTranslatedElement =
182244 // A separate element to handle the lvalue-to-rvalue conversion step of an
183245 // expression.
184246 TTranslatedLoad ( Expr expr ) {
185- // TODO: Revisit and make sure Loads are only used when needed
186247 not ignoreExpr ( expr ) and
187- expr instanceof AssignableRead and
188- not expr .getParent ( ) instanceof ArrayAccess and
189- not (
190- expr .getParent ( ) instanceof Assignment and
191- expr .getType ( ) instanceof RefType
192- ) and
193- // Ignore loads for reads in `++` and `--` since their
194- // translated elements handle them
195- not expr .getParent ( ) instanceof MutatorOperation
248+ needsLoad ( expr )
196249 } or
197250 // An expression most naturally translated as control flow.
198251 TTranslatedNativeCondition ( Expr expr ) {
@@ -250,15 +303,6 @@ newtype TTranslatedElement =
250303 not ignoreExpr ( initList ) and
251304 exists ( initList .getElement ( elementIndex ) )
252305 } or
253- // The value initialization of a range of array elements that were omitted
254- // from an initializer list.
255- TTranslatedElementValueInitialization (
256- ArrayInitializer initList , int elementIndex , int elementCount
257- ) {
258- not ignoreExpr ( initList ) and
259- isFirstValueInitializedElementInRange ( initList , elementIndex ) and
260- elementCount = getEndOfValueInitializedRange ( initList , elementIndex ) - elementIndex
261- } or
262306 // The initialization of a base class from within a constructor.
263307 TTranslatedConstructorInitializer ( ConstructorInitializer init ) { not ignoreExpr ( init ) } or
264308 // A statement
@@ -284,47 +328,6 @@ newtype TTranslatedElement =
284328 canCreateCompilerGeneratedElement ( generatedBy , index )
285329 }
286330
287- /**
288- * Gets the index of the first explicitly initialized element in `initList`
289- * whose index is greater than `afterElementIndex`, where `afterElementIndex`
290- * is a first value-initialized element in a value-initialized range in
291- * `initList`. If there are no remaining explicitly initialized elements in
292- * `initList`, the result is the total number of elements in the array being
293- * initialized.
294- */
295- private int getEndOfValueInitializedRange ( ArrayInitializer initList , int afterElementIndex ) {
296- result = getNextExplicitlyInitializedElementAfter ( initList , afterElementIndex )
297- or
298- isFirstValueInitializedElementInRange ( initList , afterElementIndex ) and
299- not exists ( getNextExplicitlyInitializedElementAfter ( initList , afterElementIndex ) ) and
300- result = initList .getNumberOfElements ( )
301- }
302-
303- /**
304- * Gets the index of the first explicitly initialized element in `initList`
305- * whose index is greater than `afterElementIndex`, where `afterElementIndex`
306- * is a first value-initialized element in a value-initialized range in
307- * `initList`.
308- */
309- private int getNextExplicitlyInitializedElementAfter (
310- ArrayInitializer initList , int afterElementIndex
311- ) {
312- isFirstValueInitializedElementInRange ( initList , afterElementIndex ) and
313- result = min ( int i | exists ( initList .getElement ( i ) ) and i > afterElementIndex )
314- }
315-
316- /**
317- * Holds if element `elementIndex` is the first value-initialized element in a
318- * range of one or more consecutive value-initialized elements in `initList`.
319- */
320- private predicate isFirstValueInitializedElementInRange ( ArrayInitWithMod initList , int elementIndex ) {
321- initList .isValueInitialized ( elementIndex ) and
322- (
323- elementIndex = 0 or
324- not initList .isValueInitialized ( elementIndex - 1 )
325- )
326- }
327-
328331/**
329332 * Represents an AST node for which IR needs to be generated.
330333 *
0 commit comments