diff options
-rw-r--r-- | src/classlibnative/bcltype/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/classlibnative/bcltype/stringbuffer.cpp | 48 | ||||
-rw-r--r-- | src/classlibnative/bcltype/stringbuffer.h | 38 | ||||
-rw-r--r-- | src/classlibnative/bcltype/stringnative.cpp | 1 | ||||
-rw-r--r-- | src/mscorlib/src/System/Text/StringBuilder.CoreCLR.cs | 76 | ||||
-rw-r--r-- | src/strongname/api/common.h | 1 | ||||
-rw-r--r-- | src/vm/common.h | 1 | ||||
-rw-r--r-- | src/vm/ecalllist.h | 6 | ||||
-rw-r--r-- | src/vm/mscorlib.cpp | 1 | ||||
-rw-r--r-- | src/vm/mscorlib.h | 5 | ||||
-rw-r--r-- | src/vm/object.cpp | 57 | ||||
-rw-r--r-- | src/vm/object.h | 132 | ||||
-rw-r--r-- | src/vm/vars.hpp | 4 |
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 |