File: vcompiler.h

package info (click to toggle)
psyco 1.6-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 1,824 kB
  • ctags: 3,237
  • sloc: ansic: 23,895; python: 5,646; perl: 1,309; makefile: 165; sh: 1
file content (760 lines) | stat: -rw-r--r-- 29,311 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
 /***************************************************************/
/***           Structures used by the compiler part            ***/
 /***************************************************************/

#ifndef _VCOMPILER_H
#define _VCOMPILER_H

#include "psyco.h"
#include <iencoding.h>
#include "blockalloc.h"
#include "Python/pycheader.h"


/*****************************************************************/
 /***   Definition of the "sources" of vinfo_t structures       ***/


/* A "source" defines the stage of the variable (run-time,
   compile-time or virtual-time), and gives information about
   the value of the variable */
typedef long Source;   /* Implemented as a bitfield 32-bit integer. */

/* the next typedefs are for documentation purposes only, as the C compiler
   will not make any difference between them all */
typedef long RunTimeSource;
typedef long CompileTimeSource;
typedef long VirtualTimeSource;

#define RunTime         0
#define CompileTime     1    /* a.k.a. "Known value" */
#define VirtualTime     2
#define TimeMask        (CompileTime | VirtualTime)

PSY_INLINE bool is_runtime(Source s)     { return (s & TimeMask) == RunTime; }
PSY_INLINE bool is_compiletime(Source s) { return (s & CompileTime) != 0; }
PSY_INLINE bool is_virtualtime(Source s) { return (s & VirtualTime) != 0; }
PSY_INLINE long gettime(Source s)        { return s & TimeMask; }
#define CHKTIME(src, time)           extra_assert(gettime(src) == (time))


/************************ Run-time sources *******************************
 *
 * If the last two bits of 'source' are 'RunTime', we have a run-time value.
 * The rest of 'source' encodes both the position of the value in the stack
 * (or StackNone) and the register holding this value (or REG_NONE).
 *
 **/

#if REG_TOTAL > 8
# error "fix the masks below"
#endif

/* flags */
#define RunTime_StackMask    0x01FFFFFC
#define RunTime_StackMax     RunTime_StackMask
#define RunTime_StackNone    0
#define RunTime_RegMask      0xF0000000
#define RunTime_NoRef        0x08000000
#define RunTime_NonNeg       0x04000000
#define RunTime_Megamorphic  0x02000000
#define RunTime_FlagsMask    RunTime_NoRef

/* construction */
PSY_INLINE RunTimeSource RunTime_New1(int stack_position,
#if REG_TOTAL > 0
				  reg_t reg,
#endif
				  bool ref, bool nonneg)
{
	long result = RunTime + stack_position;
#if REG_TOTAL > 0
	result += (long) reg << 28;
#endif
	if (!ref)
		result += RunTime_NoRef;
	if (nonneg)
		result += RunTime_NonNeg;
	return (RunTimeSource) result;
}
#if REG_TOTAL > 0
# define RunTime_NewStack(stackpos, ref, nonneg)		\
            RunTime_New1(stackpos, REG_NONE, ref, nonneg)
# define RunTime_New(reg, ref, nonneg)				\
            RunTime_New1(RunTime_StackNone, reg, ref, nonneg)
#else
# define RunTime_NewStack  RunTime_New1
#endif

/* field inspection */
PSY_INLINE bool has_rtref(Source s) {
	return (s & (TimeMask|RunTime_NoRef)) == RunTime;
}
#if REG_TOTAL > 0
PSY_INLINE reg_t getreg(RunTimeSource s)     { CHKTIME(s, RunTime); return (reg_t)(s >> 28); }
#endif
PSY_INLINE bool is_reg_none(RunTimeSource s) { CHKTIME(s, RunTime); return s < 0; }
PSY_INLINE int getstack(RunTimeSource s)     { CHKTIME(s, RunTime); return s & RunTime_StackMask; }
PSY_INLINE bool is_runtime_with_reg(Source s) {
  return (s & (TimeMask|(1<<31))) == 0;
}
PSY_INLINE bool is_rtnonneg(RunTimeSource s) { CHKTIME(s, RunTime); return s & RunTime_NonNeg; }


/* mutation */
PSY_INLINE RunTimeSource remove_rtref(RunTimeSource s) { CHKTIME(s, RunTime); return s | RunTime_NoRef; }
PSY_INLINE RunTimeSource add_rtref(RunTimeSource s)    { CHKTIME(s, RunTime); return s & ~RunTime_NoRef; }
#if REG_TOTAL > 0
PSY_INLINE RunTimeSource set_rtreg_to(RunTimeSource s, reg_t newreg) {
	CHKTIME(s, RunTime);
	return (s & ~RunTime_RegMask) | ((long) newreg << 28);
}
PSY_INLINE RunTimeSource set_rtreg_to_none(RunTimeSource s) {
	CHKTIME(s, RunTime);
	return s | ((long) REG_NONE << 28);
}
#endif
PSY_INLINE RunTimeSource set_rtstack_to(RunTimeSource s, int stack) {
	CHKTIME(s, RunTime);
	extra_assert(getstack(s) == RunTime_StackNone);
	return s | stack;
}
PSY_INLINE RunTimeSource set_rtstack_to_none(RunTimeSource s) {
	CHKTIME(s, RunTime);
	return s & ~RunTime_StackMask;
}
PSY_INLINE RunTimeSource set_rtnonneg(RunTimeSource s) {
	CHKTIME(s, RunTime);
	return s | RunTime_NonNeg;
}


/************************ Compile-time sources *******************************
 *
 * if the last two bits of 'source' are 'CompileTime',
 * the rest of 'source' points to a 'source_known_t' structure:
 *
 **/
typedef struct {
	long refcount1_flags; /* flags and reference counter */
	long value;           /* compile-time known value */
} source_known_t;

/* flags for source_known_t::refcount1_flags: */

/* flag added when producing code that relies
   essentially on this value to be constant */
#define SkFlagFixed   0x01

/* value is a PyObject* and holds a reference */
#define SkFlagPyObj   0x02

/* first unused flag */
#define SkFlagEnd     0x04
#define SkFlagMask    (SkFlagEnd-1)

/* refcounting */
EXTERNFN void sk_release(source_known_t *sk);
PSY_INLINE void sk_incref(source_known_t *sk) { sk->refcount1_flags += SkFlagEnd; }
PSY_INLINE void sk_decref(source_known_t *sk) {
	if ((sk->refcount1_flags -= SkFlagEnd)<0) sk_release(sk);
}

/* construction */
BLOCKALLOC_INTERFACE(sk, source_known_t)

PSY_INLINE source_known_t* sk_new(long v, long flags) {
	source_known_t* sk = psyco_llalloc_sk();
	sk->refcount1_flags = flags;
	sk->value = v;
	return sk;
}
PSY_INLINE void sk_delete(source_known_t* sk) {
	psyco_llfree_sk(sk);
}


/* Compile-time sources */
/* construction */
PSY_INLINE CompileTimeSource CompileTime_NewSk(source_known_t* newsource) {
	extra_assert((((long) newsource) & TimeMask) == 0);
	return (CompileTimeSource) (((char*) newsource) + CompileTime);
}
PSY_INLINE CompileTimeSource CompileTime_New(long value) {
	return CompileTime_NewSk(sk_new(value, 0));
}

/* inspection */
PSY_INLINE source_known_t* CompileTime_Get(CompileTimeSource s) {
	CHKTIME(s, CompileTime);
	return (source_known_t*)(((char*) s) - CompileTime);
}
PSY_INLINE CompileTimeSource set_ct_value(CompileTimeSource s, long v) {
	source_known_t* sk = CompileTime_Get(s);
        extra_assert((sk->refcount1_flags & SkFlagPyObj) == 0);
	if (sk->refcount1_flags < SkFlagEnd) {
		sk->value = v; /* reuse object when only one reference */
		return s;
	}
	else {
		sk_decref(sk);
		return CompileTime_NewSk(sk_new(v, sk->refcount1_flags &
						SkFlagMask));
	}
}


/************************ Virtual-time sources *******************************
 *
 * if the last two bits of 'source' are VIRTUAL_TIME,
 * the rest of 'source' points to a 'source_virtual_t' structure (in psyco.h).
 * Description of the fields of source_virtual_t:
 *
 *  compute_fn_t compute_fn;
 *     the function to be called to move the vinfo_t out of virtual-time.
 *
 *  direct_compute_fn_t direct_compute_fn
 *     a non-meta function that computes the PyObject* out of raw data.
 *     'compute_fn' is the meta version of 'direct_compute_fn'.
 *
 *  long pyobject_mask
 *     a bitfield, one bit per item in the vinfo_t's array: the bit is set
 *     to 1 if the array item represents a PyObject (and hence needs to be
 *     forced to have a reference if the virtual object escapes the current
 *     scope, which so far is only possible through compactobject attrs).
 *
 *  signed char nested_weight[2];
 *     a value > 0 prevents infinite nesting of virtual 'vinfo_t's inside
 *     of other virtual 'vinfo_t's: the sum of all 'nested_weight' fields
 *     of a chain of nested 'vinfo_t's should always be less than
 *     NESTED_WEIGHT_END. There are two values because limiting some kind
 *     of virtual 'vinfo_t's is more important across function calls than
 *     inside the same function.
 **/
