2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/gc/register.c - Register handling routines
11 Parrot has 4 register sets, one for each of its basic types. The number of
12 registers in each set varies depending on the use counts of the subroutine and
13 is determined by the PASM/PIR compiler in the register allocation pass
14 (F<imcc/reg_alloc.c>).
20 #include "parrot/parrot.h"
21 #include "parrot/register.h"
22 #include "../pmc/pmc_sub.h"
25 /* set CTX_LEAK_DEBUG_FULL to 1 for enhanced context debugging.
26 * When set (1) freed contexts are "poisoned" so that any dangling
27 * references produce segfaults, and (2) contexts are not recycled
28 * so that later allocations don't suddenly restore a dangling
29 * reference to a "working" condition.
31 #define CTX_LEAK_DEBUG_FULL 0
35 /* HEADERIZER HFILE: include/parrot/register.h */
37 /* HEADERIZER BEGIN: static */
38 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
40 static void clear_regs(PARROT_INTERP
, ARGMOD(PMC
*pmcctx
))
41 __attribute__nonnull__(1)
42 __attribute__nonnull__(2)
43 FUNC_MODIFIES(*pmcctx
);
45 static void init_context(PARROT_INTERP
,
47 ARGIN_NULLOK(PMC
*pmcold
))
48 __attribute__nonnull__(1)
49 __attribute__nonnull__(2)
50 FUNC_MODIFIES(*pmcctx
);
52 #define ASSERT_ARGS_clear_regs __attribute__unused__ int _ASSERT_ARGS_CHECK = \
53 PARROT_ASSERT_ARG(interp) \
54 || PARROT_ASSERT_ARG(pmcctx)
55 #define ASSERT_ARGS_init_context __attribute__unused__ int _ASSERT_ARGS_CHECK = \
56 PARROT_ASSERT_ARG(interp) \
57 || PARROT_ASSERT_ARG(pmcctx)
58 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
59 /* HEADERIZER END: static */
63 =head2 Context and register frame layout
65 +----------++----+------+------------+----+
66 | context || N | I | P | S +
67 +----------++----+------+------------+----+
73 Registers are addressed as usual via the register base pointer ctx.bp.
75 The macro CONTEXT() hides these details
82 #define ALIGNED_CTX_SIZE (((sizeof (Parrot_Context) + NUMVAL_SIZE - 1) \
83 / NUMVAL_SIZE) * NUMVAL_SIZE)
89 Round register allocation size up to the nearest multiple of 8. A granularity
90 of 8 is arbitrary, it could have been some bigger power of 2. A "slot" is an
91 index into the free_list array. Each slot in free_list has a linked list of
92 pointers to already allocated contexts available for (re)use. The slot where
93 an available context is stored corresponds to the size of the context.
99 #define SLOT_CHUNK_SIZE 8
101 #define ROUND_ALLOC_SIZE(size) ((((size) + SLOT_CHUNK_SIZE - 1) \
102 / SLOT_CHUNK_SIZE) * SLOT_CHUNK_SIZE)
103 #define CALCULATE_SLOT_NUM(size) ((size) / SLOT_CHUNK_SIZE)
107 =head2 Context and Register Allocation Functions
118 =item C<void create_initial_context(PARROT_INTERP)>
120 Creates the interpreter's initial context.
127 create_initial_context(PARROT_INTERP
)
129 ASSERT_ARGS(create_initial_context
)
130 static INTVAL num_regs
[] = {32, 32, 32, 32};
133 /* Create some initial free_list slots. */
135 #define INITIAL_FREE_SLOTS 8
136 /* For now create context with 32 regs each. Some src tests (and maybe
137 * other extenders) assume the presence of these registers */
138 ignored
= Parrot_set_new_context(interp
, num_regs
);
145 =item C<static void clear_regs(PARROT_INTERP, PMC *pmcctx)>
147 Clears all registers in a context. PMC and STRING registers contain PMCNULL
148 and NULL, respectively. Integer and float registers contain negative flag
149 values, for debugging purposes.
156 clear_regs(PARROT_INTERP
, ARGMOD(PMC
*pmcctx
))
158 ASSERT_ARGS(clear_regs
)
160 Parrot_Context
*ctx
= Parrot_pcc_get_context_struct(interp
, pmcctx
);
162 /* NULL out registers - P/S have to be NULL for GC
164 * if the architecture has 0x := NULL and 0.0 we could memset too
167 for (i
= 0; i
< ctx
->n_regs_used
[REGNO_PMC
]; i
++) {
168 CTX_REG_PMC(pmcctx
, i
) = PMCNULL
;
171 for (i
= 0; i
< ctx
->n_regs_used
[REGNO_STR
]; i
++) {
172 CTX_REG_STR(pmcctx
, i
) = NULL
;
175 if (Interp_debug_TEST(interp
, PARROT_REG_DEBUG_FLAG
)) {
176 /* depending on -D40 we set int and num to be identifiable garbage values */
177 for (i
= 0; i
< ctx
->n_regs_used
[REGNO_INT
]; i
++) {
178 CTX_REG_INT(pmcctx
, i
) = -999;
180 for (i
= 0; i
< ctx
->n_regs_used
[REGNO_NUM
]; i
++) {
181 CTX_REG_NUM(pmcctx
, i
) = -99.9;
189 =item C<static void init_context(PARROT_INTERP, PMC *pmcctx, PMC *pmcold)>
191 Initializes a freshly allocated or recycled context.
198 init_context(PARROT_INTERP
, ARGMOD(PMC
*pmcctx
),
199 ARGIN_NULLOK(PMC
*pmcold
))
201 ASSERT_ARGS(init_context
)
202 Parrot_Context
*ctx
= Parrot_pcc_get_context_struct(interp
, pmcctx
);
203 Parrot_Context
*old
= Parrot_pcc_get_context_struct(interp
, pmcold
);
205 ctx
->current_results
= NULL
;
206 ctx
->results_signature
= NULL
;
207 ctx
->lex_pad
= PMCNULL
;
208 ctx
->outer_ctx
= NULL
;
209 ctx
->current_cont
= NULL
;
210 ctx
->current_object
= NULL
;
211 ctx
->handlers
= PMCNULL
;
212 ctx
->caller_ctx
= NULL
;
213 ctx
->pred_offset
= 0;
216 /* some items should better be COW copied */
217 ctx
->constants
= old
->constants
;
218 ctx
->warns
= old
->warns
;
219 ctx
->errors
= old
->errors
;
220 ctx
->trace_flags
= old
->trace_flags
;
221 ctx
->pred_offset
= old
->pred_offset
;
222 ctx
->current_HLL
= old
->current_HLL
;
223 ctx
->current_namespace
= old
->current_namespace
;
225 ctx
->recursion_depth
= old
->recursion_depth
;
228 ctx
->constants
= NULL
;
231 ctx
->trace_flags
= 0;
232 ctx
->pred_offset
= 0;
233 ctx
->current_HLL
= 0;
234 ctx
->current_namespace
= PMCNULL
;
235 ctx
->recursion_depth
= 0;
238 /* other stuff is set inside Sub.invoke */
239 clear_regs(interp
, pmcctx
);
245 =item C<PMC * Parrot_push_context(PARROT_INTERP, const INTVAL *n_regs_used)>
247 Creates and sets the current context to a new context, remembering the old
248 context in C<caller_ctx>. Suitable to use with C<Parrot_pop_context>.
255 PARROT_WARN_UNUSED_RESULT
256 PARROT_CANNOT_RETURN_NULL
258 Parrot_push_context(PARROT_INTERP
, ARGIN(const INTVAL
*n_regs_used
))
260 ASSERT_ARGS(Parrot_push_context
)
261 PMC
* const old
= CURRENT_CONTEXT(interp
);
262 PMC
* const ctx
= Parrot_set_new_context(interp
, n_regs_used
);
264 Parrot_pcc_set_caller_ctx(interp
, ctx
, old
);
267 Parrot_pcc_set_sub(interp
, ctx
, Parrot_pcc_get_sub(interp
, old
));
276 =item C<void Parrot_pop_context(PARROT_INTERP)>
278 Frees the context created with C<Parrot_push_context> and restores the previous
279 context (the caller context).
287 Parrot_pop_context(PARROT_INTERP
)
289 ASSERT_ARGS(Parrot_pop_context
)
290 PMC
* const ctx
= CURRENT_CONTEXT(interp
);
291 PMC
* const old
= Parrot_pcc_get_caller_ctx(interp
, ctx
);
293 /* restore old, set cached interpreter base pointers */
294 CURRENT_CONTEXT(interp
) = old
;
299 =item C<size_t Parrot_pcc_calculate_context_size(PARROT_INTERP, const UINTVAL
302 Calculate size of Context.
308 Parrot_pcc_calculate_context_size(SHIM_INTERP
, ARGIN(const UINTVAL
*number_regs_used
))
310 ASSERT_ARGS(Parrot_pcc_calculate_context_size
)
312 return ALIGNED_CTX_SIZE
+ ROUND_ALLOC_SIZE(
313 sizeof (INTVAL
) * number_regs_used
[REGNO_INT
] +
314 sizeof (FLOATVAL
) * number_regs_used
[REGNO_NUM
] +
315 sizeof (STRING
*) * number_regs_used
[REGNO_STR
] +
316 sizeof (PMC
*) * number_regs_used
[REGNO_PMC
]);
321 =item C<PMC * Parrot_alloc_context(PARROT_INTERP, const INTVAL
322 *number_regs_used, PMC *old)>
324 Allocates and returns a new context. Does not set this new context as the
325 current context. Note that the register usage C<n_regs_used> is copied. Use
326 the init flag to indicate whether you want to initialize the new context
327 (setting its default values and clearing its registers).
333 PARROT_CANNOT_RETURN_NULL
334 PARROT_WARN_UNUSED_RESULT
336 Parrot_alloc_context(PARROT_INTERP
, ARGIN(const INTVAL
*number_regs_used
),
337 ARGIN_NULLOK(PMC
*old
))
339 ASSERT_ARGS(Parrot_alloc_context
)
344 const size_t size_i
= sizeof (INTVAL
) * number_regs_used
[REGNO_INT
];
345 const size_t size_n
= sizeof (FLOATVAL
) * number_regs_used
[REGNO_NUM
];
346 const size_t size_s
= sizeof (STRING
*) * number_regs_used
[REGNO_STR
];
347 const size_t size_p
= sizeof (PMC
*) * number_regs_used
[REGNO_PMC
];
349 const size_t size_nip
= size_n
+ size_i
+ size_p
;
350 const size_t all_regs_size
= size_n
+ size_i
+ size_p
+ size_s
;
351 const size_t reg_alloc
= ROUND_ALLOC_SIZE(all_regs_size
);
353 const size_t to_alloc
= reg_alloc
+ ALIGNED_CTX_SIZE
;
355 #ifdef GC_USE_FIXED_SIZE_ALLOCATOR
356 ctx
= (Parrot_Context
*)Parrot_gc_allocate_fixed_size_storage(interp
, to_alloc
);
358 ctx
= (Parrot_Context
*)mem_sys_allocate(to_alloc
);
361 ctx
->n_regs_used
[REGNO_INT
] = number_regs_used
[REGNO_INT
];
362 ctx
->n_regs_used
[REGNO_NUM
] = number_regs_used
[REGNO_NUM
];
363 ctx
->n_regs_used
[REGNO_STR
] = number_regs_used
[REGNO_STR
];
364 ctx
->n_regs_used
[REGNO_PMC
] = number_regs_used
[REGNO_PMC
];
366 /* regs start past the context */
367 p
= (void *) ((char *)ctx
+ ALIGNED_CTX_SIZE
);
369 /* ctx.bp points to I0, which has Nx on the left */
370 ctx
->bp
.regs_i
= (INTVAL
*)((char *)p
+ size_n
);
372 /* ctx.bp_ps points to S0, which has Px on the left */
373 ctx
->bp_ps
.regs_s
= (STRING
**)((char *)p
+ size_nip
);
375 pmcctx
= pmc_new(interp
, enum_class_Context
);
376 VTABLE_set_pointer(interp
, pmcctx
, ctx
);
378 init_context(interp
, pmcctx
, old
);
386 =item C<PMC * Parrot_set_new_context(PARROT_INTERP, const INTVAL
389 Allocates and returns a new context as the current context. Note that the
390 register usage C<n_regs_used> is copied.
396 PARROT_CANNOT_RETURN_NULL
397 PARROT_WARN_UNUSED_RESULT
399 Parrot_set_new_context(PARROT_INTERP
, ARGIN(const INTVAL
*number_regs_used
))
401 ASSERT_ARGS(Parrot_set_new_context
)
402 PMC
*old
= CURRENT_CONTEXT(interp
);
403 PMC
*ctx
= Parrot_alloc_context(interp
, number_regs_used
, old
);
405 CURRENT_CONTEXT(interp
) = ctx
;
415 =head2 Register Stack Functions
421 =item C<void Parrot_clear_i(PARROT_INTERP)>
423 Sets all integer registers in the current context to 0.
431 Parrot_clear_i(PARROT_INTERP
)
433 ASSERT_ARGS(Parrot_clear_i
)
435 for (i
= 0; i
< Parrot_pcc_get_regs_used(interp
, CURRENT_CONTEXT(interp
), REGNO_INT
); ++i
)
436 REG_INT(interp
, i
) = 0;
442 =item C<void Parrot_clear_s(PARROT_INTERP)>
444 Sets all STRING registers in the current context to NULL.
452 Parrot_clear_s(PARROT_INTERP
)
454 ASSERT_ARGS(Parrot_clear_s
)
456 for (i
= 0; i
< Parrot_pcc_get_regs_used(interp
, CURRENT_CONTEXT(interp
), REGNO_STR
); ++i
)
457 REG_STR(interp
, i
) = NULL
;
463 =item C<void Parrot_clear_p(PARROT_INTERP)>
465 Sets all PMC registers in the current context to NULL.
473 Parrot_clear_p(PARROT_INTERP
)
475 ASSERT_ARGS(Parrot_clear_p
)
477 for (i
= 0; i
< Parrot_pcc_get_regs_used(interp
, CURRENT_CONTEXT(interp
), REGNO_PMC
); ++i
)
478 REG_PMC(interp
, i
) = PMCNULL
;
484 =item C<void Parrot_clear_n(PARROT_INTERP)>
486 Sets all number registers in the current context to 0.0.
494 Parrot_clear_n(PARROT_INTERP
)
496 ASSERT_ARGS(Parrot_clear_n
)
498 for (i
= 0; i
< Parrot_pcc_get_regs_used(interp
, CURRENT_CONTEXT(interp
), REGNO_NUM
); ++i
)
499 REG_NUM(interp
, i
) = 0.0;
504 =item C<INTVAL * Parrot_pcc_get_INTVAL_reg(PARROT_INTERP, PMC *ctx, UINTVAL
507 Get pointer to INTVAL register.
514 PARROT_CANNOT_RETURN_NULL
516 Parrot_pcc_get_INTVAL_reg(PARROT_INTERP
, ARGIN(PMC
*ctx
), UINTVAL idx
)
518 ASSERT_ARGS(Parrot_pcc_get_INTVAL_reg
)
519 PARROT_ASSERT(Parrot_pcc_get_regs_used(interp
, ctx
, REGNO_INT
) > idx
);
520 return &(Parrot_pcc_get_context_struct(interp
, ctx
)->bp
.regs_i
[idx
]);
525 =item C<FLOATVAL * Parrot_pcc_get_FLOATVAL_reg(PARROT_INTERP, PMC *ctx, UINTVAL
528 Get pointer to FLOATVAL register.
535 PARROT_CANNOT_RETURN_NULL
537 Parrot_pcc_get_FLOATVAL_reg(PARROT_INTERP
, ARGIN(PMC
*ctx
), UINTVAL idx
)
539 ASSERT_ARGS(Parrot_pcc_get_FLOATVAL_reg
)
540 PARROT_ASSERT(Parrot_pcc_get_regs_used(interp
, ctx
, REGNO_NUM
) > idx
);
541 return &(Parrot_pcc_get_context_struct(interp
, ctx
)->bp
.regs_n
[-1L - idx
]);
546 =item C<STRING ** Parrot_pcc_get_STRING_reg(PARROT_INTERP, PMC *ctx, UINTVAL
549 Get pointer to STRING register.
556 PARROT_CANNOT_RETURN_NULL
558 Parrot_pcc_get_STRING_reg(PARROT_INTERP
, ARGIN(PMC
*ctx
), UINTVAL idx
)
560 ASSERT_ARGS(Parrot_pcc_get_STRING_reg
)
561 PARROT_ASSERT(Parrot_pcc_get_regs_used(interp
, ctx
, REGNO_STR
) > idx
);
562 return &(Parrot_pcc_get_context_struct(interp
, ctx
)->bp_ps
.regs_s
[idx
]);
567 =item C<PMC ** Parrot_pcc_get_PMC_reg(PARROT_INTERP, PMC *ctx, UINTVAL idx)>
569 Get pointer to PMC register.
576 PARROT_CANNOT_RETURN_NULL
578 Parrot_pcc_get_PMC_reg(PARROT_INTERP
, ARGIN(PMC
*ctx
), UINTVAL idx
)
580 ASSERT_ARGS(Parrot_pcc_get_PMC_reg
)
581 PARROT_ASSERT(Parrot_pcc_get_regs_used(interp
, ctx
, REGNO_PMC
) > idx
);
582 return &(Parrot_pcc_get_context_struct(interp
, ctx
)->bp_ps
.regs_p
[-1L - idx
]);
587 =item C<UINTVAL Parrot_pcc_get_regs_used(PARROT_INTERP, PMC *ctx, int type)>
589 Return number of used registers of particular type.
596 Parrot_pcc_get_regs_used(PARROT_INTERP
, ARGIN(PMC
*ctx
), int type
)
598 ASSERT_ARGS(Parrot_pcc_get_regs_used
)
599 return Parrot_pcc_get_context_struct(interp
, ctx
)->n_regs_used
[type
];
604 =item C<void Parrot_pcc_set_regs_used(PARROT_INTERP, PMC *ctx, int type, INTVAL
607 Set number of used registers of particular type.
614 Parrot_pcc_set_regs_used(PARROT_INTERP
, ARGIN(PMC
*ctx
), int type
, INTVAL num
)
616 ASSERT_ARGS(Parrot_pcc_set_regs_used
)
617 Parrot_pcc_get_context_struct(interp
, ctx
)->n_regs_used
[type
] = num
;
622 =item C<Regs_ni* Parrot_pcc_get_regs_ni(PARROT_INTERP, PMC *ctx)>
624 Get pointer to FLOANFAL and INTVAL registers.
630 PARROT_CANNOT_RETURN_NULL
632 Parrot_pcc_get_regs_ni(PARROT_INTERP
, ARGIN(PMC
*ctx
))
634 ASSERT_ARGS(Parrot_pcc_get_regs_ni
)
635 return &(Parrot_pcc_get_context_struct(interp
, ctx
)->bp
);
640 =item C<void Parrot_pcc_set_regs_ni(PARROT_INTERP, PMC *ctx, Regs_ni *bp)>
642 Copy Regs_ni into Context.
648 PARROT_CANNOT_RETURN_NULL
650 Parrot_pcc_set_regs_ni(PARROT_INTERP
, ARGIN(PMC
*ctx
), ARGIN(Regs_ni
*bp
))
652 ASSERT_ARGS(Parrot_pcc_set_regs_ni
)
653 Parrot_pcc_get_context_struct(interp
, ctx
)->bp
= *bp
;
658 =item C<Regs_ps* Parrot_pcc_get_regs_ps(PARROT_INTERP, PMC *ctx)>
660 Get pointer to PMC and STRING registers.
666 PARROT_CANNOT_RETURN_NULL
668 Parrot_pcc_get_regs_ps(PARROT_INTERP
, ARGIN(PMC
*ctx
))
670 ASSERT_ARGS(Parrot_pcc_get_regs_ps
)
671 return &(Parrot_pcc_get_context_struct(interp
, ctx
)->bp_ps
);
676 =item C<void Parrot_pcc_set_regs_ps(PARROT_INTERP, PMC *ctx, Regs_ps *bp_ps)>
678 Copy Regs_ps into Context.
684 PARROT_CANNOT_RETURN_NULL
686 Parrot_pcc_set_regs_ps(PARROT_INTERP
, ARGIN(PMC
*ctx
), ARGIN(Regs_ps
*bp_ps
))
688 ASSERT_ARGS(Parrot_pcc_set_regs_ps
)
689 Parrot_pcc_get_context_struct(interp
, ctx
)->bp_ps
= *bp_ps
;
697 F<include/parrot/register.h> and F<src/stacks.c>.
706 * c-file-style: "parrot"
708 * vim: expandtab shiftwidth=4: