Eeep. I was struck by this recent code fragment /* calling convention says that receiver should be in P2 and method in P0 */ interpreter->ctx.pmc_reg.registers[0] = method; interpreter->ctx.pmc_reg.registers[2] = $1; interpreter->ctx.string_reg.registers[0] = $2; which might be rewritten as P0 = method; P2 = $1; S0 = $2; with just a little bit of macroness.
So I wandered off to look at the state of interpreter->ctx.FOO_reg.registers usage in parrot. #### INT_REG #### A macro set # define INT_REG(x) interpreter->ctx.int_reg.registers[x] # define NUM_REG(x) interpreter->ctx.num_reg.registers[x] # define STR_REG(x) interpreter->ctx.string_reg.registers[x] # define PMC_REG(x) interpreter->ctx.pmc_reg.registers[x] is identically defined and used within two files, jit/i386/jit_emit.h and build_nativecall.pl and thus also its generated nci.c jit/i386/jit_emit.h also has one similar but unmacroed access. #### IREG #### A second macro set is variously defined as #define IREG(i) interpreter->ctx.int_reg.registers[i] #define NREG(i) interpreter->ctx.num_reg.registers[i] #define PREG(i) interpreter->ctx.pmc_reg.registers[i] #define SREG(i) interpreter->ctx.string_reg.registers[i] or #define IREG(i) interpreter->ctx.int_reg.registers[cur_opcode[i]] #define NREG(i) interpreter->ctx.num_reg.registers[cur_opcode[i]] #define PREG(i) interpreter->ctx.pmc_reg.registers[cur_opcode[i]] #define SREG(i) interpreter->ctx.string_reg.registers[cur_opcode[i]] or #define IREG(i) interpreter->ctx.int_reg.registers[jit_info->cur_op[i]] #define NREG(i) interpreter->ctx.num_reg.registers[jit_info->cur_op[i]] #define PREG(i) interpreter->ctx.pmc_reg.registers[jit_info->cur_op[i]] #define SREG(i) interpreter->ctx.string_reg.registers[jit_info->cur_op[i]] by lib/Parrot/OpTrans/Compiled.pm lib/Parrot/OpTrans/CGoto.pm and lib/Parrot/OpTrans/C.pm jit2h.pl respectively, and thus as #define IREG(i) interpreter->ctx.int_reg.registers[cur_opcode[i]] and #define IREG(i) interpreter->ctx.int_reg.registers[jit_info->cur_op[i]] in core_ops.c and core_ops_cg.c jit_cpu.c respectively, and used in those three files. Hmm... so is Compiled.pm maybe using a the same names for a different concept? #### unmacroed #### Unmacroed usage is done about 72 times (or 81 including generated files) in 18 (or 26) files. classes/compiler.pmc core.ops debug.c dod.c embed.c interpreter.c jit/alpha/jit_emit.h jit/arm/jit_emit.h jit.c jit_debug.c jit/i386/jit_emit.h jit/ppc/jit_emit.h jit/sun4/jit_emit.h key.c languages/imcc/optimizer.c pbc2c.pl register.c trace.c and classes/compiler.c core_ops.c core_ops_cg.c core_ops_cgp.c core_ops_prederef.c core_ops_switch.c include/parrot/jit_emit.h lib/Parrot/OpLib/core.pm Lots'o cut-and-paste. #### variants #### ->registers is used 4 times in debug.c And 4 times bogusly in ops2cgc.pl, like 'i' => "interpreter->ctx.int_reg->registers[cur_opcode[%ld]]" Perhaps this should be fixed? Non-"ctx" .registers are used 7 times in 2 files, dod.c register.c Specifically, dod.c: if (cur_chunk->PReg[j].registers[i]) { dod.c: (PObj *)cur_chunk->PReg[j].registers[i]); dod.c: Buffer *reg = (Buffer *)cur_chunk->SReg[j].registers[i]; register.c: &top->IReg[top->used].registers[NUM_REGISTERS/2], register.c: &top->SReg[top->used].registers[NUM_REGISTERS/2], register.c: &top->NReg[top->used].registers[NUM_REGISTERS/2], register.c: &top->PReg[top->used].registers[NUM_REGISTERS/2], Non-"interpreter" ctx registers are used in 12 times in 3 files, jit/sun4/jit_emit.h languages/imcc/optimizer.c method_util.c Specifically, jit/sun4/jit_emit.h: #define Parrot_jit_regbase_ptr(i) &((i)->ctx.int_reg.registers[0]) languages/imcc/optimizer.c: sprintf(b, INTVAL_FMT, interp->ctx.int_reg.registers[0]); languages/imcc/optimizer.c: sprintf(b, fmt, interp->ctx.num_reg.registers[0]); method_util.c: interp->ctx.int_reg.registers[0] = 0; /* no prototype */ method_util.c: interp->ctx.int_reg.registers[1] = argc; method_util.c: INTVAL nret = interp->ctx.int_reg.registers[1]; method_util.c: interp->ctx.int_reg.registers[0] = 1; /* with proto */ method_util.c: push_these(npush, interp, interp->ctx.int_reg.registers, intc, intv[i], method_util.c: push_these(npush, interp, interp->ctx.num_reg.registers, numc, numv[i], method_util.c: push_these(npush, interp, interp->ctx.string_reg.registers, strc, method_util.c: push_these(npush, interp, interp->ctx.pmc_reg.registers, pmcc, method_util.c: interp->ctx.int_reg.registers[1] = npush; Though only 8 of the 12 times are individual register accesses. Of these 8, the 5 in method_util.c result from its saying "interp" rather than "interpreter" (actually, it uses both conventions, sigh). Perhaps method_util.c should be "interpreter"-ized? ctx.FOO_reg and FOO_reg.registers are used whole 34 times in 6 files. debug.c debug.ops method_util.c ops2cgc.pl register.c trace.c There are about 166 uses of interpreter->ctx. which are not FOO_reg.registers. #### so what? #### The vast majority of register accesses (~90%) are simply cut-and-pastes of 4 interpreter->ctx.FOO_reg.registers[BAR] strings. Register access is a high profile user concept. It looks like register access is a plausible place to make an abstraction cut. The only(?) downside of doing so is decoupling register access interpreter->ctx.FOO_reg.registers[BAR] from the various interpreter->ctx.SOMETHING_ELSE expressions. But, this decoupling has _already_ occurred in several files. So... I suggest existing register access be replaced with a new macro set #define REG_INT(x) interpreter->ctx.int_reg.registers[x] #define REG_NUM(x) interpreter->ctx.num_reg.registers[x] #define REG_STR(x) interpreter->ctx.string_reg.registers[x] #define REG_PMC(x) interpreter->ctx.pmc_reg.registers[x] (Then jit/i386/jit_emit.h and build_nativecall.pl can be synced by flopping FOO_REG's to REG_FOO's.) I suggest REG_PMC(1) is clearer than PMC_REG(1), as it places the most variable information together. Like P1, or CLUTTER_P(1), rather than P_CLUTTER(1). At a minimum, it would be nice for some register access macro set to be globally available. While REG_PMC(0) = method; REG_PMC(2) = $1; REG_STR(0) = $2; is not as clear as P0 = method; P2 = $1; S0 = $2; it sure beats interpreter->ctx.pmc_reg.registers[0] = method; interpreter->ctx.pmc_reg.registers[2] = $1; interpreter->ctx.string_reg.registers[0] = $2; No? Mitchell