#define NESTED_WEIGHT_END   15
#define NWI_NORMAL          0  /* use nested_weight[0] */
#define NWI_FUNCALL         1  /* use nested_weight[1] */
#define INIT_SVIRTUAL(sv, fn, directfn, objmask, w_normal, w_funcall) do { \
	(sv).compute_fn = fn;                                              \
	(sv).direct_compute_fn = directfn;                                 \
	(sv).pyobject_mask = objmask;                                      \
	(sv).nested_weight[NWI_NORMAL] = w_normal;                         \
	(sv).nested_weight[NWI_FUNCALL] = w_funcall;                       \
} while (0)
#define INIT_SVIRTUAL_NOCALL(sv, fn, w_normal)                             \
		INIT_SVIRTUAL(sv, fn, NULL, 0, w_normal, NW_FORCE)
#define SVIRTUAL_MUTABLE(sv)	((sv)->nested_weight[NWI_FUNCALL] == NW_FORCE)

/* some weights for common virtual-time objects, grouped here to better
   show their relative importance. A careful tuning is required to avoid
   code size explosion. (The following figures are only a guess; some
   real-code testing would be welcome.) */
#define NW_VLISTS               5
#define NW_TUPLES_NORMAL        4
#define NW_TUPLES_FUNCALL       4
#define NW_STRSLICES_NORMAL     5
#define NW_STRSLICES_FUNCALL    9
#define NW_CATSTRS_NORMAL       4  /* catstrs also have a vlist internally */
#define NW_CATSTRS_FUNCALL      7
#define NW_BUFSTRS_NORMAL       5
#define NW_FORCE                NESTED_WEIGHT_END  /* always force */

/* construction */
PSY_INLINE VirtualTimeSource VirtualTime_New(source_virtual_t* sv) {
	extra_assert((((long) sv) & TimeMask) == 0);
	return (VirtualTimeSource) (((char*) sv) + VirtualTime);
}

/* inspection */
PSY_INLINE source_virtual_t* VirtualTime_Get(VirtualTimeSource s) {
	CHKTIME(s, VirtualTime);
	return (source_virtual_t*)(((char*) s) - VirtualTime);
}


EXTERNVAR source_virtual_t psyco_vsource_not_important;

#define SOURCE_NOT_IMPORTANT    VirtualTime_New(&psyco_vsource_not_important)
#define SOURCE_DUMMY            RunTime_NewStack(RunTime_StackNone, false, false)
#define SOURCE_DUMMY_WITH_REF   RunTime_NewStack(RunTime_StackNone, true, false)
#define SOURCE_ERROR            ((Source) -1)



 /***************************************************************/
/***      Definition of the fundamental vinfo_t structure      ***/
 /***************************************************************/


/* 'array' fields are never NULL, but point to a fraction of vinfo_array_t
 * in which 'count' is 0, like 'NullArray'.
 * This allows 'array->count' to always return a sensible value.
 * Invariant: the array is dynamically allocated if and only if 'array->count'
 * is greater than 0.
 */
EXTERNVAR const long psyco_zero;
#define NullArrayAt(zero_variable)  ((vinfo_array_t*)(&(zero_variable)))
#define NullArray                   NullArrayAt(psyco_zero)


struct vinfo_array_s {
	int count;
	vinfo_t* items[7];  /* always variable-sized */
};

/* construction */
EXTERNFN vinfo_array_t* array_grow1(vinfo_array_t* array, int ncount);
PSY_INLINE void array_release(vinfo_array_t* array) {
	if (array->count > 0) PyMem_FREE(array);
}
PSY_INLINE vinfo_array_t* array_new(int ncount) {
	if (ncount > 0)
		return array_grow1(NullArray, ncount);
	else
		return NullArray;
}


/* 'vinfo_t' defines for the compiler the stage of a
   variable and where it is found. It is a wrapper around a 'Source'.
   For pointers to structures, 'array' is used to decompose the structure
   fields into 'vinfo_t'-described variables which can in turn
   be at various stages. */
struct vinfo_s {
	int refcount;           /* reference counter */
	Source source;
	vinfo_array_t* array;   /* substructure variables or a NullArray */
	vinfo_t* tmp;           /* internal use of the dispatcher */
};

/* construction */
BLOCKALLOC_INTERFACE(vinfo, vinfo_t)

PSY_INLINE vinfo_t* vinfo_new(Source src) {
	vinfo_t* vi = psyco_llalloc_vinfo();
	vi->refcount = 1;
	vi->source = src;
	vi->array = NullArray;
	return vi;
}
PSY_INLINE vinfo_t* vinfo_new_skref(Source src) {
	if (is_compiletime(src)) sk_incref(CompileTime_Get(src));
	return vinfo_new(src);
}

/* copy constructor */
EXTERNFN vinfo_t* vinfo_copy(vinfo_t* vi);

/* refcounting */
#define VINFO_CHECKREF						\
	extra_assert(vi->refcount >= 1);			\
	extra_assert(vi->refcount < 0x1000000 /* arbitrary */);
EXTERNFN void vinfo_release(vinfo_t* vi, PsycoObject* po);
PSY_INLINE void vinfo_incref(vinfo_t* vi) { VINFO_CHECKREF ++vi->refcount; }
PSY_INLINE void vinfo_decref(vinfo_t* vi, PsycoObject* po) {
	VINFO_CHECKREF
	if (!--vi->refcount) vinfo_release(vi, po);
}
PSY_INLINE void vinfo_xdecref(vinfo_t* vi, PsycoObject* po) {
	if (vi != NULL) vinfo_decref(vi, po);
}

/* promoting out of virtual-time */
PSY_INLINE bool compute_vinfo(vinfo_t* vi, PsycoObject* po) {
	if (is_virtualtime(vi->source)) {
		if (!VirtualTime_Get(vi->source)->compute_fn(po, vi))
			return false;
		extra_assert(!is_virtualtime(vi->source));
	}
	return true;
}
EXTERNFN bool psyco_limit_nested_weight(PsycoObject* po, vinfo_array_t* array,
					int nw_index, signed char nw_end);
EXTERNFN long direct_read_vinfo(vinfo_t* vi, char* data);
EXTERNFN PyObject* direct_xobj_vinfo(vinfo_t* vi, char* data);

PSY_INLINE bool vinfo_known_equal(vinfo_t* v, vinfo_t* w) {
	return (v->source == w->source &&
		(v == w || !is_virtualtime(v->source)));
}

/* misc */
PSY_INLINE bool is_nonneg(Source s) {
	switch (gettime(s)) {
	case RunTime:     return is_rtnonneg(s);
	case CompileTime: return CompileTime_Get(s)->value >= 0;
	default:          return false;
	}
}
PSY_INLINE void assert_nonneg(vinfo_t* v) {
	if (is_runtime(v->source))
		v->source = set_rtnonneg(v->source);
	else
		extra_assert(is_virtualtime(v->source) || is_nonneg(v->source));
}

/* sub-array (see also psyco_get_field()&co.) */
PSY_INLINE void vinfo_array_grow(vinfo_t* vi, int ncount) {
	if (ncount > vi->array->count)
		vi->array = array_grow1(vi->array, ncount);
}
EXTERNFN void vinfo_array_shrink(PsycoObject* po, vinfo_t* vi, int ncount);
PSY_INLINE vinfo_t* vinfo_getitem(vinfo_t* vi, int index) {
	if (((unsigned int) index) < ((unsigned int) vi->array->count))
		return vi->array->items[index];
	else
		return NULL;
}
PSY_INLINE vinfo_t* vinfo_needitem(vinfo_t* vi, int index) {
	vinfo_array_grow(vi, index+1);
	return vi->array->items[index];
}
PSY_INLINE void vinfo_setitem(PsycoObject* po, vinfo_t* vi, int index,
                          vinfo_t* newitem) {
	/* consumes a reference to 'newitem' */
	if (newitem != NULL) {
		extra_assert(!(is_compiletime(vi->source) &&
			       !is_compiletime(newitem->source)));
	}
	vinfo_array_grow(vi, index+1);
	vinfo_xdecref(vi->array->items[index], po);
	vi->array->items[index] = newitem;
}


/* array management */
EXTERNFN void clear_tmp_marks(vinfo_array_t* array);
#if ALL_CHECKS
EXTERNFN void assert_cleared_tmp_marks(vinfo_array_t* array);
EXTERNFN void assert_array_contains_nonct(vinfo_array_t* array, vinfo_t* vi);
#else
PSY_INLINE void assert_cleared_tmp_marks(vinfo_array_t* array) { }   /* nothing */
PSY_INLINE void assert_array_contains_nonct(vinfo_array_t* a, vinfo_t* v) { }
#endif
EXTERNFN void duplicate_array(vinfo_array_t* target, vinfo_array_t* source);
PSY_INLINE void deallocate_array(vinfo_array_t* array, PsycoObject* po) {
	int i = array->count;
	while (i--) vinfo_xdecref(array->items[i], po);
}
PSY_INLINE void array_delete(vinfo_array_t* array, PsycoObject* po) {
	deallocate_array(array, po);
	array_release(array);
}


/*****************************************************************/
 /***   read and write fields of structures in memory           ***/

/* Implementation of defield_t as a single packed bitfield,
   stored as a pointer to enable type checks in the C compiler */
/* [This is internal stuff: see comments below for an introduction.] */
/* type is defined by its size (given as the nth power of two)
   and a handful of flags */
typedef struct undefined_fld_s* defield_t;
EXTERNFN vinfo_t* psyco_internal_getfld(PsycoObject* po, int findex,
					defield_t df, vinfo_t* vi, long offset);
EXTERNFN bool psyco_internal_putfld(PsycoObject* po, int findex, defield_t df,
				    vinfo_t* vi, long offset, vinfo_t* value);
#define FIELD_INDEX_MASK  0x00FF
#define FIELD_MUTABLE     0x0100
#define FIELD_ARRAY       0x0200
#define FIELD_UNSIGNED    0x0400
#define FIELD_NONNEG      0x0800
#define FIELD_PYOBJ_REF   0x1000
#define FIELD_SIZE2_SHIFT 13
#define FIELD_INTL_NOREF  0x8000
#define FIELD_OFS_SHIFT   16
#define NO_PREV_FIELD     ((defield_t) -1)
#define FIELD_RESERVED_INDEX  0xCC
#define SIZE2_FROM_CTYPE(ctype) \
	(sizeof(ctype)==1 ? 0 : \
	 sizeof(ctype)==2 ? 1 : \
	 sizeof(ctype)==4 ? 2 : \
	 sizeof(ctype)==8 ? 3 : \
	 (extra_assert(!"field size is not a small power of two"), 0))
/*#define FIELD_NTH(df, n)
	(extra_assert(FIELD_INDEX(df)+(n) == FIELD_INDEX((df)+(n))),
	((df) + (n) + (((n) << FIELD_SIZE2(df)) << FIELD_OFS_SHIFT))*/
#define STRUCT_FIELD_BUILD(cstruct, ctype, cfield, prevf, flags)	\
	((defield_t) ((offsetof(cstruct, cfield) << FIELD_OFS_SHIFT) |	\
		      (SIZE2_FROM_CTYPE(ctype) << FIELD_SIZE2_SHIFT) |	\
		      field_next_index(prevf, true) |			\
		      flags))
#define ARRAY_FIELD_BUILD(ctype, baseofs, flags)			\
	((defield_t) (((baseofs) << FIELD_OFS_SHIFT) | 			\
		      (SIZE2_FROM_CTYPE(ctype) << FIELD_SIZE2_SHIFT) | 	\
		      FIELD_RESERVED_INDEX | FIELD_ARRAY |		\
		      flags))


/*****************************************************************
 * You must describe the fields of each C structure of the interpreter
 * that you want Psyco to work with.  Use the following macros field
 * by field.  Each macro returns a defield_t which contains the
 * definition of the field. */

/* build the field definition corresponding to:
    - the C structure whose name is in 'cstruct';
    - the C type given by 'ctype';
    - the field name given by 'cfield'.
   For the field order you must give in 'prevf' the defield_t
   corresponding to the previous field of the C structure,
   or NO_PREV_FIELD if you are defining the first field. */
#define DEF_FIELD(cstruct, ctype, cfield, prevf) \
	STRUCT_FIELD_BUILD(cstruct, ctype, cfield, prevf, 0)

