@@ -92,20 +92,12 @@ abstract class TranslatedCoreExpr extends TranslatedExpr {
9292 * then a load.
9393 */
9494 final override predicate producesExprResult ( ) {
95- // Reads need loads
96- not expr instanceof AssignableRead
95+ // If the expr needs a load, its translation does not produce the final value.
96+ not needsLoad ( expr )
9797 or
98- // No load needed for an array access
99- expr .getParent ( ) instanceof ArrayAccess
100- or
101- // No load is needed for `RefTypes` in assignments
102- // Eg. `Object obj = oldObj`;
103- expr .getParent ( ) instanceof Assignment and
104- expr .getType ( ) instanceof RefType
105- or
106- // Since the loads for a crement operation is handled by the
107- // expression itself, we ignore the default load
108- expr .getParent ( ) instanceof MutatorOperation
98+ // If we're supposed to ignore the load on this expression, then this
99+ // expression produces the final value.
100+ ignoreLoad ( expr )
109101 }
110102
111103 /**
@@ -771,16 +763,63 @@ abstract class TranslatedVariableAccess extends TranslatedNonConstantExpr {
771763 result = getTranslatedExpr ( expr .( QualifiableExpr ) .getQualifier ( ) )
772764 }
773765
774- override Instruction getResult ( ) { result = this .getInstruction ( OnlyInstructionTag ( ) ) }
766+ override Instruction getResult ( ) {
767+ if this .needsExtraLoad ( )
768+ then result = this .getInstruction ( LoadTag ( ) )
769+ else result = this .getInstruction ( AddressTag ( ) )
770+ }
771+
772+ override predicate hasInstruction (
773+ Opcode opcode , InstructionTag tag , Type resultType , boolean isLValue
774+ ) {
775+ this .needsExtraLoad ( ) and
776+ tag = LoadTag ( ) and
777+ opcode instanceof Opcode:: Load and
778+ resultType = this .getResultType ( ) and
779+ isLValue = false
780+ }
775781
776782 final override Instruction getInstructionSuccessor ( InstructionTag tag , EdgeKind kind ) {
777- tag = OnlyInstructionTag ( ) and
778- result = this .getParent ( ) .getChildSuccessor ( this ) and
783+ tag = AddressTag ( ) and
784+ (
785+ if this .needsExtraLoad ( )
786+ then result = this .getInstruction ( LoadTag ( ) )
787+ else result = this .getParent ( ) .getChildSuccessor ( this )
788+ ) and
779789 kind instanceof GotoEdge
790+ or
791+ this .needsExtraLoad ( ) and
792+ tag = LoadTag ( ) and
793+ kind instanceof GotoEdge and
794+ result = this .getParent ( ) .getChildSuccessor ( this )
795+ }
796+
797+ override Instruction getInstructionOperand ( InstructionTag tag , OperandTag operandTag ) {
798+ this .needsExtraLoad ( ) and
799+ tag = LoadTag ( ) and
800+ (
801+ operandTag instanceof AddressOperandTag and
802+ result = this .getInstruction ( AddressTag ( ) )
803+ or
804+ operandTag instanceof LoadOperandTag and
805+ result = this .getEnclosingFunction ( ) .getUnmodeledDefinitionInstruction ( )
806+ )
780807 }
781808
782809 final override Instruction getChildSuccessor ( TranslatedElement child ) {
783- child = this .getQualifier ( ) and result = this .getInstruction ( OnlyInstructionTag ( ) )
810+ child = this .getQualifier ( ) and result = this .getInstruction ( AddressTag ( ) )
811+ }
812+
813+ /**
814+ * Some variable accesses need an extra load, eg. ref parameters,
815+ * out parameters
816+ */
817+ final predicate needsExtraLoad ( ) {
818+ (
819+ expr .getTarget ( ) .( Parameter ) .isOutOrRef ( ) or
820+ expr .getTarget ( ) .( Parameter ) .isIn ( )
821+ ) and
822+ ( expr .getParent ( ) instanceof FieldAccess implies expr .getType ( ) .isRefType ( ) )
784823 }
785824}
786825
@@ -801,22 +840,26 @@ class TranslatedNonFieldVariableAccess extends TranslatedVariableAccess {
801840 override Instruction getFirstInstruction ( ) {
802841 if exists ( this .getQualifier ( ) )
803842 then result = this .getQualifier ( ) .getFirstInstruction ( )
804- else result = this .getInstruction ( OnlyInstructionTag ( ) )
843+ else result = this .getInstruction ( AddressTag ( ) )
805844 }
806845
807- override Instruction getInstructionOperand ( InstructionTag tag , OperandTag operandTag ) { none ( ) }
846+ override Instruction getInstructionOperand ( InstructionTag tag , OperandTag operandTag ) {
847+ result = TranslatedVariableAccess .super .getInstructionOperand ( tag , operandTag )
848+ }
808849
809850 override predicate hasInstruction (
810851 Opcode opcode , InstructionTag tag , Type resultType , boolean isLValue
811852 ) {
812- tag = OnlyInstructionTag ( ) and
853+ TranslatedVariableAccess .super .hasInstruction ( opcode , tag , resultType , isLValue )
854+ or
855+ tag = AddressTag ( ) and
813856 opcode instanceof Opcode:: VariableAddress and
814857 resultType = this .getResultType ( ) and
815858 isLValue = true
816859 }
817860
818861 override IRVariable getInstructionVariable ( InstructionTag tag ) {
819- tag = OnlyInstructionTag ( ) and
862+ tag = AddressTag ( ) and
820863 result = getIRUserVariable ( expr .getEnclosingCallable ( ) , expr .getTarget ( ) )
821864 }
822865}
@@ -831,11 +874,13 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
831874 else
832875 // it means that the access is part of an `ObjectInitializer` expression
833876 // so the instructions for the qualifier have been generated previously.
834- result = this .getInstruction ( OnlyInstructionTag ( ) )
877+ result = this .getInstruction ( AddressTag ( ) )
835878 }
836879
837880 override Instruction getInstructionOperand ( InstructionTag tag , OperandTag operandTag ) {
838- tag = OnlyInstructionTag ( ) and
881+ result = TranslatedVariableAccess .super .getInstructionOperand ( tag , operandTag )
882+ or
883+ tag = AddressTag ( ) and
839884 operandTag instanceof UnaryOperandTag and
840885 // A normal field access always has a qualifier
841886 if exists ( this .getQualifier ( ) )
@@ -851,14 +896,14 @@ class TranslatedFieldAccess extends TranslatedVariableAccess {
851896 override predicate hasInstruction (
852897 Opcode opcode , InstructionTag tag , Type resultType , boolean isLValue
853898 ) {
854- tag = OnlyInstructionTag ( ) and
899+ tag = AddressTag ( ) and
855900 opcode instanceof Opcode:: FieldAddress and
856901 resultType = this .getResultType ( ) and
857902 isLValue = true
858903 }
859904
860905 override Field getInstructionField ( InstructionTag tag ) {
861- tag = OnlyInstructionTag ( ) and
906+ tag = AddressTag ( ) and
862907 result = expr .getTarget ( )
863908 }
864909}
@@ -1992,35 +2037,75 @@ abstract class TranslatedCreation extends TranslatedCoreExpr, TTranslatedCreatio
19922037 opcode instanceof Opcode:: NewObj and
19932038 resultType = expr .getType ( ) and
19942039 isLValue = false
2040+ or
2041+ this .needsLoad ( ) and
2042+ tag = LoadTag ( ) and
2043+ opcode instanceof Opcode:: Load and
2044+ resultType = expr .getType ( ) and
2045+ isLValue = false
19952046 }
19962047
19972048 final override Instruction getFirstInstruction ( ) { result = this .getInstruction ( NewObjTag ( ) ) }
19982049
1999- override Instruction getResult ( ) { result = getInstruction ( NewObjTag ( ) ) }
2050+ override Instruction getResult ( ) {
2051+ if not this .needsLoad ( )
2052+ then result = this .getInstruction ( NewObjTag ( ) )
2053+ else result = this .getInstruction ( LoadTag ( ) )
2054+ }
20002055
20012056 override Instruction getReceiver ( ) { result = getInstruction ( NewObjTag ( ) ) }
20022057
20032058 override Instruction getInstructionSuccessor ( InstructionTag tag , EdgeKind kind ) {
20042059 kind instanceof GotoEdge and
20052060 tag = NewObjTag ( ) and
20062061 result = this .getConstructorCall ( ) .getFirstInstruction ( )
2062+ or
2063+ this .needsLoad ( ) and
2064+ kind instanceof GotoEdge and
2065+ tag = LoadTag ( ) and
2066+ result = this .getParent ( ) .getChildSuccessor ( this )
2067+ }
2068+
2069+ override Instruction getInstructionOperand ( InstructionTag tag , OperandTag operandTag ) {
2070+ this .needsLoad ( ) and
2071+ tag = LoadTag ( ) and
2072+ (
2073+ operandTag instanceof AddressOperandTag and
2074+ result = this .getInstruction ( NewObjTag ( ) )
2075+ or
2076+ operandTag instanceof LoadOperandTag and
2077+ result = this .getEnclosingFunction ( ) .getUnmodeledDefinitionInstruction ( )
2078+ )
20072079 }
20082080
20092081 override Instruction getChildSuccessor ( TranslatedElement child ) {
20102082 (
20112083 child = this .getConstructorCall ( ) and
20122084 if exists ( this .getInitializerExpr ( ) )
20132085 then result = this .getInitializerExpr ( ) .getFirstInstruction ( )
2014- else result = this . getParent ( ) . getChildSuccessor ( this )
2086+ else result = getLoadOrChildSuccessor ( )
20152087 )
20162088 or
20172089 child = this .getInitializerExpr ( ) and
2018- result = this .getParent ( ) .getChildSuccessor ( this )
2090+ result = getLoadOrChildSuccessor ( )
2091+ }
2092+
2093+ private Instruction getLoadOrChildSuccessor ( ) {
2094+ if not this .needsLoad ( )
2095+ then result = this .getParent ( ) .getChildSuccessor ( this )
2096+ else result = this .getInstruction ( LoadTag ( ) )
20192097 }
20202098
20212099 abstract TranslatedElement getConstructorCall ( ) ;
20222100
20232101 abstract TranslatedExpr getInitializerExpr ( ) ;
2102+
2103+ /**
2104+ * If the newly allocated object is a value type, then we need
2105+ * to load the newly allocated object before storing it in the variable,
2106+ * since `NewObj` returns an address.
2107+ */
2108+ abstract predicate needsLoad ( ) ;
20242109}
20252110
20262111/**
@@ -2037,6 +2122,8 @@ class TranslatedObjectCreation extends TranslatedCreation {
20372122 // also return `this`).
20382123 result .getAST ( ) = this .getAST ( )
20392124 }
2125+
2126+ override predicate needsLoad ( ) { expr .getObjectType ( ) .isValueType ( ) }
20402127}
20412128
20422129/**
@@ -2050,4 +2137,6 @@ class TranslatedDelegateCreation extends TranslatedCreation {
20502137 override TranslatedElement getConstructorCall ( ) {
20512138 result = DelegateElements:: getConstructor ( expr )
20522139 }
2140+
2141+ override predicate needsLoad ( ) { none ( ) }
20532142}
0 commit comments