Merge pull request #2017 from AndreiDiaconu1/ircsharp-various

C# IR: Some minor additions
This commit is contained in:
Calum Grant
2019-09-26 15:02:59 +01:00
committed by GitHub
5 changed files with 317 additions and 98 deletions

View File

@@ -99,6 +99,12 @@ private predicate ignoreExprOnly(Expr expr) {
// Ignore the expression (that is not a declaration)
// that appears in a using block
expr.getParent().(UsingBlockStmt).getExpr() = expr
or
// Ignore the `ThisAccess` when it is used as the qualifier for
// a callable access (e.g. when a member callable is passed as a
// parameter for a delegate creation expression)
expr instanceof ThisAccess and
expr.getParent() instanceof CallableAccess
}
/**
@@ -199,6 +205,10 @@ private predicate ignoreLoad(Expr expr) {
// to get the address of the first element in an array
expr = any(ArrayAccess aa).getQualifier()
or
// Indexer calls returns a reference or a value,
// no need to load it
expr instanceof IndexerCall
or
// No load is needed for the lvalue in an assignment such as:
// Eg. `Object obj = oldObj`;
expr = any(Assignment a).getLValue() and

View File

@@ -1382,6 +1382,11 @@ class TranslatedAssignExpr extends TranslatedAssignment {
class TranslatedAssignOperation extends TranslatedAssignment {
override AssignOperation expr;
TranslatedAssignOperation() {
// Assignments to events is handled differently
not expr.getLValue() instanceof EventAccess
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
kind instanceof GotoEdge and
(
@@ -1893,104 +1898,6 @@ class TranslatedIsExpr extends TranslatedNonConstantExpr {
}
}
/**
* The IR translation of a lambda expression. This initializes a temporary variable whose type is that of the lambda,
* using the initializer list that represents the captures of the lambda.
*/
class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationContext {
override LambdaExpr expr;
final override Instruction getFirstInstruction() {
result = this.getInstruction(InitializerVariableAddressTag())
}
final override TranslatedElement getChild(int id) { id = 0 and result = this.getInitialization() }
override Instruction getResult() { result = this.getInstruction(LoadTag()) }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
tag = InitializerVariableAddressTag() and
kind instanceof GotoEdge and
result = this.getInstruction(InitializerStoreTag())
or
tag = InitializerStoreTag() and
kind instanceof GotoEdge and
(
result = this.getInitialization().getFirstInstruction()
or
not this.hasInitializer() and result = this.getInstruction(LoadTag())
)
or
tag = LoadTag() and
kind instanceof GotoEdge and
result = this.getParent().getChildSuccessor(this)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = getInitialization() and
result = this.getInstruction(LoadTag())
}
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
tag = InitializerVariableAddressTag() and
opcode instanceof Opcode::VariableAddress and
resultType = this.getResultType() and
isLValue = true
or
tag = InitializerStoreTag() and
opcode instanceof Opcode::Uninitialized and
resultType = this.getResultType() and
isLValue = false
or
tag = LoadTag() and
opcode instanceof Opcode::Load and
resultType = this.getResultType() and
isLValue = false
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag = InitializerStoreTag() and
operandTag instanceof AddressOperandTag and
result = this.getInstruction(InitializerVariableAddressTag())
or
tag = LoadTag() and
(
operandTag instanceof AddressOperandTag and
result = this.getInstruction(InitializerVariableAddressTag())
or
operandTag instanceof LoadOperandTag and
result = this.getEnclosingFunction().getUnmodeledDefinitionInstruction()
)
}
override IRVariable getInstructionVariable(InstructionTag tag) {
(
tag = InitializerVariableAddressTag() or
tag = InitializerStoreTag()
) and
result = this.getTempVariable(LambdaTempVar())
}
override predicate hasTempVariable(TempVariableTag tag, Type type) {
tag = LambdaTempVar() and
type = this.getResultType()
}
final override Instruction getTargetAddress() {
result = this.getInstruction(InitializerVariableAddressTag())
}
final override Type getTargetType() { result = this.getResultType() }
private predicate hasInitializer() { exists(this.getInitialization()) }
private TranslatedInitialization getInitialization() {
result = getTranslatedInitialization(expr.getChild(0))
}
}
/**
* The translation of a `DelegateCall`. Since this type of call needs
* desugaring, we treat it as a special case. The AST node of the
@@ -2155,3 +2062,37 @@ class TranslatedDelegateCreation extends TranslatedCreation {
override predicate needsLoad() { none() }
}
/**
* Represents the IR translation of an assign operation where the lhs is an event access.
*/
class TranslatedEventAccess extends TranslatedNonConstantExpr {
override AssignOperation expr;
TranslatedEventAccess() { expr.getLValue() instanceof EventAccess }
// We only translate the lhs, since the rhs is translated as part of the
// accessor call.
override TranslatedElement getChild(int id) { id = 0 and result = this.getLValue() }
override predicate hasInstruction(
Opcode opcode, InstructionTag tag, Type resultType, boolean isLValue
) {
none()
}
final override Instruction getFirstInstruction() {
result = this.getLValue().getFirstInstruction()
}
override Instruction getResult() { none() }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getLValue() and
result = this.getParent().getChildSuccessor(this)
}
private TranslatedExpr getLValue() { result = getTranslatedExpr(expr.getLValue()) }
}

