/* Execution of byte code produced by bytecomp.el.
- Copyright (C) 1985, 1986, 1987, 1988, 1993, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1985, 1986, 1987, 1988, 1993, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
hacked on by jwz@lucid.com 17-jun-91
o added a compile-time switch to turn on simple sanity checking;
o put back the obsolete byte-codes for error-detection;
- o added a new instruction, unbind_all, which I will use for
+ o added a new instruction, unbind_all, which I will use for
tail-recursion elimination;
o made temp_output_buffer_show be called with the right number
of args;
#include "buffer.h"
#include "charset.h"
#include "syntax.h"
+#include "window.h"
+
+#ifdef CHECK_FRAME_FONT
+#include "frame.h"
+#include "xterm.h"
+#endif
/*
- * define BYTE_CODE_SAFE to enable some minor sanity checking (useful for
+ * define BYTE_CODE_SAFE to enable some minor sanity checking (useful for
* debugging the byte compiler...)
*
- * define BYTE_CODE_METER to enable generation of a byte-op usage histogram.
+ * define BYTE_CODE_METER to enable generation of a byte-op usage histogram.
*/
/* #define BYTE_CODE_SAFE */
/* #define BYTE_CODE_METER */
#define METER_1(code) METER_2 (0, (code))
-#define METER_CODE(last_code, this_code) \
-{ \
- if (byte_metering_on) \
- { \
- if (METER_1 (this_code) != ((1<<VALBITS)-1)) \
- METER_1 (this_code)++; \
- if (last_code \
- && METER_2 (last_code, this_code) != ((1<<VALBITS)-1))\
- METER_2 (last_code, this_code)++; \
- } \
+#define METER_CODE(last_code, this_code) \
+{ \
+ if (byte_metering_on) \
+ { \
+ if (METER_1 (this_code) < MOST_POSITIVE_FIXNUM) \
+ METER_1 (this_code)++; \
+ if (last_code \
+ && METER_2 (last_code, this_code) < MOST_POSITIVE_FIXNUM) \
+ METER_2 (last_code, this_code)++; \
+ } \
}
#else /* no BYTE_CODE_METER */
{
/* Program counter. This points into the byte_string below
and is relocated when that string is relocated. */
- unsigned char *pc;
+ const unsigned char *pc;
/* Top and bottom of stack. The bottom points to an area of memory
allocated with alloca in Fbyte_code. */
Storing this here protects it from GC because mark_byte_stack
marks it. */
Lisp_Object byte_string;
- unsigned char *byte_string_start;
+ const unsigned char *byte_string_start;
/* The vector of constants used during byte-code execution. Storing
this here protects it from GC because mark_byte_stack marks it. */
The culprit is found in the frame of Fbyte_code where the
address of its local variable `stack' is equal to the
recorded value of `stack' here. */
- if (!stack->top)
- abort ();
-
- for (obj = stack->bottom; obj <= stack->top; ++obj)
- if (!XMARKBIT (*obj))
- {
- mark_object (obj);
- XMARK (*obj);
- }
+ eassert (stack->top);
- if (!XMARKBIT (stack->byte_string))
- {
- mark_object (&stack->byte_string);
- XMARK (stack->byte_string);
- }
+ for (obj = stack->bottom; obj <= stack->top; ++obj)
+ mark_object (*obj);
- if (!XMARKBIT (stack->constants))
- {
- mark_object (&stack->constants);
- XMARK (stack->constants);
- }
+ mark_object (stack->byte_string);
+ mark_object (stack->constants);
}
}
/* Unmark objects in the stacks on byte_stack_list. Relocate program
counters. Called when GC has completed. */
-void
+void
unmark_byte_stack ()
{
struct byte_stack *stack;
- Lisp_Object *obj;
for (stack = byte_stack_list; stack; stack = stack->next)
{
- for (obj = stack->bottom; obj <= stack->top; ++obj)
- XUNMARK (*obj);
-
- XUNMARK (stack->byte_string);
- XUNMARK (stack->constants);
-
- if (stack->byte_string_start != XSTRING (stack->byte_string)->data)
+ if (stack->byte_string_start != SDATA (stack->byte_string))
{
int offset = stack->pc - stack->byte_string_start;
- stack->byte_string_start = XSTRING (stack->byte_string)->data;
+ stack->byte_string_start = SDATA (stack->byte_string);
stack->pc = stack->byte_string_start + offset;
}
}
#endif /* not BYTE_CODE_SAFE */
+/* A version of the QUIT macro which makes sure that the stack top is
+ set before signaling `quit'. */
+
+#define BYTE_CODE_QUIT \
+ do { \
+ if (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) \
+ { \
+ Vquit_flag = Qnil; \
+ BEFORE_POTENTIAL_GC (); \
+ Fsignal (Qquit, Qnil); \
+ AFTER_POTENTIAL_GC (); \
+ } \
+ } while (0)
+
DEFUN ("byte-code", Fbyte_code, Sbyte_code, 3, 3, 0,
- "Function used internally in byte-compiled code.\n\
-The first argument, BYTESTR, is a string of byte code;\n\
-the second, VECTOR, a vector of constants;\n\
-the third, MAXDEPTH, the maximum stack depth used in this function.\n\
-If the third argument is incorrect, Emacs may crash.")
- (bytestr, vector, maxdepth)
+ doc: /* Function used internally in byte-compiled code.
+The first argument, BYTESTR, is a string of byte code;
+the second, VECTOR, a vector of constants;
+the third, MAXDEPTH, the maximum stack depth used in this function.
+If the third argument is incorrect, Emacs may crash. */)
+ (bytestr, vector, maxdepth)
Lisp_Object bytestr, vector, maxdepth;
{
- int count = specpdl_ptr - specpdl;
+ int count = SPECPDL_INDEX ();
#ifdef BYTE_CODE_METER
int this_op = 0;
int prev_op;
Lisp_Object *top;
Lisp_Object result;
- CHECK_STRING (bytestr, 0);
+#ifdef CHECK_FRAME_FONT
+ {
+ struct frame *f = SELECTED_FRAME ();
+ if (FRAME_X_P (f)
+ && FRAME_FONT (f)->direction != 0
+ && FRAME_FONT (f)->direction != 1)
+ abort ();
+ }
+#endif
+
+ CHECK_STRING (bytestr);
if (!VECTORP (vector))
vector = wrong_type_argument (Qvectorp, vector);
- CHECK_NUMBER (maxdepth, 2);
+ CHECK_NUMBER (maxdepth);
if (STRING_MULTIBYTE (bytestr))
/* BYTESTR must have been produced by Emacs 20.2 or the earlier
because they produced a raw 8-bit string for byte-code and now
such a byte-code string is loaded as multibyte while raw 8-bit
characters converted to multibyte form. Thus, now we must
- convert them back to the original unibyte form. */
+ convert them back to the originally intended unibyte form. */
bytestr = Fstring_as_unibyte (bytestr);
- bytestr_length = STRING_BYTES (XSTRING (bytestr));
+ bytestr_length = SBYTES (bytestr);
vectorp = XVECTOR (vector)->contents;
stack.byte_string = bytestr;
- stack.pc = stack.byte_string_start = XSTRING (bytestr)->data;
+ stack.pc = stack.byte_string_start = SDATA (bytestr);
stack.constants = vector;
- stack.bottom = (Lisp_Object *) alloca (XFASTINT (maxdepth)
+ stack.bottom = (Lisp_Object *) alloca (XFASTINT (maxdepth)
* sizeof (Lisp_Object));
top = stack.bottom - 1;
stack.top = NULL;
#ifdef BYTE_CODE_SAFE
stacke = stack.bottom - 1 + XFASTINT (maxdepth);
#endif
-
+
while (1)
{
#ifdef BYTE_CODE_SAFE
op = FETCH2;
goto varref;
- case Bvarref:
- case Bvarref + 1:
- case Bvarref + 2:
+ case Bvarref:
+ case Bvarref + 1:
+ case Bvarref + 2:
case Bvarref + 3:
- case Bvarref + 4:
+ case Bvarref + 4:
case Bvarref + 5:
op = op - Bvarref;
goto varref;
v1 = vectorp[op];
if (SYMBOLP (v1))
{
- v2 = XSYMBOL (v1)->value;
+ v2 = SYMBOL_VALUE (v1);
if (MISCP (v2) || EQ (v2, Qunbound))
{
BEFORE_POTENTIAL_GC ();
op = FETCH2;
if (NILP (POP))
{
- QUIT;
+ BYTE_CODE_QUIT;
CHECK_RANGE (op);
stack.pc = stack.byte_string_start + op;
}
TOP = Qnil;
else
{
- BEFORE_POTENTIAL_GC ();
- Fcar (wrong_type_argument (Qlistp, v1));
- AFTER_POTENTIAL_GC ();
+ wrong_type_argument (Qlistp, v1);
}
break;
}
TOP = Qnil;
else
{
- BEFORE_POTENTIAL_GC ();
- Fcdr (wrong_type_argument (Qlistp, v1));
- AFTER_POTENTIAL_GC ();
+ wrong_type_argument (Qlistp, v1);
}
break;
}
varset:
{
Lisp_Object sym, val;
-
+
sym = vectorp[op];
val = TOP;
/* Inline the most common case. */
if (SYMBOLP (sym)
&& !EQ (val, Qunbound)
- && !MISCP (XSYMBOL (sym)->value)
- /* I think this should either be checked in the byte
- compiler, or there should be a flag indicating that
- a symbol might be constant in Lisp_Symbol, instead
- of checking this here over and over again. --gerd. */
- && !EQ (sym, Qnil)
- && !EQ (sym, Qt)
- && !(XSYMBOL (sym)->name->data[0] == ':'
- && EQ (XSYMBOL (sym)->obarray, initial_obarray)
- && !EQ (val, sym)))
+ && !XSYMBOL (sym)->indirect_variable
+ && !XSYMBOL (sym)->constant
+ && !MISCP (XSYMBOL (sym)->value))
XSYMBOL (sym)->value = val;
else
{
AFTER_POTENTIAL_GC ();
}
}
- POP;
+ (void) POP;
break;
case Bdup:
case Bvarbind+5:
op -= Bvarbind;
varbind:
+ /* Specbind can signal and thus GC. */
+ BEFORE_POTENTIAL_GC ();
specbind (vectorp[op], POP);
+ AFTER_POTENTIAL_GC ();
break;
case Bcall+6:
v1 = TOP;
v2 = Fget (v1, Qbyte_code_meter);
if (INTEGERP (v2)
- && XINT (v2) != ((1<<VALBITS)-1))
+ && XINT (v2) < MOST_POSITIVE_FIXNUM)
{
XSETINT (v2, XINT (v2) + 1);
Fput (v1, Qbyte_code_meter, v2);
op -= Bunbind;
dounbind:
BEFORE_POTENTIAL_GC ();
- unbind_to (specpdl_ptr - specpdl - op, Qnil);
+ unbind_to (SPECPDL_INDEX () - op, Qnil);
AFTER_POTENTIAL_GC ();
break;
case Bgoto:
MAYBE_GC ();
- QUIT;
+ BYTE_CODE_QUIT;
op = FETCH2; /* pc = FETCH2 loses since FETCH2 contains pc++ */
CHECK_RANGE (op);
stack.pc = stack.byte_string_start + op;
op = FETCH2;
if (!NILP (POP))
{
- QUIT;
+ BYTE_CODE_QUIT;
CHECK_RANGE (op);
stack.pc = stack.byte_string_start + op;
}
op = FETCH2;
if (NILP (TOP))
{
- QUIT;
+ BYTE_CODE_QUIT;
CHECK_RANGE (op);
stack.pc = stack.byte_string_start + op;
}
op = FETCH2;
if (!NILP (TOP))
{
- QUIT;
+ BYTE_CODE_QUIT;
CHECK_RANGE (op);
stack.pc = stack.byte_string_start + op;
}
case BRgoto:
MAYBE_GC ();
- QUIT;
+ BYTE_CODE_QUIT;
stack.pc += (int) *stack.pc - 127;
break;
MAYBE_GC ();
if (NILP (POP))
{
- QUIT;
+ BYTE_CODE_QUIT;
stack.pc += (int) *stack.pc - 128;
}
stack.pc++;
MAYBE_GC ();
if (!NILP (POP))
{
- QUIT;
+ BYTE_CODE_QUIT;
stack.pc += (int) *stack.pc - 128;
}
stack.pc++;
op = *stack.pc++;
if (NILP (TOP))
{
- QUIT;
+ BYTE_CODE_QUIT;
stack.pc += op - 128;
}
else DISCARD (1);
op = *stack.pc++;
if (!NILP (TOP))
{
- QUIT;
+ BYTE_CODE_QUIT;
stack.pc += op - 128;
}
else DISCARD (1);
}
case Bunwind_protect:
- record_unwind_protect (0, POP);
- (specpdl_ptr - 1)->symbol = Qnil;
+ record_unwind_protect (Fprogn, POP);
break;
case Bcondition_case:
case Btemp_output_buffer_setup:
BEFORE_POTENTIAL_GC ();
- temp_output_buffer_setup (XSTRING (TOP)->data);
+ CHECK_STRING (TOP);
+ temp_output_buffer_setup (SDATA (TOP));
AFTER_POTENTIAL_GC ();
TOP = Vstandard_output;
break;
temp_output_buffer_show (TOP);
TOP = v1;
/* pop binding of standard-output */
- unbind_to (specpdl_ptr - specpdl - 1, Qnil);
+ unbind_to (SPECPDL_INDEX () - 1, Qnil);
AFTER_POTENTIAL_GC ();
break;
}
BEFORE_POTENTIAL_GC ();
v1 = POP;
v2 = TOP;
- CHECK_NUMBER (v2, 0);
+ CHECK_NUMBER (v2);
AFTER_POTENTIAL_GC ();
op = XINT (v2);
immediate_quit = 1;
else if (!NILP (v1))
{
immediate_quit = 0;
- BEFORE_POTENTIAL_GC ();
- v1 = wrong_type_argument (Qlistp, v1);
- AFTER_POTENTIAL_GC ();
- immediate_quit = 1;
- op++;
+ wrong_type_argument (Qlistp, v1);
}
}
immediate_quit = 0;
else if (NILP (v1))
TOP = Qnil;
else
- {
- BEFORE_POTENTIAL_GC ();
- Fcar (wrong_type_argument (Qlistp, v1));
- AFTER_POTENTIAL_GC ();
- }
+ wrong_type_argument (Qlistp, v1);
break;
}
TOP = v1;
}
else
- TOP = Fsub1 (v1);
+ {
+ BEFORE_POTENTIAL_GC ();
+ TOP = Fsub1 (v1);
+ AFTER_POTENTIAL_GC ();
+ }
break;
}
Lisp_Object v1, v2;
BEFORE_POTENTIAL_GC ();
v2 = POP; v1 = TOP;
- CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v1, 0);
- CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v2, 0);
+ CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v1);
+ CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v2);
AFTER_POTENTIAL_GC ();
if (FLOATP (v1) || FLOATP (v2))
{
case Bgeq:
{
Lisp_Object v1;
+ BEFORE_POTENTIAL_GC ();
v1 = POP;
TOP = Fgeq (TOP, v1);
+ AFTER_POTENTIAL_GC ();
break;
}
case Bcurrent_column:
{
Lisp_Object v1;
- XSETFASTINT (v1, current_column ());
+ BEFORE_POTENTIAL_GC ();
+ XSETFASTINT (v1, (int) current_column ()); /* iftc */
+ AFTER_POTENTIAL_GC ();
PUSH (v1);
break;
}
case Bchar_syntax:
BEFORE_POTENTIAL_GC ();
- CHECK_NUMBER (TOP, 0);
+ CHECK_NUMBER (TOP);
AFTER_POTENTIAL_GC ();
XSETFASTINT (TOP, syntax_code_spec[(int) SYNTAX (XINT (TOP))]);
break;
BEFORE_POTENTIAL_GC ();
v2 = POP;
v1 = TOP;
- CHECK_NUMBER (v2, 0);
+ CHECK_NUMBER (v2);
AFTER_POTENTIAL_GC ();
op = XINT (v2);
immediate_quit = 1;
else if (!NILP (v1))
{
immediate_quit = 0;
- BEFORE_POTENTIAL_GC ();
- v1 = wrong_type_argument (Qlistp, v1);
- AFTER_POTENTIAL_GC ();
- immediate_quit = 1;
- op++;
+ wrong_type_argument (Qlistp, v1);
}
}
immediate_quit = 0;
else if (NILP (v1))
TOP = Qnil;
else
- {
- BEFORE_POTENTIAL_GC ();
- Fcar (wrong_type_argument (Qlistp, v1));
- AFTER_POTENTIAL_GC ();
- }
+ wrong_type_argument (Qlistp, v1);
}
else
{
byte_stack_list = byte_stack_list->next;
/* Binds and unbinds are supposed to be compiled balanced. */
- if (specpdl_ptr - specpdl != count)
+ if (SPECPDL_INDEX () != count)
#ifdef BYTE_CODE_SAFE
error ("binding stack not balanced (serious byte compiler bug)");
#else
abort ();
#endif
-
+
return result;
}
#ifdef BYTE_CODE_METER
DEFVAR_LISP ("byte-code-meter", &Vbyte_code_meter,
- "A vector of vectors which holds a histogram of byte-code usage.\n\
-(aref (aref byte-code-meter 0) CODE) indicates how many times the byte\n\
-opcode CODE has been executed.\n\
-(aref (aref byte-code-meter CODE1) CODE2), where CODE1 is not 0,\n\
-indicates how many times the byte opcodes CODE1 and CODE2 have been\n\
-executed in succession.");
+ doc: /* A vector of vectors which holds a histogram of byte-code usage.
+\(aref (aref byte-code-meter 0) CODE) indicates how many times the byte
+opcode CODE has been executed.
+\(aref (aref byte-code-meter CODE1) CODE2), where CODE1 is not 0,
+indicates how many times the byte opcodes CODE1 and CODE2 have been
+executed in succession. */);
+
DEFVAR_BOOL ("byte-metering-on", &byte_metering_on,
- "If non-nil, keep profiling information on byte code usage.\n\
-The variable byte-code-meter indicates how often each byte opcode is used.\n\
-If a symbol has a property named `byte-code-meter' whose value is an\n\
-integer, it is incremented each time that symbol's function is called.");
+ doc: /* If non-nil, keep profiling information on byte code usage.
+The variable byte-code-meter indicates how often each byte opcode is used.
+If a symbol has a property named `byte-code-meter' whose value is an
+integer, it is incremented each time that symbol's function is called. */);
byte_metering_on = 0;
Vbyte_code_meter = Fmake_vector (make_number (256), make_number (0));
}
#endif
}
+
+/* arch-tag: b9803b6f-1ed6-4190-8adf-33fd3a9d10e9
+ (do not change this comment) */