summaryrefslogtreecommitdiff
path: root/src/classlibnative
diff options
context:
space:
mode:
authorStephen Toub <stoub@microsoft.com>2017-11-28 11:48:37 -0500
committerStephen Toub <stoub@microsoft.com>2017-11-28 21:30:05 -0500
commit45f1a4ff3c496e7a9814cff7d3b1b1a97d61650e (patch)
tree55f63d34f109ad48afd8f07036336f6270c41495 /src/classlibnative
parent39e99cabf31a89624c40b718ba2faf9829ab2455 (diff)
downloadcoreclr-45f1a4ff3c496e7a9814cff7d3b1b1a97d61650e.tar.gz
coreclr-45f1a4ff3c496e7a9814cff7d3b1b1a97d61650e.tar.bz2
coreclr-45f1a4ff3c496e7a9814cff7d3b1b1a97d61650e.zip
Move FormatDouble/Single to managed code
Instead of making fcalls to FormatDouble and FormatSingle, move them to managed, and use fcalls for the DoubleToNumber and NumberToDouble they call, shifting down the layer that's implemented in native. This allows us to then much more easily add TryFormat methods for double and float while also sharing more code between coreclr and corert, from which the managed implementations were taken (they're a direct port of these native implementations from coreclr). In the process, I also eliminated one fcall that can be implemented in managed easily. The remaining fcalls are more substantial and will eventually require more effort to bring to managed.
Diffstat (limited to 'src/classlibnative')
-rw-r--r--src/classlibnative/bcltype/number.cpp232
-rw-r--r--src/classlibnative/bcltype/number.h5
2 files changed, 6 insertions, 231 deletions
diff --git a/src/classlibnative/bcltype/number.cpp b/src/classlibnative/bcltype/number.cpp
index eea2b2e60b..c9eec007c3 100644
--- a/src/classlibnative/bcltype/number.cpp
+++ b/src/classlibnative/bcltype/number.cpp
@@ -2009,223 +2009,19 @@ ParseSection:
#pragma warning(pop)
#endif
-FCIMPL3_VII(Object*, COMNumber::FormatDouble, double value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
+FCIMPL3(void, COMNumber::DoubleToNumberFC, double value, int precision, BYTE* number)
{
FCALL_CONTRACT;
- NUMBER number;
- int digits;
- double dTest;
-
- struct _gc
- {
- STRINGREF format;
- NUMFMTREF numfmt;
- STRINGREF refRetVal;
- } gc;
-
- gc.format = (STRINGREF) formatUNSAFE;
- gc.numfmt = (NUMFMTREF) numfmtUNSAFE;
- gc.refRetVal = NULL;
-
- HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
- if (gc.numfmt == 0) COMPlusThrowArgumentNull(W("NumberFormatInfo"));
- wchar fmt = ParseFormatSpecifier(gc.format, &digits);
- wchar val = (fmt & 0xFFDF);
- int precision = DOUBLE_PRECISION;
- switch (val) {
- case 'R':
- //In order to give numbers that are both friendly to display and round-trippable,
- //we parse the number using 15 digits and then determine if it round trips to the same
- //value. If it does, we convert that NUMBER to a string, otherwise we reparse using 17 digits
- //and display that.
-
- DoubleToNumber(value, DOUBLE_PRECISION, &number);
-
- if (number.scale == (int) SCALE_NAN) {
- gc.refRetVal = gc.numfmt->sNaN;
- goto lExit;
- }
-
- if (number.scale == SCALE_INF) {
- gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
- goto lExit;
- }
-
- NumberToDouble(&number, &dTest);
-
- if (dTest == value) {
- gc.refRetVal = NumberToString(&number, 'G', DOUBLE_PRECISION, gc.numfmt);
- goto lExit;
- }
-
- DoubleToNumber(value, 17, &number);
- gc.refRetVal = NumberToString(&number, 'G', 17, gc.numfmt);
- goto lExit;
- break;
-
- case 'E':
- // Here we round values less than E14 to 15 digits
- if (digits > 14) {
- precision = 17;
- }
- break;
-
- case 'G':
- // Here we round values less than G15 to 15 digits, G16 and G17 will not be touched
- if (digits > 15) {
- precision = 17;
- }
- break;
-
- }
-
- DoubleToNumber(value, precision, &number);
-
- if (number.scale == (int) SCALE_NAN) {
- gc.refRetVal = gc.numfmt->sNaN;
- goto lExit;
- }
-
- if (number.scale == SCALE_INF) {
- gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
- goto lExit;
- }
-
- if (fmt != 0) {
- gc.refRetVal = NumberToString( &number, fmt, digits, gc.numfmt);
- }
- else {
- gc.refRetVal = NumberToStringFormat( &number, gc.format, gc.numfmt);
- }
-
-lExit: ;
- HELPER_METHOD_FRAME_END();
-
- return OBJECTREFToObject(gc.refRetVal);
+ DoubleToNumber(value, precision, (NUMBER*)number);
}
FCIMPLEND
-//
-//This function and the function pointer which we use to access are
-//to prevent VC7 from optimizing away our cast from double to float.
-//We need this narrowing operation to verify whether or not we successfully round-tripped
-//the single value.
-
-//
-// We need this method to have volatile arguments.
-//
-static void CvtToFloat(double val, RAW_KEYWORD(volatile) float* fltPtr)
-{
- LIMITED_METHOD_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
-
- *fltPtr = (float)val;
-}
-
-void (*CvtToFloatPtr)(double val, RAW_KEYWORD(volatile) float* fltPtr) = CvtToFloat;
-
-
-FCIMPL3_VII(Object*, COMNumber::FormatSingle, float value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
+FCIMPL2(void, COMNumber::NumberToDoubleFC, BYTE* number, double* result)
{
FCALL_CONTRACT;
- NUMBER number;
- int digits;
- double dTest;
- double argsValue = value;
-
- struct _gc
- {
- STRINGREF format;
- NUMFMTREF numfmt;
- STRINGREF refRetVal;
- } gc;
-
- gc.format = (STRINGREF) formatUNSAFE;
- gc.numfmt = (NUMFMTREF) numfmtUNSAFE;
- gc.refRetVal = NULL;
-
- HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
- if (gc.numfmt == 0) COMPlusThrowArgumentNull(W("NumberFormatInfo"));
- wchar fmt = ParseFormatSpecifier(gc.format, &digits);
- wchar val = fmt & 0xFFDF;
- int precision = FLOAT_PRECISION;
- switch (val) {
- case 'R':
- {
- //In order to give numbers that are both friendly to display and round-trippable,
- //we parse the number using 7 digits and then determine if it round trips to the same
- //value. If it does, we convert that NUMBER to a string, otherwise we reparse using 9 digits
- //and display that.
-
- DoubleToNumber(argsValue, FLOAT_PRECISION, &number);
- if (number.scale == (int) SCALE_NAN) {
- gc.refRetVal = gc.numfmt->sNaN;
- goto lExit;
- }
- if (number.scale == SCALE_INF) {
- gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
- goto lExit;
- }
-
- NumberToDouble(&number, &dTest);
-
- Volatile<float> fTest;
-
- (*CvtToFloatPtr)(dTest, &fTest);
-
- if (fTest == value) {
- gc.refRetVal = NumberToString(&number, 'G', FLOAT_PRECISION, gc.numfmt);
- goto lExit;
- }
-
- DoubleToNumber(argsValue, 9, &number);
- gc.refRetVal = NumberToString(&number, 'G', 9, gc.numfmt);
- goto lExit;
- }
- break;
- case 'E':
- // Here we round values less than E14 to 15 digits
- if (digits > 6) {
- precision = 9;
- }
- break;
-
-
- case 'G':
- // Here we round values less than G15 to 15 digits, G16 and G17 will not be touched
- if (digits > 7) {
- precision = 9;
- }
- break;
- }
-
- DoubleToNumber(value, precision, &number);
-
- if (number.scale == (int) SCALE_NAN) {
- gc.refRetVal = gc.numfmt->sNaN;
- goto lExit;
- }
-
- if (number.scale == SCALE_INF) {
- gc.refRetVal = (number.sign? gc.numfmt->sNegativeInfinity: gc.numfmt->sPositiveInfinity);
- goto lExit;
- }
-
- if (fmt != 0) {
- gc.refRetVal = NumberToString( &number, fmt, digits, gc.numfmt);
- }
- else {
- gc.refRetVal = NumberToStringFormat( &number, gc.format, gc.numfmt);
- }
-
-lExit: ;
- HELPER_METHOD_FRAME_END();
-
- return OBJECTREFToObject(gc.refRetVal);
+ NumberToDouble((NUMBER*)number, result);
}
FCIMPLEND
@@ -2236,23 +2032,3 @@ FCIMPL2(FC_BOOL_RET, COMNumber::NumberBufferToDecimal, BYTE* number, DECIMAL* va
FC_RETURN_BOOL(COMDecimal::NumberToDecimal((NUMBER *) number, value) != 0);
}
FCIMPLEND
-
-FCIMPL2(FC_BOOL_RET, COMNumber::NumberBufferToDouble, BYTE* number, double* value)
-{
- FCALL_CONTRACT;
-
- double d = 0;
- NumberToDouble((NUMBER*) number, &d);
- unsigned int e = ((FPDOUBLE*)&d)->exp;
- unsigned int fmntLow = ((FPDOUBLE*)&d)->mantLo;
- unsigned int fmntHigh = ((FPDOUBLE*)&d)->mantHi;
- if (e == 0x7FF) {
- FC_RETURN_BOOL(false);
- }
- if (e == 0 && fmntLow ==0 && fmntHigh == 0) {
- d = 0;
- }
- *value = d;
- FC_RETURN_BOOL(true);
-}
-FCIMPLEND
diff --git a/src/classlibnative/bcltype/number.h b/src/classlibnative/bcltype/number.h
index e9651b66a1..0ddcb975f6 100644
--- a/src/classlibnative/bcltype/number.h
+++ b/src/classlibnative/bcltype/number.h
@@ -31,10 +31,9 @@ struct NUMBER {
class COMNumber
{
public:
- static FCDECL3_VII(Object*, FormatDouble, double value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE);
- static FCDECL3_VII(Object*, FormatSingle, float value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE);
+ static FCDECL3(void, DoubleToNumberFC, double value, int precision, BYTE* number);
+ static FCDECL2(void, NumberToDoubleFC, BYTE* number, double* value);
static FCDECL2(FC_BOOL_RET, NumberBufferToDecimal, BYTE* number, DECIMAL* value);
- static FCDECL2(FC_BOOL_RET, NumberBufferToDouble, BYTE* number, double* value);
static wchar_t* Int32ToDecChars(__in wchar_t* p, unsigned int value, int digits);
};