/* special case: use the following macro instead of DEF_FIELD
   if 'ctype' is an unsigned numeric type. */
#define UNSIGNED_FIELD(cstruct, ctype, cfield, prevf) \
	STRUCT_FIELD_BUILD(cstruct, ctype, cfield, prevf, FIELD_UNSIGNED)

/* signed fields that are known to be non-negative */
#define NONNEG_FIELD(cstruct, ctype, cfield, prevf) \
	STRUCT_FIELD_BUILD(cstruct, ctype, cfield, prevf, FIELD_NONNEG)

/* the same, for pure arrays instead of structures */
#define DEF_ARRAY(ctype, baseofs) \
	ARRAY_FIELD_BUILD(ctype, baseofs, 0)
#define UNSIGNED_ARRAY(ctype, baseofs) \
	ARRAY_FIELD_BUILD(ctype, baseofs, FIELD_UNSIGNED)

/* you can surround DEF_FIELD() by FARRAY(), FMUT(), FPYREF():
    - FARRAY() means that the field is actually an array in the
      structure, as for example 'ob_items' in PyTupleObject;
    - FMUT() means that the field is mutable;
    - FPYREF() means that we want to read or store a PyObject* reference */
#define FARRAY(df)  ((defield_t) ((long)(df) | FIELD_ARRAY))
#define FMUT(df)    ((defield_t) ((long)(df) | FIELD_MUTABLE))
#define FPYREF(df)  (extra_assert(1<<FIELD_SIZE2(df) == sizeof(PyObject*)), \
                     (defield_t) ((long)(df) | FIELD_PYOBJ_REF))

/* inspection of a defield_t:
    - FIELDS_TOTAL(df) returns the number of fields of the structure
      defined so far, if 'df' is the defield_t of the last field;
    - FIELD_INDEX(df) returns the 0-based index of 'df' in vinfo->array;
    - 1<<FIELD_SIZE2(df) computes the size of the field 'df';
    - FIELD_C_OFFSET(df) is the offset of 'df' in the C structure. */
#define FIELDS_TOTAL(lastdf)  (field_next_index(lastdf, false))
#define FIELD_INDEX(df)    ((long)(df) & FIELD_INDEX_MASK)
#define FIELD_SIZE2(df)   (((long)(df) >> FIELD_SIZE2_SHIFT) & 3)
#define FIELD_C_OFFSET(df)   ((long)(df) >> FIELD_OFS_SHIFT)
#define FIELD_HAS_REF(df)  ((long)(df) & FIELD_PYOBJ_REF)
#define CHECK_FIELD_INDEX(n)  extra_assert((unsigned)FIELD_INDEX(n) <	\
					   FIELD_RESERVED_INDEX)

/* functions to read or write a field from or to the structure 
   pointed to by 'vi': */
PSY_INLINE vinfo_t* psyco_get_field(PsycoObject* po, vinfo_t* vi, defield_t df) {
	return psyco_internal_getfld(po, FIELD_INDEX(df), df,
				     vi, FIELD_C_OFFSET(df));
}
PSY_INLINE vinfo_t* psyco_get_nth_field(PsycoObject* po, vinfo_t* vi, defield_t df,
				    int index) {
	long ofs = index << FIELD_SIZE2(df);
	return psyco_internal_getfld(po, FIELD_INDEX(df) + index, df,
				     vi, FIELD_C_OFFSET(df) + ofs);
}
PSY_INLINE vinfo_t* psyco_get_field_offset(PsycoObject* po, vinfo_t* vi,
				       defield_t df, long offset) {
	extra_assert((long)df & FIELD_MUTABLE);
	return psyco_internal_getfld(po, FIELD_RESERVED_INDEX, df,
				     vi, FIELD_C_OFFSET(df) + offset);
}
EXTERNFN vinfo_t* psyco_get_field_array(PsycoObject* po, vinfo_t* vi,
					defield_t df, vinfo_t* vindex);
PSY_INLINE bool psyco_put_field(PsycoObject* po, vinfo_t* vi, defield_t df,
			    vinfo_t* value) {
	return psyco_internal_putfld(po, FIELD_INDEX(df), df,
				     vi, FIELD_C_OFFSET(df), value);
}
PSY_INLINE bool psyco_put_nth_field(PsycoObject* po, vinfo_t* vi, defield_t df, 
				int index, vinfo_t* value) {
	long ofs = index << FIELD_SIZE2(df);
	return psyco_internal_putfld(po, FIELD_INDEX(df) + index, df,
				     vi, FIELD_C_OFFSET(df) + ofs, value);
}
EXTERNFN bool psyco_put_field_array(PsycoObject* po, vinfo_t* vi, defield_t df,
                                    vinfo_t* vindex, vinfo_t* value);

