summaryrefslogtreecommitdiff
path: root/src/vm/amd64/jithelpers_slow.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/amd64/jithelpers_slow.S')
-rw-r--r--src/vm/amd64/jithelpers_slow.S113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/vm/amd64/jithelpers_slow.S b/src/vm/amd64/jithelpers_slow.S
new file mode 100644
index 0000000000..0a5da69393
--- /dev/null
+++ b/src/vm/amd64/jithelpers_slow.S
@@ -0,0 +1,113 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+
+#ifdef _DEBUG
+// Version for when we're sure to be in the GC, checks whether or not the card
+// needs to be updated
+//
+// void JIT_WriteBarrier_Debug(Object** dst, Object* src)
+LEAF_ENTRY JIT_WriteBarrier_Debug, _TEXT
+
+#ifdef WRITE_BARRIER_CHECK
+ // **ALSO update the shadow GC heap if that is enabled**
+ // Do not perform the work if g_GCShadow is 0
+ PREPARE_EXTERNAL_VAR g_GCShadow, rax
+ cmp qword ptr [rax], 0
+ je NoShadow
+
+ // If we end up outside of the heap don't corrupt random memory
+ mov r10, rdi
+ PREPARE_EXTERNAL_VAR g_lowest_address, r11
+ sub r10, [r11]
+ jb NoShadow
+
+ // Check that our adjusted destination is somewhere in the shadow gc
+ add r10, [rax]
+ PREPARE_EXTERNAL_VAR g_GCShadowEnd, r11
+ cmp r10, [r11]
+ ja NoShadow
+
+ // Write ref into real GC// see comment below about possibility of AV
+ mov [rdi], rsi
+ // Write ref into shadow GC
+ mov [r10], rsi
+
+ // Ensure that the write to the shadow heap occurs before the read from
+ // the GC heap so that race conditions are caught by INVALIDGCVALUE
+ mfence
+
+ // Check that GC/ShadowGC values match
+ mov r11, [rdi]
+ mov rax, [r10]
+ cmp rax, r11
+ je DoneShadow
+ movabs r11, INVALIDGCVALUE
+ mov [r10], r11
+
+ jmp DoneShadow
+
+ // If we don't have a shadow GC we won't have done the write yet
+ NoShadow:
+#endif
+
+ mov rax, rsi
+
+ // Do the move. It is correct to possibly take an AV here, the EH code
+ // figures out that this came from a WriteBarrier and correctly maps it back
+ // to the managed method which called the WriteBarrier (see setup in
+ // InitializeExceptionHandling, vm\exceptionhandling.cpp).
+ mov [rdi], rax
+
+#ifdef WRITE_BARRIER_CHECK
+ // If we had a shadow GC then we already wrote to the real GC at the same time
+ // as the shadow GC so we want to jump over the real write immediately above
+ DoneShadow:
+#endif
+
+#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+ // Update the write watch table if necessary
+ PREPARE_EXTERNAL_VAR g_sw_ww_enabled_for_gc_heap, r10
+ cmp byte ptr [r10], 0h
+ je CheckCardTable_Debug
+ mov r10, rdi
+ shr r10, 0Ch // SoftwareWriteWatch::AddressToTableByteIndexShift
+ PREPARE_EXTERNAL_VAR g_sw_ww_table, r11
+ add r10, qword ptr [r11]
+ cmp byte ptr [r10], 0h
+ jne CheckCardTable_Debug
+ mov byte ptr [r10], 0FFh
+#endif
+
+ CheckCardTable_Debug:
+ // See if we can just quick out
+ PREPARE_EXTERNAL_VAR g_ephemeral_low, r10
+ cmp rax, [r10]
+ jb Exit_Debug
+ PREPARE_EXTERNAL_VAR g_ephemeral_high, r10
+ cmp rax, [r10]
+ jnb Exit_Debug
+
+ // Check if we need to update the card table
+ // Calc pCardByte
+ shr rdi, 0x0B
+ PREPARE_EXTERNAL_VAR g_card_table, r10
+ add rdi, [r10]
+
+ // Check if this card is dirty
+ cmp byte ptr [rdi], 0FFh
+ jne UpdateCardTable_Debug
+ REPRET
+
+ UpdateCardTable_Debug:
+ mov byte ptr [rdi], 0FFh
+ ret
+
+ .balign 16
+ Exit_Debug:
+ REPRET
+LEAF_END_MARKED JIT_WriteBarrier_Debug, _TEXT
+#endif