View File

@@ -0,0 +1,35 @@
class Events
{
public delegate string MyDel(string str);
public MyDel Inst;
event MyDel MyEvent;
public Events()
{
this.Inst = new MyDel(this.Fun);
}
public void AddEvent()
{
this.MyEvent += this.Inst;
}
public void RemoveEvent()
{
this.MyEvent -= this.Inst;
}
public string Fun(string str)
{
return str;
}
static void Main(string[] args)
{
Events obj = new Events();
obj.AddEvent();
string result = obj.MyEvent("string");
obj.RemoveEvent();
}
}

View File

@@ -0,0 +1,30 @@
class Indexers
{
public class MyClass
{
public MyClass()
{
}
private string[] address = new string[2];
public string this[int index]
{
get
{
return address[index];
}
set
{
address[index] = value;
}
}
}
public static void Main()
{
MyClass inst = new MyClass();
inst[0] = "str1";
inst[1] = "str1";
inst[1] = inst[0];
}
}

View File

@@ -480,6 +480,111 @@ delegates.cs:
# 11| v0_17(Void) = UnmodeledUse : mu*
# 11| v0_18(Void) = ExitFunction :
events.cs:
# 8| System.Void Events..ctor()
# 8| Block 0
# 8| v0_0(Void) = EnterFunction :
# 8| mu0_1(null) = AliasedDefinition :
# 8| mu0_2(null) = UnmodeledDefinition :
# 8| r0_3(glval<Events>) = InitializeThis :
# 10| r0_4(MyDel) = NewObj :
# 10| r0_5(glval<null>) = FunctionAddress[MyDel] :
# 10| r0_6(glval<MyDel>) = FunctionAddress[Fun] :
# 10| v0_7(Void) = Call : func:r0_5, this:r0_4, 0:r0_6
# 10| mu0_8(null) = ^CallSideEffect : ~mu0_2
# 10| r0_9(Events) = CopyValue : r0_3
# 10| r0_10(glval<MyDel>) = FieldAddress[Inst] : r0_9
# 10| mu0_11(MyDel) = Store : &:r0_10, r0_4
# 8| v0_12(Void) = ReturnVoid :
# 8| v0_13(Void) = UnmodeledUse : mu*
# 8| v0_14(Void) = ExitFunction :
# 13| System.Void Events.AddEvent()
# 13| Block 0
# 13| v0_0(Void) = EnterFunction :
# 13| mu0_1(null) = AliasedDefinition :
# 13| mu0_2(null) = UnmodeledDefinition :
# 13| r0_3(glval<Events>) = InitializeThis :
# 15| r0_4(Events) = CopyValue : r0_3
# 15| r0_5(glval<null>) = FunctionAddress[add_MyEvent] :
# 15| r0_6(Events) = CopyValue : r0_3
# 15| r0_7(glval<MyDel>) = FieldAddress[Inst] : r0_6
# 15| r0_8(MyDel) = Load : &:r0_7, ~mu0_2
# 15| v0_9(Void) = Call : func:r0_5, this:r0_4, 0:r0_8
# 15| mu0_10(null) = ^CallSideEffect : ~mu0_2
# 13| v0_11(Void) = ReturnVoid :
# 13| v0_12(Void) = UnmodeledUse : mu*
# 13| v0_13(Void) = ExitFunction :
# 18| System.Void Events.RemoveEvent()
# 18| Block 0
# 18| v0_0(Void) = EnterFunction :
# 18| mu0_1(null) = AliasedDefinition :
# 18| mu0_2(null) = UnmodeledDefinition :
# 18| r0_3(glval<Events>) = InitializeThis :
# 20| r0_4(Events) = CopyValue : r0_3
# 20| r0_5(glval<null>) = FunctionAddress[remove_MyEvent] :
# 20| r0_6(Events) = CopyValue : r0_3
# 20| r0_7(glval<MyDel>) = FieldAddress[Inst] : r0_6
# 20| r0_8(MyDel) = Load : &:r0_7, ~mu0_2
# 20| v0_9(Void) = Call : func:r0_5, this:r0_4, 0:r0_8
# 20| mu0_10(null) = ^CallSideEffect : ~mu0_2
# 18| v0_11(Void) = ReturnVoid :
# 18| v0_12(Void) = UnmodeledUse : mu*
# 18| v0_13(Void) = ExitFunction :
# 23| System.String Events.Fun(System.String)
# 23| Block 0
# 23| v0_0(Void) = EnterFunction :
# 23| mu0_1(null) = AliasedDefinition :
# 23| mu0_2(null) = UnmodeledDefinition :
# 23| r0_3(glval<Events>) = InitializeThis :
# 23| r0_4(glval<String>) = VariableAddress[str] :
# 23| mu0_5(String) = InitializeParameter[str] : &:r0_4
# 25| r0_6(glval<String>) = VariableAddress[#return] :
# 25| r0_7(glval<String>) = VariableAddress[str] :
# 25| r0_8(String) = Load : &:r0_7, ~mu0_2
# 25| mu0_9(String) = Store : &:r0_6, r0_8
# 23| r0_10(glval<String>) = VariableAddress[#return] :
# 23| v0_11(Void) = ReturnValue : &:r0_10, ~mu0_2
# 23| v0_12(Void) = UnmodeledUse : mu*
# 23| v0_13(Void) = ExitFunction :
# 28| System.Void Events.Main(System.String[])
# 28| Block 0
# 28| v0_0(Void) = EnterFunction :
# 28| mu0_1(null) = AliasedDefinition :
# 28| mu0_2(null) = UnmodeledDefinition :
# 28| r0_3(glval<String[]>) = VariableAddress[args] :
# 28| mu0_4(String[]) = InitializeParameter[args] : &:r0_3
# 30| r0_5(glval<Events>) = VariableAddress[obj] :
# 30| r0_6(Events) = NewObj :
# 30| r0_7(glval<null>) = FunctionAddress[Events] :
# 30| v0_8(Void) = Call : func:r0_7, this:r0_6
# 30| mu0_9(null) = ^CallSideEffect : ~mu0_2
# 30| mu0_10(Events) = Store : &:r0_5, r0_6
# 31| r0_11(glval<Events>) = VariableAddress[obj] :
# 31| r0_12(Events) = Load : &:r0_11, ~mu0_2
# 31| r0_13(glval<null>) = FunctionAddress[AddEvent] :
# 31| v0_14(Void) = Call : func:r0_13, this:r0_12
# 31| mu0_15(null) = ^CallSideEffect : ~mu0_2
# 32| r0_16(glval<String>) = VariableAddress[result] :
# 32| r0_17(glval<Events>) = VariableAddress[obj] :
# 32| r0_18(Events) = Load : &:r0_17, ~mu0_2
# 32| r0_19(glval<null>) = FunctionAddress[Invoke] :
# 32| r0_20(String) = StringConstant["string"] :
# 32| v0_21(Void) = Call : func:r0_19, this:r0_18, 0:r0_20
# 32| mu0_22(null) = ^CallSideEffect : ~mu0_2
# 32| mu0_23(String) = Store : &:r0_16, v0_21
# 33| r0_24(glval<Events>) = VariableAddress[obj] :
# 33| r0_25(Events) = Load : &:r0_24, ~mu0_2
# 33| r0_26(glval<null>) = FunctionAddress[RemoveEvent] :
# 33| v0_27(Void) = Call : func:r0_26, this:r0_25
# 33| mu0_28(null) = ^CallSideEffect : ~mu0_2
# 28| v0_29(Void) = ReturnVoid :
# 28| v0_30(Void) = UnmodeledUse : mu*
# 28| v0_31(Void) = ExitFunction :
foreach.cs:
# 4| System.Void ForEach.Main()
# 4| Block 0
@@ -598,6 +703,104 @@ func_with_param_call.cs:
# 10| v0_12(Void) = UnmodeledUse : mu*
# 10| v0_13(Void) = ExitFunction :
indexers.cs:
# 5| System.Void Indexers.MyClass..ctor()
# 5| Block 0
# 5| v0_0(Void) = EnterFunction :
# 5| mu0_1(null) = AliasedDefinition :
# 5| mu0_2(null) = UnmodeledDefinition :
# 5| r0_3(glval<MyClass>) = InitializeThis :
# 6| v0_4(Void) = NoOp :
# 5| v0_5(Void) = ReturnVoid :
# 5| v0_6(Void) = UnmodeledUse : mu*
# 5| v0_7(Void) = ExitFunction :
# 12| System.String Indexers.MyClass.get_Item(System.Int32)
# 12| Block 0
# 12| v0_0(Void) = EnterFunction :
# 12| mu0_1(null) = AliasedDefinition :
# 12| mu0_2(null) = UnmodeledDefinition :
# 12| r0_3(glval<MyClass>) = InitializeThis :
# 10| r0_4(glval<Int32>) = VariableAddress[index] :
# 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4
# 14| r0_6(glval<String>) = VariableAddress[#return] :
# 14| r0_7(MyClass) = CopyValue : r0_3
# 14| r0_8(glval<String[]>) = FieldAddress[address] : r0_7
# 14| r0_9(String[]) = ElementsAddress : r0_8
# 14| r0_10(glval<Int32>) = VariableAddress[index] :
# 14| r0_11(Int32) = Load : &:r0_10, ~mu0_2
# 14| r0_12(String[]) = PointerAdd[8] : r0_9, r0_11
# 14| r0_13(String) = Load : &:r0_12, ~mu0_2
# 14| mu0_14(String) = Store : &:r0_6, r0_13
# 12| r0_15(glval<String>) = VariableAddress[#return] :
# 12| v0_16(Void) = ReturnValue : &:r0_15, ~mu0_2
# 12| v0_17(Void) = UnmodeledUse : mu*
# 12| v0_18(Void) = ExitFunction :
# 16| System.Void Indexers.MyClass.set_Item(System.Int32,System.String)
# 16| Block 0
# 16| v0_0(Void) = EnterFunction :
# 16| mu0_1(null) = AliasedDefinition :
# 16| mu0_2(null) = UnmodeledDefinition :
# 16| r0_3(glval<MyClass>) = InitializeThis :
# 10| r0_4(glval<Int32>) = VariableAddress[index] :
# 10| mu0_5(Int32) = InitializeParameter[index] : &:r0_4
# 16| r0_6(glval<String>) = VariableAddress[value] :
# 16| mu0_7(String) = InitializeParameter[value] : &:r0_6
# 18| r0_8(glval<String>) = VariableAddress[value] :
# 18| r0_9(String) = Load : &:r0_8, ~mu0_2
# 18| r0_10(MyClass) = CopyValue : r0_3
# 18| r0_11(glval<String[]>) = FieldAddress[address] : r0_10
# 18| r0_12(String[]) = ElementsAddress : r0_11
# 18| r0_13(glval<Int32>) = VariableAddress[index] :
# 18| r0_14(Int32) = Load : &:r0_13, ~mu0_2
# 18| r0_15(String[]) = PointerAdd[8] : r0_12, r0_14
# 18| mu0_16(String) = Store : &:r0_15, r0_9
# 16| v0_17(Void) = ReturnVoid :
# 16| v0_18(Void) = UnmodeledUse : mu*
# 16| v0_19(Void) = ExitFunction :
# 23| System.Void Indexers.Main()
# 23| Block 0
# 23| v0_0(Void) = EnterFunction :
# 23| mu0_1(null) = AliasedDefinition :
# 23| mu0_2(null) = UnmodeledDefinition :
# 25| r0_3(glval<MyClass>) = VariableAddress[inst] :
# 25| r0_4(MyClass) = NewObj :
# 25| r0_5(glval<null>) = FunctionAddress[MyClass] :
# 25| v0_6(Void) = Call : func:r0_5, this:r0_4
# 25| mu0_7(null) = ^CallSideEffect : ~mu0_2
# 25| mu0_8(MyClass) = Store : &:r0_3, r0_4
# 26| r0_9(glval<MyClass>) = VariableAddress[inst] :
# 26| r0_10(MyClass) = Load : &:r0_9, ~mu0_2
# 26| r0_11(glval<null>) = FunctionAddress[set_Item] :
# 26| r0_12(Int32) = Constant[0] :
# 26| r0_13(String) = StringConstant["str1"] :
# 26| v0_14(Void) = Call : func:r0_11, this:r0_10, 0:r0_12, 1:r0_13
# 26| mu0_15(null) = ^CallSideEffect : ~mu0_2
# 27| r0_16(glval<MyClass>) = VariableAddress[inst] :
# 27| r0_17(MyClass) = Load : &:r0_16, ~mu0_2
# 27| r0_18(glval<null>) = FunctionAddress[set_Item] :
# 27| r0_19(Int32) = Constant[1] :
# 27| r0_20(String) = StringConstant["str1"] :
# 27| v0_21(Void) = Call : func:r0_18, this:r0_17, 0:r0_19, 1:r0_20
# 27| mu0_22(null) = ^CallSideEffect : ~mu0_2
# 28| r0_23(glval<MyClass>) = VariableAddress[inst] :
# 28| r0_24(MyClass) = Load : &:r0_23, ~mu0_2
# 28| r0_25(glval<null>) = FunctionAddress[set_Item] :
# 28| r0_26(Int32) = Constant[1] :
# 28| r0_27(glval<MyClass>) = VariableAddress[inst] :
# 28| r0_28(MyClass) = Load : &:r0_27, ~mu0_2
# 28| r0_29(glval<null>) = FunctionAddress[get_Item] :
# 28| r0_30(Int32) = Constant[0] :
# 28| r0_31(String) = Call : func:r0_29, this:r0_28, 0:r0_30
# 28| mu0_32(null) = ^CallSideEffect : ~mu0_2
# 28| v0_33(Void) = Call : func:r0_25, this:r0_24, 0:r0_26, 1:r0_31
# 28| mu0_34(null) = ^CallSideEffect : ~mu0_2
# 23| v0_35(Void) = ReturnVoid :
# 23| v0_36(Void) = UnmodeledUse : mu*
# 23| v0_37(Void) = ExitFunction :
inheritance_polymorphism.cs:
# 3| System.Int32 A.function()
# 3| Block 0