/* fields of size 8 (like those of type 'double') are accessed as two
   vinfo_t's, for the second of which we use the following macro */
#define FIELD_PART2(df)  ((defield_t) ((long)(df) + 1 +     /* next index */  \
			    (sizeof(long)<<FIELD_OFS_SHIFT))) /* next ofs */

/* these special-case convenient functions do not return a new
   vinfo_t* reference that you have to worry about and eventually release;
   but they only work for immutable fields. */
PSY_INLINE vinfo_t* psyco_get_const(PsycoObject* po, vinfo_t* vi, defield_t df) {
	return psyco_internal_getfld(po, FIELD_INDEX(df),
                                     (defield_t) ((long)df | FIELD_INTL_NOREF),
				     vi, FIELD_C_OFFSET(df));
}
PSY_INLINE vinfo_t* psyco_get_nth_const(PsycoObject* po, vinfo_t* vi, defield_t df,
				    int index) {
	long ofs = index << FIELD_SIZE2(df);
	return psyco_internal_getfld(po, FIELD_INDEX(df) + index,
                                     (defield_t) ((long)df | FIELD_INTL_NOREF),
				     vi, FIELD_C_OFFSET(df) + ofs);
}

/* "forgets" the saved value for the field 'df' in 'vi'.  Used when an
   immutable field changes after all, or when a virtual-time structure that
   stores mutable fields is computed (because the mutable fields can actually
   be mutated by anyone after the structure is computed). */
PSY_INLINE void psyco_forget_field(PsycoObject* po, vinfo_t* vi, defield_t df) {
	CHECK_FIELD_INDEX(df);
	vinfo_setitem(po, vi, FIELD_INDEX(df), NULL);
}
PSY_INLINE void psyco_forget_nth_field(PsycoObject* po, vinfo_t* vi, defield_t df,
				   int index) {
	CHECK_FIELD_INDEX(df);
	vinfo_setitem(po, vi, FIELD_INDEX(df) + index, NULL);
}

/* to tell Psyco you are sure you know the value of a given field */
EXTERNFN void psyco_assert_field(PsycoObject* po, vinfo_t* vi, defield_t df,
                                 long value);


/* internal */
#if PSYCO_DEBUG
/* in debugging mode, use the function;  while optimizing, we favour
   the macro version below because GCC does not completely optimize out
   recursive calls to functions with completely constant arguments. */
PSY_INLINE int field_next_index(defield_t df, bool ovf) {
	if (df == NO_PREV_FIELD)
		return 0;
	else {
		int n = FIELD_INDEX(df);
		int field_size = 1 << FIELD_SIZE2(df);
		CHECK_FIELD_INDEX(df);
		/* arrays are variable-sized */
		extra_assert(!((long)df & FIELD_ARRAY));
		/* round up */
		n += (field_size + sizeof(long)-1) / sizeof(long);
		if (ovf)  /* check for index overflow */
			extra_assert(n == FIELD_INDEX(n));
		return n;
	}
}
#else
/*  this macro seriously slows down compilation because it expands 'df'
    three times, producing exponential explosion in the preprocessor --
    still, the result is generally a constant. */
#  define field_next_index(df, ovf)    ((df) == NO_PREV_FIELD ? 0 :		\
     FIELD_INDEX(df) + ((1 << FIELD_SIZE2(df)) + sizeof(long)-1) / sizeof(long))
#endif


/*****************************************************************/
 /***   PsycoObject: state of the compiler                      ***/


struct PsycoObject_s {
  /* used to be a Python object, hence the name */

  /* assembly code */
  code_t* code;                /* where the emitted code goes                */
  code_t* codelimit;           /* do not write code past this limit          */

  /* compiler private variables for producing and optimizing code */
  PROCESSOR_PSYCOOBJECT_FIELDS      /* processor state                       */
  int respawn_cnt;                  /* see psyco_prepare_respawn()           */
  CodeBufferObject* respawn_proxy;  /* see psyco_prepare_respawn()           */
  pyc_data_t pr;                    /* private language-dependent data       */

