[t] Refactor some namespace pmc tests to use throws_like
[parrot.git] / src / gc / alloc_register.c
blob1b8cbbfd67d85ca68740a66b40d4805596f9429f
1 /*
2 Copyright (C) 2001-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/gc/register.c - Register handling routines
9 =head1 DESCRIPTION
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>).
16 =cut
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,
46 ARGMOD(PMC *pmcctx),
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 +----------++----+------+------------+----+
68 ^ ^ ^ ^
69 | | ctx.bp ctx.bp_ps
70 ctx.state opt
71 padding
73 Registers are addressed as usual via the register base pointer ctx.bp.
75 The macro CONTEXT() hides these details
77 =cut
82 #define ALIGNED_CTX_SIZE (((sizeof (Parrot_Context) + NUMVAL_SIZE - 1) \
83 / NUMVAL_SIZE) * NUMVAL_SIZE)
87 =pod
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.
95 =cut
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
109 =over 4
111 =cut
118 =item C<void create_initial_context(PARROT_INTERP)>
120 Creates the interpreter's initial context.
122 =cut
126 void
127 create_initial_context(PARROT_INTERP)
129 ASSERT_ARGS(create_initial_context)
130 static INTVAL num_regs[] = {32, 32, 32, 32};
131 PMC *ignored;
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);
139 UNUSED(ignored);
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.
151 =cut
155 static void
156 clear_regs(PARROT_INTERP, ARGMOD(PMC *pmcctx))
158 ASSERT_ARGS(clear_regs)
159 UINTVAL i;
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.
193 =cut
197 static void
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;
215 if (old) {
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;
224 /* end COW */
225 ctx->recursion_depth = old->recursion_depth;
227 else {
228 ctx->constants = NULL;
229 ctx->warns = 0;
230 ctx->errors = 0;
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>.
250 =cut
254 PARROT_EXPORT
255 PARROT_WARN_UNUSED_RESULT
256 PARROT_CANNOT_RETURN_NULL
257 PMC *
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);
266 /* doesn't change */
267 Parrot_pcc_set_sub(interp, ctx, Parrot_pcc_get_sub(interp, old));
269 /* copy more ? */
270 return ctx;
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).
281 =cut
285 PARROT_EXPORT
286 void
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
300 *number_regs_used)>
302 Calculate size of Context.
304 =cut
307 size_t
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).
329 =cut
333 PARROT_CANNOT_RETURN_NULL
334 PARROT_WARN_UNUSED_RESULT
335 PMC *
336 Parrot_alloc_context(PARROT_INTERP, ARGIN(const INTVAL *number_regs_used),
337 ARGIN_NULLOK(PMC *old))
339 ASSERT_ARGS(Parrot_alloc_context)
340 PMC *pmcctx;
341 Parrot_Context *ctx;
342 void *p;
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);
357 #else
358 ctx = (Parrot_Context *)mem_sys_allocate(to_alloc);
359 #endif
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);
380 return pmcctx;
386 =item C<PMC * Parrot_set_new_context(PARROT_INTERP, const INTVAL
387 *number_regs_used)>
389 Allocates and returns a new context as the current context. Note that the
390 register usage C<n_regs_used> is copied.
392 =cut
396 PARROT_CANNOT_RETURN_NULL
397 PARROT_WARN_UNUSED_RESULT
398 PMC *
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;
407 return ctx;
413 =back
415 =head2 Register Stack Functions
417 =over 4
419 =cut
421 =item C<void Parrot_clear_i(PARROT_INTERP)>
423 Sets all integer registers in the current context to 0.
425 =cut
429 PARROT_EXPORT
430 void
431 Parrot_clear_i(PARROT_INTERP)
433 ASSERT_ARGS(Parrot_clear_i)
434 UINTVAL 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.
446 =cut
450 PARROT_EXPORT
451 void
452 Parrot_clear_s(PARROT_INTERP)
454 ASSERT_ARGS(Parrot_clear_s)
455 UINTVAL i;
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.
467 =cut
471 PARROT_EXPORT
472 void
473 Parrot_clear_p(PARROT_INTERP)
475 ASSERT_ARGS(Parrot_clear_p)
476 UINTVAL i;
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.
488 =cut
492 PARROT_EXPORT
493 void
494 Parrot_clear_n(PARROT_INTERP)
496 ASSERT_ARGS(Parrot_clear_n)
497 UINTVAL i;
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
505 idx)>
507 Get pointer to INTVAL register.
509 =cut
513 PARROT_EXPORT
514 PARROT_CANNOT_RETURN_NULL
515 INTVAL *
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
526 idx)>
528 Get pointer to FLOATVAL register.
530 =cut
534 PARROT_EXPORT
535 PARROT_CANNOT_RETURN_NULL
536 FLOATVAL *
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
547 idx)>
549 Get pointer to STRING register.
551 =cut
555 PARROT_EXPORT
556 PARROT_CANNOT_RETURN_NULL
557 STRING **
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.
571 =cut
575 PARROT_EXPORT
576 PARROT_CANNOT_RETURN_NULL
577 PMC **
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.
591 =cut
594 PARROT_EXPORT
595 UINTVAL
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
605 num)>
607 Set number of used registers of particular type.
609 =cut
612 PARROT_EXPORT
613 void
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.
626 =cut
629 PARROT_EXPORT
630 PARROT_CANNOT_RETURN_NULL
631 Regs_ni*
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.
644 =cut
647 PARROT_EXPORT
648 PARROT_CANNOT_RETURN_NULL
649 void
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.
662 =cut
665 PARROT_EXPORT
666 PARROT_CANNOT_RETURN_NULL
667 Regs_ps*
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.
680 =cut
683 PARROT_EXPORT
684 PARROT_CANNOT_RETURN_NULL
685 void
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;
693 =back
695 =head1 SEE ALSO
697 F<include/parrot/register.h> and F<src/stacks.c>.
699 =cut
705 * Local variables:
706 * c-file-style: "parrot"
707 * End:
708 * vim: expandtab shiftwidth=4: