From 691fa95d7be025e0a8a328c225f1367372cdf921 Mon Sep 17 00:00:00 2001
From: Vlad Brezae <brezaevlad@gmail.com>
Date: Tue, 6 Dec 2022 21:10:27 +0200
Subject: [PATCH 1/2] [mono][interp] Add new cpobj version that doesn't require
 card marking

---
 src/mono/mono/mini/interp/interp.c    | 5 +++++
 src/mono/mono/mini/interp/mintops.def | 1 +
 src/mono/mono/mini/interp/transform.c | 9 +++++++--
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c
index ed38874fbf5f3c..7c72bbfa4eb7b4 100644
--- a/src/mono/mono/mini/interp/interp.c
+++ b/src/mono/mono/mini/interp/interp.c
@@ -5514,6 +5514,11 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
 			ip += 4;
 			MINT_IN_BREAK;
 		}
+		MINT_IN_CASE(MINT_CPOBJ_VT_NOREF) {
+			memcpy (LOCAL_VAR (ip [1], gpointer), LOCAL_VAR (ip [2], gpointer), ip [3]);
+			ip += 4;
+			MINT_IN_BREAK;
+		}
 		MINT_IN_CASE(MINT_LDOBJ_VT) {
 			guint16 size = ip [3];
 			gpointer srcAddr = LOCAL_VAR (ip [2], gpointer);
diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def
index f8b65c48c404d2..fc3b5cf793c97d 100644
--- a/src/mono/mono/mini/interp/mintops.def
+++ b/src/mono/mono/mini/interp/mintops.def
@@ -380,6 +380,7 @@ OPDEF(MINT_LDFTN_DYNAMIC, "ldftn.dynamic", 3, 1, 1, MintOpMethodToken)
 OPDEF(MINT_LDVIRTFTN, "ldvirtftn", 4, 1, 1, MintOpMethodToken)
 OPDEF(MINT_CPOBJ, "cpobj", 4, 0, 2, MintOpClassToken)
 OPDEF(MINT_CPOBJ_VT, "cpobj.vt", 4, 0, 2, MintOpClassToken)
+OPDEF(MINT_CPOBJ_VT_NOREF, "cpobj.vt.noref", 4, 0, 2, MintOpUShortInt)
 OPDEF(MINT_LDOBJ_VT, "ldobj.vt", 4, 1, 1, MintOpShortInt)
 OPDEF(MINT_STOBJ_VT, "stobj.vt", 4, 0, 2, MintOpClassToken)
 OPDEF(MINT_STOBJ_VT_NOREF, "stobj.vt.noref", 4, 0, 2, MintOpShortInt)
diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c
index d5c7068882f120..686690f3e110cc 100644
--- a/src/mono/mono/mini/interp/transform.c
+++ b/src/mono/mono/mini/interp/transform.c
@@ -5650,9 +5650,14 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
 			if (m_class_is_valuetype (klass)) {
 				mt = mint_type (m_class_get_byval_arg (klass));
 				td->sp -= 2;
-				interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_CPOBJ_VT : MINT_CPOBJ);
+				if (mt == MINT_TYPE_VT && !m_class_has_references (klass)) {
+					interp_add_ins (td, MINT_CPOBJ_VT_NOREF);
+					td->last_ins->data [0] = GINT32_TO_UINT16 (mono_class_value_size (klass, NULL));
+				} else {
+					interp_add_ins (td, (mt == MINT_TYPE_VT) ? MINT_CPOBJ_VT : MINT_CPOBJ);
+					td->last_ins->data [0] = get_data_item_index (td, klass);
+				}
 				interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
-				td->last_ins->data [0] = get_data_item_index(td, klass);
 			} else {
 				td->sp--;
 				interp_add_ins (td, MINT_LDIND_I);

From d574ff431abc034bc0cda47e277aaa6a858c4859 Mon Sep 17 00:00:00 2001
From: Vlad Brezae <brezaevlad@gmail.com>
Date: Tue, 6 Dec 2022 21:24:17 +0200
Subject: [PATCH 2/2] [mono][interp] Replace ldobj.vt + stobj.vt.noref pair
 with cpobj.vt.noref

---
 src/mono/mono/mini/interp/interp.c    |  4 +++-
 src/mono/mono/mini/interp/transform.c | 18 ++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c
index 7c72bbfa4eb7b4..a710e5e969c7ad 100644
--- a/src/mono/mono/mini/interp/interp.c
+++ b/src/mono/mono/mini/interp/interp.c
@@ -5515,7 +5515,9 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
 			MINT_IN_BREAK;
 		}
 		MINT_IN_CASE(MINT_CPOBJ_VT_NOREF) {
-			memcpy (LOCAL_VAR (ip [1], gpointer), LOCAL_VAR (ip [2], gpointer), ip [3]);
+			gpointer src_addr = LOCAL_VAR (ip [2], gpointer);
+			NULL_CHECK (src_addr);
+			memcpy (LOCAL_VAR (ip [1], gpointer), src_addr, ip [3]);
 			ip += 4;
 			MINT_IN_BREAK;
 		}
diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c
index 686690f3e110cc..cc5b3bd130d72e 100644
--- a/src/mono/mono/mini/interp/transform.c
+++ b/src/mono/mono/mini/interp/transform.c
@@ -9438,6 +9438,24 @@ interp_super_instructions (TransformData *td)
 					}
 
 				}
+			} else if (opcode == MINT_STOBJ_VT_NOREF) {
+				int sreg_src = ins->sregs [1];
+				InterpInst *def = td->locals [sreg_src].def;
+				if (def != NULL && interp_prev_ins (ins) == def && def->opcode == MINT_LDOBJ_VT && ins->data [0] == def->data [0] && td->local_ref_count [sreg_src] == 1) {
+					InterpInst *new_inst = interp_insert_ins (td, ins, MINT_CPOBJ_VT_NOREF);
+					new_inst->sregs [0] = ins->sregs [0]; // dst
+					new_inst->sregs [1] = def->sregs [0]; // src
+					new_inst->data [0] = ins->data [0];   // size
+
+					interp_clear_ins (def);
+					interp_clear_ins (ins);
+					local_ref_count [sreg_src]--;
+					mono_interp_stats.super_instructions++;
+					if (td->verbose_level) {
+						g_print ("superins: ");
+						dump_interp_inst (new_inst);
+					}
+				}
 			}
 			noe += get_inst_length (ins);
 		}