  /* finally, the description of variable stages. This is the data against
     which state matches and synchronizations are performed. */
  vinfo_array_t vlocals;          /* all the 'vinfo_t' variables             */
  /* variable-sized array! */
};

#define PSYCOOBJECT_SIZE(arraycnt)                                      \
	(sizeof(PsycoObject)-sizeof(vinfo_array_t) + sizeof(int) +      \
         (arraycnt)*sizeof(vinfo_t*))

/* move 'vsource->source' into 'vtarget->source'. Must be the last reference
   to 'vsource', which is freed. 'vsource' must have no array, and
   'vtarget->source' must hold no reference to anything. In short, this
   function must not be used except by virtual-time computers. */
EXTERNFN void vinfo_move(PsycoObject* po, vinfo_t* vtarget, vinfo_t* vsource);


/*****************************************************************/
 /***   Compiler language-independent functions                 ***/

/* compilation */

/* Main compiling function. Emit machine code corresponding to the state
   'po'. The compiler produces its code into 'code' and the return value is
   the end of the written code. 'po' is freed. 'mp' is the current mergepoint
   position or NULL if there is no mergepoint here.

   Be sure to call clear_tmp_marks(&po->vlocals) before this function.

   'continue_compilation' is normally false. When compile() is called
   during the compilation of 'po', 'continue_compilation' is true and
   psyco_compile() may return NULL to tell the caller to continue the
   compilation of 'po' itself. The sole purpose of this is to reduce the
   depth of recursion of the C stack.
*/
EXTERNFN code_t* psyco_compile(PsycoObject* po, mergepoint_t* mp,
                               bool continue_compilation);

/* Conditional compilation: the state 'po' is compiled to be executed only if
   'condition' holds. In general this creates a coding pause for it to be
   compiled later. It always makes a copy of 'po' so that the original can be
   used to compile the other case ('not condition'). 'condition' must not be
   CC_ALWAYS_xxx here. 'mp' is the current mergepoint position or NULL if there
   is no mergepoint here.
*/
EXTERNFN void psyco_compile_cond(PsycoObject* po, mergepoint_t* mp,
                                 condition_code_t condition);

/* Simplified interface to compile() without using a previously
   existing code buffer. Return a new code buffer. */
EXTERNFN CodeBufferObject* psyco_compile_code(PsycoObject* po, mergepoint_t* mp);

/* Prepare a 'coding pause', i.e. a short amount of code (proxy) that will be
   called only if the execution actually reaches it to go on with compilation.
   'po' is the PsycoObject corresponding to the proxy.
   'condition' may not be CC_ALWAYS_FALSE.
   The (possibly conditional) jump to the proxy is encoded in 'calling_code'.
   When the execution reaches the proxy, 'resume_fn' is called and the proxy
   destroys itself and replaces the original jump to it by a jump to the newly
   compiled code. */
typedef code_t* (*resume_fn_t)(PsycoObject* po, void* extra);
EXTERNFN void psyco_coding_pause(PsycoObject* po, condition_code_t jmpcondition,
				 resume_fn_t resume_fn,
				 void* extra, int extrasize);

/* management functions; see comments in compiler.c */
#if ALL_CHECKS
EXTERNFN void psyco_assert_coherent1(PsycoObject* po, bool full);
#else
#  define psyco_assert_coherent1(po, full)  do { } while (0) /* nothing */
#endif
#define psyco_assert_coherent(po)    psyco_assert_coherent1(po, true)

/* construction */
PSY_INLINE PsycoObject* PsycoObject_New(int vlocalscnt) {
	int psize = PSYCOOBJECT_SIZE(vlocalscnt);
	PsycoObject* po = (PsycoObject*) PyMem_MALLOC(psize);
	if (po == NULL)
		OUT_OF_MEMORY();
	memset(po, 0, psize);
	return po;
}
EXTERNFN PsycoObject* psyco_duplicate(PsycoObject* po);  /* internal */
PSY_INLINE PsycoObject* PsycoObject_Duplicate(PsycoObject* po) {
	clear_tmp_marks(&po->vlocals);
	return psyco_duplicate(po);
}
EXTERNFN void PsycoObject_Delete(PsycoObject* po);
PSY_INLINE PsycoObject* PsycoObject_Resize(PsycoObject* po, int nvlocalscnt) {
	int psize = PSYCOOBJECT_SIZE(nvlocalscnt);
	return (PsycoObject*) PyMem_REALLOC(po, psize);
}


#endif /* _VCOMPILER_H */