bmx-ng / bcc

A next-generation bcc parser for BlitzMax
zlib License
33 stars 13 forks source link

Question: Why do "release-build" type-structs contain debug struct information? #651

Closed GWRon closed 5 months ago

GWRon commented 6 months ago

Heya,

This question goes out targeting most probably @HurryStarfish and @woollybah.

I wrote a small sample to check if self.x = 20 vs x = 20 create the same code (yes it does, so writing self. ... comes without costs by adding some maybe improved readability regarding local and instance variables). Ok ... distracting ancillary information aside...

This code here:

SuperStrict
Framework Brl.StandardIO

Type TTest
    Field x:Int
    Method Yeah()
        x = 10
        self.x = 20
    End Method
End Type

Generates this C Code:

#include "untitled1.bmx.console.release.linux.x64.h"
struct BBDebugScope_3{int kind; const char *name; BBDebugDecl decls[4]; };
void __m_untitled1_TTest_New(struct _m_untitled1_TTest_obj* o) {
    bbObjectCtor((BBOBJECT)o);
    o->clas = &_m_untitled1_TTest;
    o->__m_untitled1_ttest_x = 0;
}
void __m_untitled1_TTest_Yeah(struct _m_untitled1_TTest_obj* o){
    o->__m_untitled1_ttest_x =10;
    o->__m_untitled1_ttest_x =20;
}
struct BBDebugScope_3 _m_untitled1_TTest_scope ={
    BBDEBUGSCOPE_USERTYPE,
    "TTest",
    {
        {
            BBDEBUGDECL_FIELD,
            "x",
            "i",
            .field_offset=offsetof(struct _m_untitled1_TTest_obj,__m_untitled1_ttest_x)
        },
        {
            BBDEBUGDECL_TYPEMETHOD,
            "New",
            "()",
            .func_ptr=(BBFuncPtr)&__m_untitled1_TTest_New
        },
        {
            BBDEBUGDECL_TYPEMETHOD,
            "Yeah",
            "()",
            .func_ptr=(BBFuncPtr)&__m_untitled1_TTest_Yeah
        },
        {
            BBDEBUGDECL_END
        }
    }
};
struct BBClass__m_untitled1_TTest _m_untitled1_TTest={
    &bbObjectClass,
    bbObjectFree,
    (BBDebugScope*)&_m_untitled1_TTest_scope,
    sizeof(struct _m_untitled1_TTest_obj),
    (void (*)(BBOBJECT))__m_untitled1_TTest_New,
    bbObjectDtor,
    bbObjectToString,
    bbObjectCompare,
    bbObjectSendMessage,
    0,
    0,
    sizeof(BBINT)
    ,0
    ,offsetof(struct _m_untitled1_TTest_obj,__m_untitled1_ttest_x)
    ,__m_untitled1_TTest_Yeah
};

static int _bb_main_inited = 0;
int _bb_main(){
    if (!_bb_main_inited) {
        _bb_main_inited = 1;
        __bb_brl_blitz_blitz();
        __bb_brl_standardio_standardio();
        bbObjectRegisterType((BBCLASS)&_m_untitled1_TTest);
        return 0;
    }
    return 0;
}

And I am wondering why a release build has to contain struct BBDebugScope_3 _m_untitled1_TTest_scope ={ ... Doesn't that mean that each object instance you create (in release builds) also occupies (additionally) a bit memory whose amount depends on the amount of methods/fields a type has ((BBDebugScope*)&_m_untitled1_TTest_scope, sizeof(struct _m_untitled1_TTest_obj),) ?

The question now: is this there for some specific reason (reflection stuff or so) or could the types be "thinned out" by removing the debug stuff (eg only using an "no-debug"-struct which all types share in release builds - only sacrificing some bytes then) ?

HurryStarfish commented 5 months ago

Yes, it is used for Reflection. The debug scope/debug decls describe the shape of the type and its members and BRL.Reflection uses them to build its TTypeId and TMember instances.

Doesn't that mean that each object instance you create (in release builds) also occupies (additionally) a bit memory whose amount depends on the amount of methods/fields a type has

No, that's not the case. One BBDebugScope instance and one BBClass instance is created per type, and the latter contains a pointer to the former ((BBDebugScope*)&_m_untitled1_TTest_scope). In the generated .h file (included at the top of the .c file you quoted), you should find this:

struct _m_untitled1_TTest_obj {
    struct BBClass__m_untitled1_TTest* clas;
    BBINT __m_untitled1_ttest_x;
};

That's what the actual instances of TTest look like - a pointer to the BBClass instance plus the contents of all the fields. The debug scope doesn't take up any additional memory per instance.

GWRon commented 5 months ago

Thanks for the explanation

Will close now (as it is answered)