Mercurial > hg > xemacs-beta
diff src/bytecode.c @ 1920:c66036f59678
[xemacs-hg @ 2004-02-20 07:29:16 by stephent]
GCPRO documentation <87y8qynrj0.fsf@tleepslib.sk.tsukuba.ac.jp>
author | stephent |
---|---|
date | Fri, 20 Feb 2004 07:29:23 +0000 |
parents | 3d25fd3d9ac4 |
children | 9c872f33ecbe |
line wrap: on
line diff
--- a/src/bytecode.c Thu Feb 19 22:50:36 2004 +0000 +++ b/src/bytecode.c Fri Feb 20 07:29:23 2004 +0000 @@ -447,6 +447,7 @@ but don't pop it. */ #define TOP (*stack_ptr) +/* See comment before the big switch in execute_optimized_program(). */ #define GCPRO_STACK (gcpro1.nvars = stack_ptr - stack_beg) /* The actual interpreter for byte code. @@ -476,25 +477,40 @@ Lisp_Object *stack_end = stack_beg + stack_depth; #endif -#if STATIC_GCPRO_STACK - /* Initialize all the objects on the stack to Qnil, - so we can GCPRO the whole stack. - The first element of the stack is actually a dummy. */ - { - int i; - Lisp_Object *p; - for (i = stack_depth, p = stack_ptr; i--;) - *++p = Qnil; - } -#endif + /* We used to GCPRO the whole interpreter stack before entering this while + loop (21.5.14 and before), but that interferes with collection of weakly + referenced objects. Although strictly speaking there's no promise that + weak references will disappear by any given point in time, they should + be collected at the first opportunity. Waiting until exit from the + function caused test failures because "stale" objects "above" the top of + the stack were still GCPROed, and they were not getting collected until + after exit from the (byte-compiled) test! + + Now the idea is to dynamically adjust the array of GCPROed objects to + include only the "active" region of the stack. + + We use the "GCPRO1 the array base and set the nvars member" method. It + would be slightly inefficient but correct to use GCPRO1_ARRAY here. It + would just redundantly set nvars. + #### Maybe it would be clearer to use GCPRO1_ARRAY and do GCPRO_STACK + after the switch? + + GCPRO_STACK is something of a misnomer, because it suggests that a + struct gcpro is initialized each time. This is false; only the nvars + member of a single struct gcpro is being adjusted. This works because + each time a new object is assigned to a stack location, the old object + loses its reference and is effectively UNGCPROed, and the new object is + automatically GCPROed as long as nvars is correct. Only when we + return from the interpreter do we need to finalize the struct gcpro + itself, and that's done at case Breturn. + */ GCPRO1 (stack_ptr[1]); -#if STATIC_GCPRO_STACK - gcpro1.nvars = stack_depth; -#endif while (1) { REGISTER Opcode opcode = (Opcode) READ_UINT_1; + + GCPRO_STACK; /* Get nvars right before maybe signaling. */ #ifdef ERROR_CHECK_BYTE_CODE if (stack_ptr > stack_end) stack_overflow ("byte code stack overflow", Qunbound); @@ -508,9 +524,6 @@ meter_code (prev_opcode, this_opcode); #endif -#if !STATIC_GCPRO_STACK - GCPRO_STACK; -#endif switch (opcode) { REGISTER int n; @@ -539,6 +552,8 @@ Lisp_Object symbol = constants_data[n]; Lisp_Object value = XSYMBOL (symbol)->value; if (SYMBOL_VALUE_MAGIC_P (value)) + /* I GCPRO_STACKed Fsymbol_value elsewhere, but I dunno why. */ + /* GCPRO_STACK; */ value = Fsymbol_value (symbol); PUSH (value); break; @@ -616,6 +631,8 @@ case Bcall+7: n = (opcode < Bcall+6 ? opcode - Bcall : opcode == Bcall+6 ? READ_UINT_1 : READ_UINT_2); + /* #### Shouldn't this be just before the Ffuncall? + Neither Fget nor Fput can GC. */ /* GCPRO_STACK; */ DISCARD (n); #ifdef BYTE_CODE_METER @@ -745,10 +762,14 @@ break; case Bcar: + /* Fcar can GC via wrong_type_argument. */ + /* GCPRO_STACK; */ TOP = CONSP (TOP) ? XCAR (TOP) : Fcar (TOP); break; case Bcdr: + /* Fcdr can GC via wrong_type_argument. */ + /* GCPRO_STACK; */ TOP = CONSP (TOP) ? XCDR (TOP) : Fcdr (TOP); break; @@ -762,6 +783,8 @@ case Bnth: { Lisp_Object arg = POP; + /* Fcar and Fnthcdr can GC via wrong_type_argument. */ + /* GCPRO_STACK; */ TOP = Fcar (Fnthcdr (TOP, arg)); break; } @@ -848,6 +871,8 @@ n = READ_UINT_1; do_concat: DISCARD (n - 1); + /* Apparently `concat' can GC; Fconcat GCPROs its arguments. */ + /* GCPRO_STACK; */ TOP = Fconcat (n, &TOP); break; @@ -865,6 +890,7 @@ } case Bsymbol_value: + /* Why does this need GCPRO_STACK? If not, remove others, too. */ /* GCPRO_STACK; */ TOP = Fsymbol_value (TOP); break; @@ -931,6 +957,8 @@ case Bnconc: DISCARD (1); + /* nconc2 GCPROs before calling this. */ + /* GCPRO_STACK; */ TOP = bytecode_nconc2 (&TOP); break; @@ -969,12 +997,16 @@ break; case Binsert: + /* Says it can GC. */ + /* GCPRO_STACK; */ TOP = Finsert (1, &TOP); break; case BinsertN: n = READ_UINT_1; DISCARD (n - 1); + /* See Binsert. */ + /* GCPRO_STACK; */ TOP = Finsert (n, &TOP); break; @@ -1004,6 +1036,8 @@ case Bequal: { Lisp_Object arg = POP; + /* Can QUIT, so can GC, right? */ + /* GCPRO_STACK; */ TOP = Fequal (TOP, arg); break; } @@ -1025,6 +1059,8 @@ case Bmember: { Lisp_Object arg = POP; + /* Can QUIT, so can GC, right? */ + /* GCPRO_STACK; */ TOP = Fmember (TOP, arg); break; } @@ -1059,6 +1095,8 @@ case Bskip_chars_forward: { Lisp_Object arg = POP; + /* Can QUIT, so can GC, right? */ + /* GCPRO_STACK; */ TOP = Fskip_chars_forward (TOP, arg, Qnil); break; }