summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/classlibnative/bcltype/CMakeLists.txt1
-rw-r--r--src/classlibnative/bcltype/stringbuffer.cpp48
-rw-r--r--src/classlibnative/bcltype/stringbuffer.h38
-rw-r--r--src/classlibnative/bcltype/stringnative.cpp1
-rw-r--r--src/mscorlib/src/System/Text/StringBuilder.CoreCLR.cs76
-rw-r--r--src/strongname/api/common.h1
-rw-r--r--src/vm/common.h1
-rw-r--r--src/vm/ecalllist.h6
-rw-r--r--src/vm/mscorlib.cpp1
-rw-r--r--src/vm/mscorlib.h5
-rw-r--r--src/vm/object.cpp57
-rw-r--r--src/vm/object.h132
-rw-r--r--src/vm/vars.hpp4
13 files changed, 72 insertions, 299 deletions
diff --git a/src/classlibnative/bcltype/CMakeLists.txt b/src/classlibnative/bcltype/CMakeLists.txt
index e2da2308bb..785f6b5b44 100644
--- a/src/classlibnative/bcltype/CMakeLists.txt
+++ b/src/classlibnative/bcltype/CMakeLists.txt
@@ -17,7 +17,6 @@ set(BCLTYPE_SOURCES
oavariant.cpp
objectnative.cpp
stringnative.cpp
- stringbuffer.cpp
system.cpp
varargsnative.cpp
variant.cpp
diff --git a/src/classlibnative/bcltype/stringbuffer.cpp b/src/classlibnative/bcltype/stringbuffer.cpp
deleted file mode 100644
index d060a7e1ba..0000000000
--- a/src/classlibnative/bcltype/stringbuffer.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-//
-// File: StringBuffer.cpp
-//
-
-//
-// Purpose: The implementation of the StringBuffer class.
-//
-//
-
-#include "common.h"
-
-#include "object.h"
-#include "excep.h"
-#include "frames.h"
-#include "vars.hpp"
-#include "string.h"
-#include "stringbuffer.h"
-
-FCIMPL3(void, COMStringBuffer::ReplaceBufferInternal, StringBufferObject* thisRefUNSAFE, __in_ecount(newLength) WCHAR* newBuffer, INT32 newLength)
-{
- FCALL_CONTRACT;
-
- STRINGBUFFERREF thisRef = (STRINGBUFFERREF)ObjectToOBJECTREF(thisRefUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_1(thisRef);
-
- StringBufferObject::ReplaceBuffer(&thisRef, newBuffer, newLength);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-FCIMPL3(void, COMStringBuffer::ReplaceBufferAnsiInternal, StringBufferObject* thisRefUNSAFE, __in_ecount(newCapacity) CHAR* newBuffer, INT32 newCapacity)
-{
- FCALL_CONTRACT;
-
- STRINGBUFFERREF thisRef = (STRINGBUFFERREF)ObjectToOBJECTREF(thisRefUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_1(thisRef);
-
- StringBufferObject::ReplaceBufferAnsi(&thisRef, newBuffer, newCapacity);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-
diff --git a/src/classlibnative/bcltype/stringbuffer.h b/src/classlibnative/bcltype/stringbuffer.h
deleted file mode 100644
index 4c151ef166..0000000000
--- a/src/classlibnative/bcltype/stringbuffer.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// 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.
-//
-// File: StringBuffer.h
-//
-
-//
-// Purpose: Contains types and method signatures for the
-// StringBuffer class.
-//
-// Each function that we call through native only gets one argument,
-// which is actually a pointer to it's stack of arguments. Our structs
-// for accessing these are defined below.
-//
-
-//
-
-#ifndef _STRINGBUFFER_H_
-#define _STRINGBUFFER_H_
-
-#define CAPACITY_LOW 10000
-#define CAPACITY_MID 15000
-#define CAPACITY_HIGH 20000
-#define CAPACITY_FIXEDINC 5000
-#define CAPACITY_PERCENTINC 1.25
-
-class COMStringBuffer {
-
-public:
- //
- // NATIVE HELPER METHODS
- //
- static FCDECL3(void, ReplaceBufferInternal, StringBufferObject* thisRefUNSAFE, __in_ecount(newLength) WCHAR* newBuffer, INT32 newLength);
- static FCDECL3(void, ReplaceBufferAnsiInternal, StringBufferObject* thisRefUNSAFE, __in_ecount(newCapacity) CHAR* newBuffer, INT32 newCapacity);
-};
-
-#endif // _STRINGBUFFER_H
diff --git a/src/classlibnative/bcltype/stringnative.cpp b/src/classlibnative/bcltype/stringnative.cpp
index 6bf6deaf7e..1a05ffb430 100644
--- a/src/classlibnative/bcltype/stringnative.cpp
+++ b/src/classlibnative/bcltype/stringnative.cpp
@@ -20,7 +20,6 @@
#include "field.h"
#include "vars.hpp"
#include "stringnative.h"
-#include "stringbuffer.h"
#include "comutilnative.h"
#include "metasig.h"
#include "excep.h"
diff --git a/src/mscorlib/src/System/Text/StringBuilder.CoreCLR.cs b/src/mscorlib/src/System/Text/StringBuilder.CoreCLR.cs
index 6e4dd68309..c7e0cb3b74 100644
--- a/src/mscorlib/src/System/Text/StringBuilder.CoreCLR.cs
+++ b/src/mscorlib/src/System/Text/StringBuilder.CoreCLR.cs
@@ -8,11 +8,79 @@ namespace System.Text
{
public partial class StringBuilder
{
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal extern unsafe void ReplaceBufferInternal(char* newBuffer, int newLength);
+ private int GetReplaceBufferCapacity(int requiredCapacity)
+ {
+ // This function assumes that required capacity will be less
+ // than the max capacity of the StringBuilder
+ Diagnostics.Debug.Assert(requiredCapacity <= m_MaxCapacity);
+
+ int newCapacity = Capacity;
+ // Round the current capacity to the nearest multiple of 2
+ // that is larger than the required capacity.
+ if (newCapacity < requiredCapacity)
+ {
+ newCapacity = (requiredCapacity + 1) & ~1;
+ }
+ return newCapacity;
+ }
+
+ internal unsafe void ReplaceBufferInternal(char* newBuffer, int newLength)
+ {
+ if (newLength > m_MaxCapacity)
+ throw new ArgumentOutOfRangeException("capacity", SR.ArgumentOutOfRange_Capacity);
+
+ // Leave space for a NUL character at the end, the previous implementation did this
+ m_ChunkChars = new char[GetReplaceBufferCapacity(newLength + 1)];
+ new Span<char>(newBuffer, newLength).CopyTo(m_ChunkChars);
+ m_ChunkLength = newLength;
+ m_ChunkPrevious = null;
+ m_ChunkOffset = 0;
+ }
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal extern unsafe void ReplaceBufferAnsiInternal(sbyte* newBuffer, int newLength);
+ internal unsafe void ReplaceBufferAnsiInternal(sbyte* newBuffer, int newLength)
+ {
+ if (newLength > m_MaxCapacity)
+ throw new ArgumentOutOfRangeException("capacity", SR.ArgumentOutOfRange_Capacity);
+
+ // Leave space for a NUL character at the end, the previous implementation did this
+ m_ChunkChars = new char[GetReplaceBufferCapacity(newLength + 1)];
+
+ int convertedChars;
+
+ fixed (char* pChunkChars = m_ChunkChars)
+ {
+ Diagnostics.Debug.Assert(newLength < m_ChunkChars.Length);
+
+ // The incoming string buffer is supposed to have been populated by the
+ // P/Invoke-called native function but there's no way to know if that really
+ // happened, the native function might populate the buffer only in certain
+ // circumstances (e.g. only if the function succeeds).
+ //
+ // As such, the buffer might contain bogus characters that cannot be converted
+ // to Unicode and in that case conversion should not result in exceptions that
+ // the managed caller does not expect. Instead, the caller is expected to know
+ // when the resulting string is not valid and not use it.
+ //
+ // Both MultiByteToWideChar and the UTF8Encoding instance used on Unix-like
+ // platforms default to replacing invalid characters with the Unicode replacement
+ // character U+FFFD.
+#if PLATFORM_UNIX
+ convertedChars = Encoding.UTF8.GetChars((byte*)newBuffer, newLength, pChunkChars, newLength);
+#else
+ convertedChars = Interop.Kernel32.MultiByteToWideChar(
+ Interop.Kernel32.CP_ACP,
+ Interop.Kernel32.MB_PRECOMPOSED,
+ (byte*)newBuffer,
+ newLength,
+ pChunkChars,
+ newLength);
+#endif
+ }
+
+ m_ChunkOffset = 0;
+ m_ChunkLength = convertedChars;
+ m_ChunkPrevious = null;
+ }
/// <summary>
/// Copies the contents of this builder to the specified buffer.
diff --git a/src/strongname/api/common.h b/src/strongname/api/common.h
index d3d0d2faf5..113885cb99 100644
--- a/src/strongname/api/common.h
+++ b/src/strongname/api/common.h
@@ -146,7 +146,6 @@ typedef DPTR(class ReJitManager) PTR_ReJitManager;
typedef DPTR(struct ReJitInfo) PTR_ReJitInfo;
typedef DPTR(struct SharedReJitInfo) PTR_SharedReJitInfo;
typedef DPTR(class StringObject) PTR_StringObject;
-typedef DPTR(class StringBufferObject) PTR_StringBufferObject;
typedef DPTR(class TypeHandle) PTR_TypeHandle;
#ifdef STUB_DISPATCH
typedef VPTR(class VirtualCallStubManager) PTR_VirtualCallStubManager;
diff --git a/src/vm/common.h b/src/vm/common.h
index 1008533ddd..044ebb017d 100644
--- a/src/vm/common.h
+++ b/src/vm/common.h
@@ -167,7 +167,6 @@ typedef DPTR(class ReJitManager) PTR_ReJitManager;
typedef DPTR(struct ReJitInfo) PTR_ReJitInfo;
typedef DPTR(struct SharedReJitInfo) PTR_SharedReJitInfo;
typedef DPTR(class StringObject) PTR_StringObject;
-typedef DPTR(class StringBufferObject) PTR_StringBufferObject;
typedef DPTR(class TypeHandle) PTR_TypeHandle;
typedef VPTR(class VirtualCallStubManager) PTR_VirtualCallStubManager;
typedef VPTR(class VirtualCallStubManagerManager) PTR_VirtualCallStubManagerManager;
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 998f62b908..66d2a3eda6 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -116,11 +116,6 @@ FCFuncStart(gStringFuncs)
#endif // FEATURE_COMINTEROP
FCFuncEnd()
-FCFuncStart(gStringBufferFuncs)
- FCFuncElement("ReplaceBufferInternal", COMStringBuffer::ReplaceBufferInternal)
- FCFuncElement("ReplaceBufferAnsiInternal", COMStringBuffer::ReplaceBufferAnsiInternal)
-FCFuncEnd()
-
FCFuncStart(gValueTypeFuncs)
FCFuncElement("CanCompareBits", ValueTypeHelper::CanCompareBits)
FCFuncElement("FastEqualsCheck", ValueTypeHelper::FastEqualsCheck)
@@ -1375,7 +1370,6 @@ FCClassElement("Signature", "System", gSignatureNative)
FCClassElement("StackTrace", "System.Diagnostics", gDiagnosticsStackTrace)
FCClassElement("Stream", "System.IO", gStreamFuncs)
FCClassElement("String", "System", gStringFuncs)
-FCClassElement("StringBuilder", "System.Text", gStringBufferFuncs)
FCClassElement("StubHelpers", "System.StubHelpers", gStubHelperFuncs)
FCClassElement("SynchronizationContext", "System.Threading", gContextSynchronizationFuncs)
FCClassElement("Thread", "System.Threading", gThreadFuncs)
diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp
index 75c1f058f0..53c3044f1a 100644
--- a/src/vm/mscorlib.cpp
+++ b/src/vm/mscorlib.cpp
@@ -26,7 +26,6 @@
//
#include "arraynative.h"
#include "stringnative.h"
-#include "stringbuffer.h"
#include "objectnative.h"
#include "comdelegate.h"
#include "customattribute.h"
diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h
index 7642db6638..cbf3b409c2 100644
--- a/src/vm/mscorlib.h
+++ b/src/vm/mscorlib.h
@@ -885,11 +885,6 @@ DEFINE_METHOD(STRING, INTERNAL_COPY, InternalCopy,
DEFINE_METHOD(STRING, WCSLEN, wcslen, SM_PtrChar_RetInt)
DEFINE_PROPERTY(STRING, LENGTH, Length, Int)
-DEFINE_CLASS_U(Text, StringBuilder, StringBufferObject)
-DEFINE_FIELD_U(m_ChunkPrevious, StringBufferObject, m_ChunkPrevious)
-DEFINE_FIELD_U(m_MaxCapacity, StringBufferObject, m_MaxCapacity)
-DEFINE_FIELD_U(m_ChunkLength, StringBufferObject, m_ChunkLength)
-DEFINE_FIELD_U(m_ChunkOffset, StringBufferObject, m_ChunkOffset)
DEFINE_CLASS(STRING_BUILDER, Text, StringBuilder)
DEFINE_PROPERTY(STRING_BUILDER, LENGTH, Length, Int)
DEFINE_PROPERTY(STRING_BUILDER, CAPACITY, Capacity, Int)
diff --git a/src/vm/object.cpp b/src/vm/object.cpp
index 83afcd2fe5..1ff98d11da 100644
--- a/src/vm/object.cpp
+++ b/src/vm/object.cpp
@@ -1300,63 +1300,6 @@ BOOL StringObject::SetTrailByte(BYTE bTrailByte) {
return TRUE;
}
-
-/*================================ReplaceBuffer=================================
-**This is a helper function designed to be used by N/Direct it replaces the entire
-**contents of the String with a new string created by some native method. This
-**will not be exposed through the StringBuilder class.
-==============================================================================*/
-void StringBufferObject::ReplaceBuffer(STRINGBUFFERREF *thisRef, __in_ecount(newLength) WCHAR *newBuffer, INT32 newLength) {
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(newBuffer));
- PRECONDITION(newLength>=0);
- PRECONDITION(CheckPointer(thisRef));
- PRECONDITION(IsProtectedByGCFrame(thisRef));
- } CONTRACTL_END;
-
- if(newLength > (*thisRef)->GetMaxCapacity())
- {
- COMPlusThrowArgumentOutOfRange(W("capacity"), W("ArgumentOutOfRange_Capacity"));
- }
-
- CHARARRAYREF newCharArray = AllocateCharArray((*thisRef)->GetAllocationLength(newLength+1));
- (*thisRef)->ReplaceBuffer(&newCharArray, newBuffer, newLength);
-}
-
-
-/*================================ReplaceBufferAnsi=================================
-**This is a helper function designed to be used by N/Direct it replaces the entire
-**contents of the String with a new string created by some native method. This
-**will not be exposed through the StringBuilder class.
-**
-**This version does Ansi->Unicode conversion along the way. Although
-**making it a member of COMStringBuffer exposes more stringbuffer internals
-**than necessary, it does avoid requiring a temporary buffer to hold
-**the Ansi->Unicode conversion.
-==============================================================================*/
-void StringBufferObject::ReplaceBufferAnsi(STRINGBUFFERREF *thisRef, __in_ecount(newCapacity) CHAR *newBuffer, INT32 newCapacity) {
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(newBuffer));
- PRECONDITION(CheckPointer(thisRef));
- PRECONDITION(IsProtectedByGCFrame(thisRef));
- PRECONDITION(newCapacity>=0);
- } CONTRACTL_END;
-
- if(newCapacity > (*thisRef)->GetMaxCapacity())
- {
- COMPlusThrowArgumentOutOfRange(W("capacity"), W("ArgumentOutOfRange_Capacity"));
- }
-
- CHARARRAYREF newCharArray = AllocateCharArray((*thisRef)->GetAllocationLength(newCapacity+1));
- (*thisRef)->ReplaceBufferWithAnsi(&newCharArray, newBuffer, newCapacity);
-}
-
#ifdef USE_CHECKED_OBJECTREFS
//-------------------------------------------------------------
diff --git a/src/vm/object.h b/src/vm/object.h
index 4324fcac2e..e3e6c12399 100644
--- a/src/vm/object.h
+++ b/src/vm/object.h
@@ -37,8 +37,6 @@ void ErectWriteBarrierForMT(MethodTable **dst, MethodTable *ref);
* +-- code:StringObject - String objects are specialized objects for string
* | storage/retrieval for higher performance
* |
- * +-- code:StringBufferObject - StringBuffer instance layout.
- * |
* +-- BaseObjectWithCachedData - Object Plus one object field for caching.
* | |
* | +- ReflectClassBaseObject - The base object for the RuntimeType class
@@ -2539,136 +2537,6 @@ typedef BStrWrapper* BSTRWRAPPEROBJECTREF;
#endif // FEATURE_COMINTEROP
-class StringBufferObject;
-#ifdef USE_CHECKED_OBJECTREFS
-typedef REF<StringBufferObject> STRINGBUFFERREF;
-#else // USE_CHECKED_OBJECTREFS
-typedef StringBufferObject * STRINGBUFFERREF;
-#endif // USE_CHECKED_OBJECTREFS
-
-//
-// StringBufferObject
-//
-// Note that the "copy on write" bit is buried within the implementation
-// of the object in order to make the implementation smaller.
-//
-
-
-class StringBufferObject : public Object
-{
- friend class MscorlibBinder;
-
- private:
- CHARARRAYREF m_ChunkChars;
- StringBufferObject *m_ChunkPrevious;
- UINT32 m_ChunkLength;
- UINT32 m_ChunkOffset;
- INT32 m_MaxCapacity;
-
- WCHAR* GetBuffer()
- {
- LIMITED_METHOD_CONTRACT;
- return (WCHAR *)m_ChunkChars->GetDirectPointerToNonObjectElements();
- }
-
- // This function assumes that requiredLength will be less
- // than the max capacity of the StringBufferObject
- DWORD GetAllocationLength(DWORD dwRequiredLength)
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE((INT32)dwRequiredLength <= m_MaxCapacity);
- DWORD dwCurrentLength = GetArrayLength();
-
- // round the current length to the nearest multiple of 2
- // that is >= the required length
- if(dwCurrentLength < dwRequiredLength)
- {
- dwCurrentLength = (dwRequiredLength + 1) & ~1;
- }
- return dwCurrentLength;
- }
-
- protected:
- StringBufferObject() { LIMITED_METHOD_CONTRACT; };
- ~StringBufferObject() { LIMITED_METHOD_CONTRACT; };
-
- public:
- INT32 GetMaxCapacity()
- {
- return m_MaxCapacity;
- }
-
- DWORD GetArrayLength()
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(m_ChunkChars);
- return m_ChunkOffset + m_ChunkChars->GetNumComponents();
- }
-
- // Given an ANSI string, use it to replace the StringBufferObject's internal buffer
- VOID ReplaceBufferWithAnsi(CHARARRAYREF *newArrayRef, __in CHAR *newChars, DWORD dwNewCapacity)
- {
-#ifndef DACCESS_COMPILE
- SetObjectReference((OBJECTREF *)&m_ChunkChars, (OBJECTREF)(*newArrayRef), GetAppDomain());
-#endif //!DACCESS_COMPILE
- WCHAR *thisChars = GetBuffer();
- // NOTE: This call to MultiByte also writes out the null terminator
- // which is currently part of the String representation.
- INT32 ncWritten = MultiByteToWideChar(CP_ACP,
- MB_PRECOMPOSED,
- newChars,
- -1,
- (LPWSTR)thisChars,
- dwNewCapacity+1);
-
- if (ncWritten == 0)
- {
- // Normally, we'd throw an exception if the string couldn't be converted.
- // In this particular case, we paper over it instead. The reason is
- // that most likely reason a P/Invoke-called api returned a
- // poison string is that the api failed for some reason, and hence
- // exercised its right to leave the buffer in a poison state.
- // Because P/Invoke cannot discover if an api failed, it cannot
- // know to ignore the buffer on the out marshaling path.
- // Because normal P/Invoke procedure is for the caller to check error
- // codes manually, we don't want to throw an exception on him.
- // We certainly don't want to randomly throw or not throw based on the
- // nondeterministic contents of a buffer passed to a failing api.
- *thisChars = W('\0');
- ncWritten++;
- }
-
- m_ChunkOffset = 0;
- m_ChunkLength = ncWritten-1;
- m_ChunkPrevious = NULL;
- }
-
- // Given a Unicode string, use it to replace the StringBufferObject's internal buffer
- VOID ReplaceBuffer(CHARARRAYREF *newArrayRef, __in_ecount(dwNewCapacity) WCHAR *newChars, DWORD dwNewCapacity)
- {
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-#ifndef DACCESS_COMPILE
- SetObjectReference((OBJECTREF *)&m_ChunkChars, (OBJECTREF)(*newArrayRef), GetAppDomain());
-#endif //!DACCESS_COMPILE
- WCHAR *thisChars = GetBuffer();
- memcpyNoGCRefs(thisChars, newChars, sizeof(WCHAR)*dwNewCapacity);
- thisChars[dwNewCapacity] = W('\0');
- m_ChunkLength = dwNewCapacity;
- m_ChunkPrevious = NULL;
- m_ChunkOffset = 0;
- }
-
- static void ReplaceBuffer(STRINGBUFFERREF *thisRef, __in_ecount(newLength) WCHAR *newBuffer, INT32 newLength);
- static void ReplaceBufferAnsi(STRINGBUFFERREF *thisRef, __in_ecount(newCapacity) CHAR *newBuffer, INT32 newCapacity);
-};
-
class SafeHandle : public Object
{
friend class MscorlibBinder;
diff --git a/src/vm/vars.hpp b/src/vm/vars.hpp
index 69540c7f39..631435545c 100644
--- a/src/vm/vars.hpp
+++ b/src/vm/vars.hpp
@@ -316,8 +316,6 @@ class REF : public OBJECTREF
#define OBJECTREFToObject(objref) ((objref).operator-> ())
#define ObjectToSTRINGREF(obj) (STRINGREF(obj))
#define STRINGREFToObject(objref) (*( (StringObject**) &(objref) ))
-#define ObjectToSTRINGBUFFERREF(obj) (STRINGBUFFERREF(obj))
-#define STRINGBUFFERREFToObject(objref) (*( (StringBufferObject**) &(objref) ))
#else // _DEBUG_IMPL
@@ -328,8 +326,6 @@ class REF : public OBJECTREF
#define OBJECTREFToObject(objref) ((PTR_Object) (objref))
#define ObjectToSTRINGREF(obj) ((PTR_StringObject) (obj))
#define STRINGREFToObject(objref) ((PTR_StringObject) (objref))
-#define ObjectToSTRINGBUFFERREF(obj) ((Ptr_StringBufferObject) (obj))
-#define STRINGBUFFERREFToObject(objref) ((Ptr_StringBufferObject) (objref))
#endif // _DEBUG_IMPL