BitConverter.ToInt32 - weird optimization?

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Now, if we take a look at the reflected BitConverter.ToInt32 method it looks
something like this:

public static unsafe int ToInt32(byte[] value, int startIndex)
{
if (value == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value);
}
if (((ulong) startIndex) >= value.Length)
{

ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex,
ExceptionResource.ArgumentOutOfRange_Index);
}
if (startIndex > (value.Length - 4))
{

ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
}
fixed (byte* numRef1 = &(value[startIndex]))
{
if ((startIndex % 4) == 0)
{
return *(((int*) numRef1));
}
if (BitConverter.IsLittleEndian)
{
return (((numRef1[0] | (numRef1[1] << 8)) | (numRef1[2] <<
0x10)) | (numRef1[3] << 0x18));
}
return ((((numRef1[0] << 0x18) | (numRef1[1] << 0x10)) |
(numRef1[2] << 8)) | numRef1[3]);
}
}

What I don't understand is this:

if ((startIndex % 4) == 0)
{
return *(((int*) numRef1));
}

What prevents me from using this method when the remaining product isn't 0?
We already checked if there is 4 bytes to read so I should be able to.

Cheers

Morten
 
<=?Utf-8?B?TW9ydGVuIEIuIFBvc3Q=?= <Morten B.
(e-mail address removed)>> wrote:

What prevents me from using this method when the remaining product isn't 0?
We already checked if there is 4 bytes to read so I should be able to.

My guess is that "something" doesn't like pointers which aren't aligned
on a word boundary.
 
Jon Skeet said:
<=?Utf-8?B?TW9ydGVuIEIuIFBvc3Q=?= <Morten B.
(e-mail address removed)>> wrote:



My guess is that "something" doesn't like pointers which aren't aligned
on a word boundary.

You mean double word? It might be that, but it would be super nice to know
WHAT doesn't like it :)
 
Morten B. Post said:
You mean double word?

Sorry, I'm used to "word" meaning "32 bits" on a 32 bit architecture.
I'd forgotten the curious Windows heritage of it meaning 16 bits...
It might be that, but it would be super nice to know
WHAT doesn't like it :)

I suspect it's *somewhere* in the CLI spec, but I'm feeling too groggy
to check at the minute.
 
....
My guess is that "something" doesn't like pointers which aren't aligned
on a word boundary.
....

Processors don't like it, it's at least performance penalty, if not an
exception (on some processors). Code seen is on the safe side...

Goran
 
Goran Sliskovic said:
....
....

Processors don't like it, it's at least performance penalty, if not an
exception (on some processors). Code seen is on the safe side...

Goran

I totally understand that. But we're talking about an array of bytes here
which are aligned by 1 byte? So lets say our CPU is using 32 bit cycles - it
would load 4 bytes to the register at a time - the the array offset is wrong
it would actually have to access two different blocks of memory and then
shift away the bits that aren't necessary. Or how do we know that the array
is properly alligned when it consists of. I hope someone can answer this.

On a final note. If .net is adding 3 padded bytes for each byte I'd be
really surprised hehe.
 
Morten said:
....


I totally understand that. But we're talking about an array of bytes here
which are aligned by 1 byte? So lets say our CPU is using 32 bit cycles - it
would load 4 bytes to the register at a time - the the array offset is wrong
it would actually have to access two different blocks of memory and then
shift away the bits that aren't necessary. Or how do we know that the array
is properly alligned when it consists of. I hope someone can answer this.

On a final note. If .net is adding 3 padded bytes for each byte I'd be
really surprised hehe.

It's not adding 3 padded bytes per byte, rather all allocated buffers
are aligned on 4 byte boundary (even if you allocate 1 byte). OS
allocates all buffers aligned (VirtualAlloc).

From MSDN:
<quote>
VirtualAlloc

Reserves or commits a region of pages in the virtual address space of
the calling process. Memory allocated by this function is automatically
initialized to zero, unless MEM_RESET is specified.

To allocate memory in the address space of another process, use the
VirtualAllocEx function.

LPVOID VirtualAlloc(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);

Parameters

lpAddress
[in] The starting address of the region to allocate. If the memory
is being reserved, the specified address is rounded down to the nearest
multiple of the allocation granularity. If the memory is already
reserved and is being committed, the address is rounded down to the next
page boundary. To determine the size of a page and the allocation
granularity on the host computer, use the GetSystemInfo function. If
this parameter is NULL, the system determines where to allocate the region.
</quote>

if ((startIndex % 4) == 0)
{
return *(((int*) numRef1));
}

since buffer is aligned on 4 bytes, all indexes % 4 == 0 are also, so
it's safe to cast to int and return, yielding performance gain. If not,
slow but safe calculation occures.

Regards,
Goran
 
Back
Top