bmx-ng / brl.mod

BlitzMax Runtime Libraries, for BlitzMax NG.
12 stars 11 forks source link

[Brl.Reflection] Issues invoking Meth/Funcs with Float-params in debug builds #227

Open GWRon opened 2 years ago

GWRon commented 2 years ago
SuperStrict
Framework Brl.StandardIO
Import Brl.Reflection

Type TTest
    Method Hello(f:Float)
        Print "Hello() f = " + f
    End Method

    Function HelloFunc(f:Float)
        Print "HelloFunc() f = " + f
    End Function
End Type

Local t:TTest = New TTest
Print "via direct:"
t.Hello(1.2345:Float)

Print "via method invoke:"
Local m:TMethod = TTypeId.ForObject(t).FindMethod("Hello")
m.Invoke(t, [String(1.2345:Float)])

Print "via function invoke:"
Local f:TFunction = TTypeId.ForObject(t).FindFunction("HelloFunc")
f.Invoke([String(1.2345:Float)])

Release:

Executing:untitled1
via direct:
Hello() f = 1.23450005
via method invoke:
Hello() f = 1.23450005
via function invoke:
HelloFunc() f = 1.23450005

Debug:

Executing:untitled1.debug
via direct:
Hello() f = 1.23450005
via method invoke:
Hello() f = 0.00000000
via function invoke:
HelloFunc() f = 0.00000000

so there seems some "offset" or so which interfers in the reflection code - might be connected to #204 and #205

GWRon commented 2 years ago

This also happens for ":double"

SuperStrict
Framework Brl.StandardIO
Import Brl.Reflection

Type TTest
    Method HelloDouble(d:Double)
        Print "HelloDouble() " + d
    End Method

    Method HelloFloat(f:Float)
        Print "HelloFloat() " + f
    End Method

    Method HelloLong(l:Long)
        Print "HelloLong() " + l
    End Method

    Method HelloInt(i:Int)
        Print "HelloInt() " + i
    End Method

End Type

Local t:TTest = New TTest
Print "via direct:"
t.HelloDouble(1.2345:Float)
t.HelloFloat(1.2345:Float)
t.HelloLong(12345:Long)
t.HelloInt(12345:Int)

Print "via method invoke:"
TTypeId.ForObject(t).FindMethod("HelloDouble").Invoke(t, [String(1.2345:Double)])
TTypeId.ForObject(t).FindMethod("HelloFloat").Invoke(t, [String(1.2345:Float)])
TTypeId.ForObject(t).FindMethod("HelloLong").Invoke(t, [String(12345:Long)])
TTypeId.ForObject(t).FindMethod("HelloInt").Invoke(t, [String(12345:Int)])

Release:

Executing:untitled1
via direct:
HelloDouble() 1.2344999999999999
HelloFloat() 1.23450005
HelloLong() 12345
HelloInt() 12345
via method invoke:
HelloDouble() 1.2344999999999999
HelloFloat() 1.23450005
HelloLong() 12345
HelloInt() 12345

Debug:

Executing:untitled1.debug
via direct:
HelloDouble() 1.2344999999999999
HelloFloat() 1.23450005
HelloLong() 12345
HelloInt() 12345
via method invoke:
HelloDouble() 0.0000000000000000
HelloFloat() 0.00000000
HelloLong() 12345
HelloInt() 12345
GWRon commented 2 years ago

Seems it does not happen on with i386/32bit (with a recent BlitzMax tool chain (bmk, bcc, modules)) On Mac and Linux at least the x64 release build seems to work. Windows... partially works in x64 release (only function call invokation).

All (Mac, Windows and Linux) are running on bcc 0.133.

OS Release x86 Debug x86 Release x64 Debug x64
Windows 10 OK OK FAIL (Method call) FAIL
Linux Cent OS 7 (32 Bit) OK OK -- --
Linux Mint 19.3 (64 Bit) -- -- OK FAIL
Linux Mint 20.3 (64 Bit) -- -- OK FAIL
Mac OS X Monterey (64 Bit) -- -- OK FAIL

Example Screenshots for Windows and Mac:

image

image

image

image

GWRon commented 2 years ago

I added some "prints" to check what happens inside the reflection-code to invoke a function ... this broke it for "x64 release" too (so it no longer passed the right number to the function call)

Simply adding this print there:

    Default
print "_CallFunction: " + argTypes.length
        If typeid.ExtendsType(PointerTypeId) Or typeid.ExtendsType(FunctionTypeId) Then
?Not ptr64
            Select argTypes.length

Replacing the print with an "Local x:Int = argTypes.length" and the function receives the correct number, but with print it becomes

_CallFunction: 1
HelloFunc() f = 9.18340949e-41

Ok, so I checked what is needed to bork the result:

'No change
'Local x:Int = argTypes.length
'No change
'Local x:Long = Long(argTypes.length)
'borks result
'Local x:String = String(argTypes.length)
'borks result
'print "_CallFunction: " + argTypes.length

So it works for casts to Long or Int - but when casting it to a String, it somehow affects the stuff behind that code.

Dunno if that helps... and as said, this is only tested onr x64 linux

GWRon commented 2 years ago

What else changes that value?

'No change
'print "hello"
'borks result
myprintf(1)

with myprintf being added to reflection.c:

void myprintf(int n) {
    printf("%d\n", n);
    fflush(stdout);
}

And when replacing that with simply printing "hello", then I get a "0.000000" instead of a one like "9.14767638e-41"

void myprintf(int n) {
    printf("hello\n");
    fflush(stdout);
}

Some memory address/offsets borked?


Edit:

            Select argTypes.length
                Case 0
                    Local f:Byte Ptr()=p
                    Return String.Fromlong(Long f())
                Case 1
print " --- 1 argument: " + p
                    Local f:Byte Ptr(p0:Byte Ptr)=p
                    Return String.Fromlong(Long f(q[0]))

Simply printing the memory address of the function will lead to the call returning a different value:

 --- 1 argument: 4214192
HelloFunc() f = -nan

and without the print:

HelloFunc() f = 9.18340949e-41

Edit: This is surely connected to #147