all groups > dotnet clr > november 2005 >
You're in the

dotnet clr

group:

CIL, CopyMemory and Compact Framework



CIL, CopyMemory and Compact Framework Luc Vaillant
11/15/2005 11:12:02 PM
dotnet clr: Hi,

I'm trying to write a method for my PocketPC that will write a Double value
to an Array buffer at the specified offset.

The constraints are :
- Must be safe managed code
- Array buffer can be of any integral type (byte, short, int, long, etc.)
- offset can be unaligned

I already wrote this method for Win32, and it works fine.

Because I knew about alignement constraint on ARM processors, I rewrote the
method doing a loop on the 8 bytes of the double value like do the
BitConverter.ToDouble method in its Compact Framewrok version

The differences between BitConverter.ToDouble and my method are:
- I'm writing a SetDouble method
- The destination buffer is an Array of any integral type (not only a Byte[])

My Compact Framework version of SetDouble works fine on the Pocket PC 2002
emulator, but throws a 0x80000002 exception on my Pocket PC device (QTEK 9090)

Here is the method code I wrote (I know that I'm accessing the Array like a
Byte array, but only for the first element in order to retreive the array's
starting address. This works fine in my Windows.Forms version):

..method public hidebysig static void
SetDouble(class [mscorlib]System.Array buffer,
int32 offset,
float64 'value') cil managed
{
.locals (unsigned int8* pBuffer, int32 nIndex, unsigned int8* pValue)

ldarg.0
ldc.i4.0
ldelema [mscorlib]System.Byte
ldarg.1
add
stloc.0

ldc.i4.0
stloc.1

ldarga.s 2
stloc.2

LOOP:
ldloc.0
ldloc.1
add

ldloc.2
ldloc.1
add

ldind.i1
stind.i1

ldloc.1
ldc.i4.1
add
stloc.1

ldloc.1
ldc.i4.8
blt.s LOOP
ret
} // end of method Buffer::SetDouble

Any suggestion ?

Thanks a lot
Re: CIL, CopyMemory and Compact Framework Holger Grund
11/16/2005 12:00:00 AM
[quoted text, click to view]
Do you mean verifiable code? Or just valid CIL?

[quoted text, click to view]
Did you write that in MSIL assembler? Can you share the source?

BTW: There's also unaligned
[quoted text, click to view]

I don't think you can do anything verifiable with native pointers. And
if you really want to use them, make sure the pointee is pinned.

[quoted text, click to view]
That's probably not verifiable. You should cast to the array
type before via
ldarg.0
castclass unsigned int8[]
ldc.i4.0
ldelema unsigned int8
....

[quoted text, click to view]
(Managed) pointer arithmetic is not verifiable.

[quoted text, click to view]
You store a managed pointer into a variable of native pointer
type. You should only do so if you know the memory pointed
to can't be moved by the GC.

You might want to use unaligned.1 cpblk

-hg


RE: CIL, CopyMemory and Compact Framework Luc Vaillant
11/16/2005 2:42:04 AM
First of all, I'm using .Net Framework v1.1 with VS.NET 2003

I have made some tests, and I realized that "ldelema [mscorlib]System.Byte"
doesn't work on my Pocket PC device if my buffer is declared as follow even
if typeof(buffer) is Byte[]:

