[runtime] Convert String.InternalSetLength to an icall. Needed for canary support.
authorAlexis Christoforides <alexis@thenull.net>
Mon, 6 Oct 2014 05:21:15 +0000 (22:21 -0700)
committerAlexis Christoforides <alexis@thenull.net>
Mon, 6 Oct 2014 05:21:15 +0000 (22:21 -0700)
The change does not have a negative impact on StringBuilder performance; under variable-string-length microbenchmarks it seems to perform ~15-20% faster than the managed implementation.

mcs/class/corlib/System/String.cs
mono/metadata/boehm-gc.c
mono/metadata/gc-internal.h
mono/metadata/icall-def.h
mono/metadata/sgen-gc.c
mono/metadata/string-icalls.c
mono/metadata/string-icalls.h

index 2a408933eacf42bb4dfa82e80fdcf142481997d1..65e460647ca4955aecd1a8c4b97cccae46d9f582 100644 (file)
@@ -2688,24 +2688,8 @@ namespace System
                        }
                }
 
-               internal unsafe void InternalSetLength (int newLength)
-               {
-                       if (newLength > length)
-                               throw new ArgumentOutOfRangeException ("newLength", "newLength as to be <= length");
-
-                       // zero terminate, we can pass string objects directly via pinvoke
-                       // we also zero the rest of the string, since the new GC needs to be
-                       // able to handle the changing size (it will skip the 0 bytes).
-                       fixed (char * pStr = &start_char) {
-                               char *p = pStr + newLength;
-                               char *end = pStr + length;
-                               while (p < end) {
-                                       p [0] = '\0';
-                                       p++;
-                               }
-                       }
-                       length = newLength;
-               }
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal extern void InternalSetLength (int newLength);
 
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
                // When modifying it, GetCaseInsensitiveHashCode() should be modified as well.
index a3f8296459a2500efea3372f8c4441cc822df519..090f2f7a1dc98e9296d02c829debb4cba317c11c 100644 (file)
@@ -1291,6 +1291,18 @@ mono_gc_get_los_limit (void)
        return G_MAXINT;
 }
 
+void
+mono_gc_set_string_length (MonoString *str, gint32 new_length)
+{
+       mono_unichar2 *new_end = str->chars + new_length;
+       
+       /* zero the discarded string. This null-delimits the string and allows 
+        * the space to be reclaimed by SGen. */
+        
+       memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
+       str->length = new_length;
+}
+
 gboolean
 mono_gc_user_markers_supported (void)
 {
index 8e8c35f836065991b4a5266b39a45da65f223441..7b8836363f8a2a769b980d2a063e7d4567c398b2 100644 (file)
@@ -329,6 +329,8 @@ void mono_gc_set_skip_thread (gboolean skip) MONO_INTERNAL;
  */
 gboolean mono_gc_is_disabled (void) MONO_INTERNAL;
 
+void mono_gc_set_string_length (MonoString *str, gint32 new_length) MONO_INTERNAL;
+
 #if defined(__MACH__)
 void mono_gc_register_mach_exception_thread (pthread_t thread) MONO_INTERNAL;
 pthread_t mono_gc_get_mach_exception_thread (void) MONO_INTERNAL;
index 103eb3c4230490ba81c24dfa376d3291fcfe98ec..257b8332f5f4ac9abaf33200788483a60daf44b7 100644 (file)
@@ -797,6 +797,7 @@ ICALL(STRING_8a, "GetLOSLimit", ves_icall_System_String_GetLOSLimit)
 ICALL(STRING_9, "InternalAllocateStr", ves_icall_System_String_InternalAllocateStr)
 ICALL(STRING_10, "InternalIntern", ves_icall_System_String_InternalIntern)
 ICALL(STRING_11, "InternalIsInterned", ves_icall_System_String_InternalIsInterned)
+ICALL(STRING_12, "InternalSetLength", ves_icall_System_String_InternalSetLength)
 
 ICALL_TYPE(TENC, "System.Text.Encoding", TENC_1)
 ICALL(TENC_1, "InternalCodePage", ves_icall_System_Text_Encoding_InternalCodePage)
index ddbef83fe2418fad66a29f1b935d5eff1617e366..f24fabeac0ac1ce6802706a468c09b4789be8672 100644 (file)
@@ -4360,6 +4360,25 @@ mono_gc_get_los_limit (void)
        return MAX_SMALL_OBJ_SIZE;
 }
 
+void
+mono_gc_set_string_length (MonoString *str, gint32 new_length)
+{
+       mono_unichar2 *new_end = str->chars + new_length;
+       
+       /* zero the discarded string. This null-delimits the string and allows 
+        * the space to be reclaimed by SGen. */
+        
+       if (nursery_canaries_enabled () && sgen_ptr_in_nursery (str)) {
+               CHECK_CANARY_FOR_OBJECT (str);
+               memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2) + CANARY_SIZE);
+               memcpy (new_end + 1 , CANARY_STRING, CANARY_SIZE);
+       } else {
+               memset (new_end, 0, (str->length - new_length + 1) * sizeof (mono_unichar2));
+       }
+       
+       str->length = new_length;
+}
+
 gboolean
 mono_gc_user_markers_supported (void)
 {
index 388d866141fad205fb9ccee43287e03d77d62b86..22b1fbbbdb49a2aed23b58776bc07811f7c39496 100644 (file)
@@ -67,3 +67,10 @@ ves_icall_System_String_GetLOSLimit (void)
 
        return (limit - 2 - offsetof (MonoString, chars)) / 2;
 }
+
+void
+ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length)
+{
+       mono_gc_set_string_length (str, new_length);
+}
+
index a0b831a1e2006411eecc26190d60ca4df45c4f27..33bcf80378b006c177992070ddac209613660b34 100644 (file)
@@ -30,4 +30,7 @@ ves_icall_System_String_InternalIsInterned (MonoString *str) MONO_INTERNAL;
 int
 ves_icall_System_String_GetLOSLimit (void) MONO_INTERNAL;
 
+void
+ves_icall_System_String_InternalSetLength (MonoString *str, gint32 new_length) MONO_INTERNAL;
+
 #endif /* _MONO_CLI_STRING_ICALLS_H_ */