Csound Csound-dev Csound-tekno Search About

[Csnd-dev] Shared memory for scalar optional arguments to opcodes

Date2024-11-27 07:15
FromEduardo Moguillansky
Subject[Csnd-dev] Shared memory for scalar optional arguments to opcodes
I hope I am understanding something fundamentally wrong about how optional arguments work . I am seeing surprising (for me) behaviour in csound (tested 6.18, 6.19 and develop branch) when an opcode declares optional arguments. All optional arguments which are not passed seem to share the same memory space, which means that they cannot be initialized and should be treated as read-only. Is this the intended behaviour? This holds true for any both i, k types, as long as they are optional:  o/O, p/P, j/J, etc.

Here is some minimal code to prove the point. When this opcode is called in the form

aout testargs ain  ;; optional args left unfilled

The result is

Adresses in0: 1771221120, in1: 1770975480, in2: 1770975480
Values in0: 0.000000, in1: 1.000000, in2: 1.000000

Notice how the k arguments (in1 and in2) share the same memory address.

typedef struct {
    OPDS h;
    MYFLT *out;
    MYFLT *in0;
    MYFLT *in1;
    MYFLT *in2;
} TESTARGS;

static int32_t testargs_init(CSOUND *csound, TESTARGS *p) {
    printf("Addresses in0: %d, in1: %d, in2: %d\n", p->in0, p->in1, p->in2);
    printf("Values in0: %f, in1: %f, in2: %f\n", *p->in0, *p->in1, *p->in2);
    return OK;
}

// for csound 6
static OENTRY localops[] = {
{"testargs", S(TESTARGS), 0, 1, "a", "aPP", (SUBR)testargs_init}
}

// for csound 7
static OENTRY localops[] = {
{"testargs", S(TESTARGS), 0, "a", "aPP", (SUBR)testargs_init}
}



Date2024-11-27 13:34
FromVictor Lazzarini <000010b17ddd988e-dmarc-request@LISTSERV.HEANET.IE>
SubjectRe: [Csnd-dev] [EXTERNAL] [Csnd-dev] Shared memory for scalar optional arguments to opcodes
Should it not be 

{"testargs", S(TESTARGS), 0, "a", "app", (SUBR)testargs_init}

or else

{"testargs", S(TESTARGS), 0, "a", "aPP”,  NULL, (SUBR)testargs_init}

I would expect the compiler to put the correct constants anyway. If the constant
is of the same value (e.g. 1.0), then it would point to the same memory,
since constants are kept in a pool. So what you are seeing is probably
this, since the two arguments use the same default constant. If you run
with -v you’ll probably see the pool etc

I ran a quick check in the debugger using  a1 oscili p4, p5
and saw that the two optional arguments had different addresses and 
correct default values, well otherwise the code would not run at all so it
was actually moot, which just shows how I don’t think things through ;)

Anyway with that code we have

Constants Pool:
  10) -1.000000
  11) 0.000000

The two constants used in the oscili default argument.

So yes, I guess we can confirm your observation.
========================
Prof. Victor Lazzarini
Maynooth University
Ireland

> On 27 Nov 2024, at 07:15, Eduardo Moguillansky  wrote:
> 
> *Warning*
> This email originated from outside of Maynooth University's Mail System. Do not reply, click links or open attachments unless you recognise the sender and know the content is safe.
> I hope I am understanding something fundamentally wrong about how optional arguments work . I am seeing surprising (for me) behaviour in csound (tested 6.18, 6.19 and develop branch) when an opcode declares optional arguments. All optional arguments which are not passed seem to share the same memory space, which means that they cannot be initialized and should be treated as read-only. Is this the intended behaviour? This holds true for any both i, k types, as long as they are optional:  o/O, p/P, j/J, etc.
> 
> Here is some minimal code to prove the point. When this opcode is called in the form
> 
> aout testargs ain  ;; optional args left unfilled
> 
> The result is 
> 
> Adresses in0: 1771221120, in1: 1770975480, in2: 1770975480
> Values in0: 0.000000, in1: 1.000000, in2: 1.000000
> 
> Notice how the k arguments (in1 and in2) share the same memory address. 
> 
> typedef struct {
>     OPDS h;
>     MYFLT *out;
>     MYFLT *in0;
>     MYFLT *in1;
>     MYFLT *in2;
> } TESTARGS;
> 
> static int32_t testargs_init(CSOUND *csound, TESTARGS *p) {
>     printf("Addresses in0: %d, in1: %d, in2: %d\n", p->in0, p->in1, p->in2);
>     printf("Values in0: %f, in1: %f, in2: %f\n", *p->in0, *p->in1, *p->in2);
>     return OK;
> }
> 
> // for csound 6
> static OENTRY localops[] = {
> {"testargs", S(TESTARGS), 0, 1, "a", "aPP", (SUBR)testargs_init}
> }
> 
> // for csound 7
> static OENTRY localops[] = {
> {"testargs", S(TESTARGS), 0, "a", "aPP", (SUBR)testargs_init}
> }
> 
>