SetDouble(class [mscorlib]System.Array buffer,...

It does work if the buffer is declared as follow:

SetDouble(unsigned int8[] buffer,...

Here is the code of my method. It works on Win32 and Compact Framwork in the
emulator, but not on my Pocket PC device

.method public hidebysig static void
SetDouble(class [mscorlib]System.Array buffer,
// SetDouble(unsigned int8[] buffer,
int32 offset,
float64 'value') cil managed
{
.locals (int32 nIndex, unsigned int8* pValue, unsigned int8* pBuffer)

ldc.i4.0 // 0
stloc.0 // nIndex = 0

ldarga.s 2 // &value
stloc.1 // pValue = &value;

ldarg.0 // buffer
ldarg.1 // offset
ldelema [mscorlib]System.Byte // &buffer[offset]
stloc.2 // pBuffer = &buffer[offset]

LOOP:
ldloc.2 // pBuffer
ldloc.0 // nIndex
add // pBuffer + nIndex
ldloc.1 // pValue
ldloc.0 // nIndex
add // &pValue[nIndex]
ldind.i1 // pValue[nIndex]
stind.i1 // pBuffer[nIndex] = pValue[nIndex]

ldloc.0 // nIndex
ldc.i4.1 // 1
add // nIndex++
stloc.0 // ->nIndex

ldloc.0 // nIndex
ldc.i4.8 // 8
blt.s LOOP // if (nIndex < 8) goto LOOP

ret
} // end of method Buffer::SetDouble






[quoted text, click to view]
RE: CIL, CopyMemory and Compact Framework Mattias Sjögren
11/16/2005 4:32:02 AM
[quoted text, click to view]

Any reason you're not calling System.Buffer.BlockCopy ?


Mattias
RE: CIL, CopyMemory and Compact Framework Luc Vaillant
11/16/2005 9:57:05 PM
The main reason is that the source or destination is not an Array


[quoted text, click to view]
Re: CIL, CopyMemory and Compact Framework Luc Vaillant
11/16/2005 10:46:08 PM
Thank you very much for your time, here are some answers

Lvt


[quoted text, click to view]
LVT : I just want not to be bored if security constraints (like only managed
code is allowed to run on this computer) are ON in .Net Framework

[quoted text, click to view]
LVT : Yes, I wrote this code in MSIL : First I wrote a small class with
empty methods, then I used ILDASM to get the MSIL of my class with methods
doing nothing, and then I wrote the missing MSIL code in my methods
Here is the code of the C# class :

using System;

namespace Memory
{
public class Buffer
{
private Buffer() {}
public static void SetDouble(Array buffer, Int32 offset, Double value)
{}
}
}

Here is the SetDouble generated code with my MSIL:

.method public hidebysig static void
SetDouble(class [mscorlib]System.Array buffer,
int32 offset,
float64 'value') cil managed
{
.locals (int32 nIndex, unsigned int8* pValue, unsigned int8* pBuffer)

ldc.i4.0 // 0
stloc.0 // nIndex = 0

ldarga.s 2 // &value
stloc.1 // pValue = &value;

ldarg.0 // buffer
ldarg.1 // offset
ldelema [mscorlib]System.Byte // &buffer[offset]
stloc.2 // pBuffer = &buffer[offset]

LOOP:
ldloc.2 // pBuffer
ldloc.0 // nIndex
add // pBuffer + nIndex
ldloc.1 // pValue
ldloc.0 // nIndex
add // &pValue[nIndex]
ldind.i1 // pValue[nIndex]
stind.i1 // pBuffer[nIndex] = pValue[nIndex]

ldloc.0 // nIndex
ldc.i4.1 // 1
add // nIndex++
stloc.0 // ->nIndex

ldloc.0 // nIndex
ldc.i4.8 // 8
blt.s LOOP // if (nIndex < 8) goto LOOP

ret
} // end of method Buffer::SetDouble

[quoted text, click to view]
LVT: Yes, alignment is a big issue on ARM, that's why I used a loop
The first version I wrote in MSIL for SetDouble was:

IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: ldelema [mscorlib]System.Byte
IL_0007: ldarg.1
IL_0008: add
IL_0009: ldarg.2
IL_000a: unaligned. 1
IL_000d: stind.r8
IL_000e: ret

but this code throws an exception on my Pocket PC

[quoted text, click to view]
LVT: I don't know how to pin memory

[quoted text, click to view]
LVT : Unfortunately, I couldn't cast the Array because I don't know its type
My first Idea was to provide a method that works on any integral type array,
but I realize that drive me to a lot of problems for 'nothing'.
I Think I will simply allow bytes array and then used Byte[] parameter type
instead of Array type.
This way I can use the ldelem.u1 just like BitConverter.ToDouble is doing in
its CF version

[quoted text, click to view]
LVT: You're right and I will avoid pointer arithmetic with ldelem.u1

[quoted text, click to view]
LVT: Idealy YES but the following code throws an InvalidProgramException:

.method public hidebysig static void
SetDouble(unsigned int8[] buffer,
int32 offset,
float64 'value') cil managed
{
ldarg.0 // buffer
ldarg.1 // offset
ldelema [mscorlib]System.Byte // &buffer[offset]
ldarga.s 2 // &value
ldc.i4.8 // 8
unaligned. 1 cpblk // CopyMemory
ret
} // end of method Buffer::SetDouble



[quoted text, click to view]
Re: CIL, CopyMemory and Compact Framework Holger Grund
11/17/2005 12:00:00 AM
[quoted text, click to view]
You probably want your code to verifiable then. Almost none of the things
suggested in here will work then. Maybe there are some base library
helpers which are statically known to be safe, but I'm afraid you'll have
to stick with a less efficient method.

[snip]

[quoted text, click to view]
Alignment is important on almost all platforms.

[quoted text, click to view]
I don't see anything wrong here. What's the exception?
Can you locate where it happens in the CIL stream? (You may
want to ilasm with debug information /DEBUG)

[quoted text, click to view]
You need a managed pointer with the pinned attribute to
point to the object (or any subobject of the complete object).
This can safely be converted to a native pointer. However,
native pointers are never verifiable.

..class X { // .ctor
.field int32 f; }

..method public static void main() {
.entrypoint
.locals ( int32& pinned p )
newobj instance void class X::.ctor() // x
ldflda int32 X::f
stloc p
// x.f is now pinned => x is pinned
ldloc p
conv.u
// top of the stack can be used as a native pointer
ret
}

[quoted text, click to view]
You can't do much with an array whose element type is unknown (in
a verifiable way).

[quoted text, click to view]
Looks perfectly valid to me. Did you get the calling function
correct? What does peverify say?


Re: CIL, CopyMemory and Compact Framework Luc Vaillant
11/17/2005 5:57:16 AM
Unfortunately, I do not have time to spend on this issue right now (my
clients are waiting for me...), I will investigate this later.
For now, I just change Array type to Byte[] and use a 8 bytes loop just like
BitConverter.ToDouble does.

As you certainely guess, I'm new in MSIL coding, and I found your remarks
very helpfull.

Thank you very much

Lvt

[quoted text, click to view]
Re: CIL, CopyMemory and Compact Framework Mattias Sjögren
11/17/2005 8:35:24 PM

[quoted text, click to view]

Looks to me like the destination is an array and you said so yoruself
in your original message.

The source value isn't an array but nothing's stopping you from
putting it into a single element double[].


Mattias

--
Mattias Sjögren [MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
AddThis Social Bookmark Button