Add x86_64 assembly to allocate and access thread-local variables.
authorMatt Birkholz <puck@birchwood-abbey.net>
Sun, 19 Jul 2015 05:55:44 +0000 (22:55 -0700)
committerMatt Birkholz <puck@birchwood-abbey.net>
Thu, 26 Nov 2015 08:09:46 +0000 (01:09 -0700)
Thus stack_pointer, Free and Registers are now thread-local.  And
several more variables are allocated in the assembly (no longer in the
C code): heap_alloc_limit, heap_end, stack_guard, stack_start,
C_Stack_Pointer and C_Frame_Pointer.

src/microcode/cmpauxmd/x86-64.m4
src/microcode/cmpint.c
src/microcode/cmpintmd/x86-64.c
src/microcode/cmpintmd/x86-64.h
src/microcode/extern.h
src/microcode/makegen/m4.sh
src/microcode/storage.c

index 6a54851c4c7c7cdf0c0e5c73ff9b7351699f9dbc..d1b5b50884f547b80d5e97f5a366783094aa3705 100644 (file)
@@ -40,7 +40,7 @@
 ###    2) The C compiler divides registers into three groups:
 ###    - Linkage registers, used for procedure calls and global
 ###    references.  On AMD64 Unix ABI: %rbp, %rsp.
-###    - super temporaries, not preserved accross procedure calls and
+###    - super temporaries, not preserved across procedure calls and
 ###    always usable. On AMD64 Unix ABI: everything but what is
 ###    listed below.
 ###    - preserved registers saved by the callee if they are written.
@@ -155,6 +155,9 @@ IFNDASM(`define(popfd,`popf')')
 ifdef(`SUPPRESS_LEADING_UNDERSCORE',
        `define(EVR,`$1')',
        `define(EVR,`_$1')')
+ifdef(`ENABLE_SMP',
+      `define(TLVR,`%fs:$1\@tpoff')',
+      `define(TLVR,`ABS(EVR($1))')')
 
 # When using the Watcom C compiler with register-based calling
 # conventions, source-code function names normally expand to `FOO_',
@@ -314,6 +317,15 @@ define(FLONUM_STORAGE_SIZE,16)
 define(REGBLOCK_VAL,16)
 define(REGBLOCK_COMPILER_TEMP,32)
 define(REGBLOCK_DLINK,REGBLOCK_COMPILER_TEMP)
+define(COMPILER_REGBLOCK_N_FIXED,16)
+define(COMPILER_REGBLOCK_N_HOOKS,80)
+define(COMPILER_REGBLOCK_N_TEMPS,256)
+define(COMPILER_HOOK_SIZE,1)
+define(COMPILER_TEMP_SIZE,1)
+define(REGBLOCK_LENGTH,
+       eval(COMPILER_REGBLOCK_N_FIXED
+           +(COMPILER_REGBLOCK_N_HOOKS*COMPILER_HOOK_SIZE)
+           +(COMPILER_REGBLOCK_N_TEMPS*COMPILER_TEMP_SIZE)))
 
 # Define the floating-point processor control word.  Always set
 # round-to-even and double precision.  Under Win32, mask all
@@ -330,17 +342,45 @@ define(rmask,REG(rbp))
 IFDASM(`.586p
 .model flat')
 
+use_external_data(EVR(utility_table))
+
+ifdef(`ENABLE_SMP',`
+       .section .tbss,"awT",\@nobits
+       .align 8
+define(`define_tllong',`
+       .globl $1
+       .type $1 STT_TLS
+       .size $1, 8
+$1:
+       .zero   8
+')
+       define_tllong(Free)
+       define_tllong(heap_alloc_limit)
+       define_tllong(heap_end)
+       define_tllong(stack_guard)
+       define_tllong(stack_pointer)
+       define_tllong(stack_start)
+       define_tllong(C_Stack_Pointer)
+       define_tllong(C_Frame_Pointer)
+
+       .globl Registers
+       .type Registers STT_TLS
+       .size Registers, eval(REGBLOCK_LENGTH*8)
+Registers:
+       .zero eval(REGBLOCK_LENGTH*8)
+
 DECLARE_DATA_SEGMENT()
 declare_alignment(2)
+',`
 
-use_external_data(EVR(Free))
-use_external_data(EVR(stack_pointer))
-use_external_data(EVR(utility_table))
+DECLARE_DATA_SEGMENT()
+declare_alignment(2)
 
 ifdef(`WIN32',`
 use_external_data(EVR(RegistersPtr))
 ',`
-use_external_data(EVR(Registers))
+define_data(Registers)
+allocate_space(`Registers',`eval(REGBLOCK_LENGTH*8)')
 ')
 
 define_data(C_Stack_Pointer)
@@ -348,6 +388,7 @@ allocate_quadword(C_Stack_Pointer)
 
 define_data(C_Frame_Pointer)
 allocate_quadword(C_Frame_Pointer)
+')
 
 declare_alignment(8)
 define_double(flonum_zero,0.0)
@@ -383,7 +424,7 @@ define_c_label(x86_64_interface_initialize)
 # set esp to something they consider funny.
 
 define_c_label(within_c_stack)
-       OP(mov,q)       TW(ABS(EVR(C_Stack_Pointer)),REG(rax))
+       OP(mov,q)       TW(TLVR(C_Stack_Pointer),REG(rax))
        # Are we currently in C, signalled by having no saved C stack pointer?
        OP(cmp,q)       TW(IMM(0),REG(rax))
        # Yes: just call the function without messing with rsp.
@@ -392,7 +433,7 @@ define_c_label(within_c_stack)
        OP(push,q)      REG(rbp)                        # Save frame pointer
        OP(mov,q)       TW(REG(rsp),REG(rbp))
        OP(mov,q)       TW(REG(rax),REG(rsp))           # Switch to C stack
-       OP(mov,q)       TW(IMM(0),ABS(EVR(C_Stack_Pointer)))
+       OP(mov,q)       TW(IMM(0),TLVR(C_Stack_Pointer))
        OP(push,q)      IMM(0)                          # Align sp to 16 bytes
        OP(push,q)      REG(rbp)                        # Save stack pointer
        OP(mov,q)       TW(REG(rdi),REG(rax))           # arg1 (fn) -> rax
@@ -402,7 +443,7 @@ define_c_label(within_c_stack)
 define_debugging_label(within_c_stack_restore)
        OP(mov,q)       TW(REG(rsp),REG(rax))           # Restore C stack ptr
        OP(add,q)       TW(IMM(16),REG(rax))
-       OP(mov,q)       TW(REG(rax),ABS(EVR(C_Stack_Pointer)))
+       OP(mov,q)       TW(REG(rax),TLVR(C_Stack_Pointer))
        OP(pop,q)       REG(rsp)                        # Restore stack pointer
                                                        #   and switch back to
                                                        #   Scheme stack
@@ -438,9 +479,9 @@ define_c_label(C_to_interface)
        OP(push,q)      IMM(0)                          # Align stack
        OP(mov,q)       TW(REG(rdi),REG(rdx))           # Entry point
                                                        # Preserve frame ptr
-       OP(mov,q)       TW(REG(rbp),ABS(EVR(C_Frame_Pointer)))
+       OP(mov,q)       TW(REG(rbp),TLVR(C_Frame_Pointer))
                                                        # Preserve stack ptr
-       OP(mov,q)       TW(REG(rsp),ABS(EVR(C_Stack_Pointer)))
+       OP(mov,q)       TW(REG(rsp),TLVR(C_Stack_Pointer))
        jmp     EPFR(interface_to_scheme)
 
 define_hook_label(trampoline_to_interface)
@@ -468,13 +509,13 @@ define_debugging_label(scheme_to_interface_call)
 
 define_hook_label(scheme_to_interface)
 define_debugging_label(scheme_to_interface)
-       OP(mov,q)       TW(REG(rsp),ABS(EVR(stack_pointer)))
-       OP(mov,q)       TW(rfree,ABS(EVR(Free)))
-       OP(mov,q)       TW(ABS(EVR(C_Stack_Pointer)),REG(rsp))
-       OP(mov,q)       TW(ABS(EVR(C_Frame_Pointer)),REG(rbp))
+       OP(mov,q)       TW(REG(rsp),TLVR(stack_pointer))
+       OP(mov,q)       TW(rfree,TLVR(Free))
+       OP(mov,q)       TW(TLVR(C_Stack_Pointer),REG(rsp))
+       OP(mov,q)       TW(TLVR(C_Frame_Pointer),REG(rbp))
 
        # Signal to within_c_stack that we are now in C land.
-       OP(mov,q)       TW(IMM(0),ABS(EVR(C_Stack_Pointer)))
+       OP(mov,q)       TW(IMM(0),TLVR(C_Stack_Pointer))
 
        OP(sub,q)       TW(IMM(16),REG(rsp))    # alloc struct return
        OP(mov,q)       TW(REG(rsp),REG(rdi))   # Structure is first argument.
@@ -498,15 +539,18 @@ define_debugging_label(scheme_to_interface_return)
 
 define_c_label(interface_to_scheme)
 ifdef(`WIN32',                                         # Register block = %rsi
-`      OP(mov,q)       TW(ABS(EVR(RegistersPtr)),regs)',
-`      OP(lea,q)       TW(ABS(EVR(Registers)),regs)')
-       OP(mov,q)       TW(ABS(EVR(Free)),rfree)        # Free pointer = %rdi
+`      OP(mov,q)       TW(TLVR(RegistersPtr),regs)',
+`ifdef(`ENABLE_SMP',
+`      OP(mov,q)       TW(%fs:0,regs)
+       OP(add,q)       TW($Registers\@tpoff,regs)',
+`      OP(lea,q)       TW(ABS(EVR(Registers)),regs)')')
+       OP(mov,q)       TW(TLVR(Free),rfree)    # Free pointer = %rdi
        OP(mov,q)       TW(QOF(REGBLOCK_VAL(),regs),REG(rax)) # Value/dynamic link
        OP(mov,q)       TW(IMM(ADDRESS_MASK),rmask)     # = %rbp
        # Restore the C stack pointer, which we zeroed back in
        # scheme_to_interface, for within_c_stack.
-       OP(mov,q)       TW(REG(rsp),ABS(EVR(C_Stack_Pointer)))
-       OP(mov,q)       TW(ABS(EVR(stack_pointer)),REG(rsp))
+       OP(mov,q)       TW(REG(rsp),TLVR(C_Stack_Pointer))
+       OP(mov,q)       TW(TLVR(stack_pointer),REG(rsp))
        OP(mov,q)       TW(REG(rax),REG(rcx))           # Preserve if used
        OP(and,q)       TW(rmask,REG(rcx))              # Restore potential dynamic link
        OP(mov,q)       TW(REG(rcx),QOF(REGBLOCK_DLINK(),regs))
index 1c06ce384329381f8a7046cc49f3bdd6474659a3..2e897f7c31b4176efcb29ffd5f8eda6e66e855f6 100644 (file)
@@ -251,7 +251,11 @@ long C_return_value;
    + COMPILER_REGBLOCK_EXTRA_SIZE)
 
 #ifndef REGBLOCK_ALLOCATED_BY_INTERFACE
-  SCHEME_OBJECT Registers [REGBLOCK_LENGTH];
+  __thread SCHEME_OBJECT Registers [REGBLOCK_LENGTH];
+#  ifdef ENABLE_SMP
+    __thread void *C_Stack_Pointer;
+    __thread void *C_Frame_Pointer;
+#  endif
 #endif
 
 #ifndef ASM_INIT_HOOK
index dc7f2750dddfbcd7a263e3bc2326f76c0f1228a2..27a985cb9495fe3d06dae42a1e58938b7aa46112 100644 (file)
@@ -210,12 +210,107 @@ store_trampoline_insns (insn_t * entry, byte_t code)
 #  define VM_PROT_SCHEME (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
 #endif
 
+void
+x86_64_init_hook (void)
+{
+  x86_64_interface_initialize ();
+
+  declare_builtin ((unsigned long)asm_scheme_to_interface, "asm_scheme_to_interface");
+  declare_builtin ((unsigned long)asm_scheme_to_interface_call, "asm_scheme_to_interface_call");
+  declare_builtin ((unsigned long)asm_trampoline_to_interface, "asm_trampoline_to_interface");
+  declare_builtin ((unsigned long)asm_interrupt_procedure, "asm_interrupt_procedure");
+  declare_builtin ((unsigned long)asm_interrupt_continuation, "asm_interrupt_continuation");
+  declare_builtin ((unsigned long)asm_interrupt_closure, "asm_interrupt_closure");
+  declare_builtin ((unsigned long)asm_interrupt_dlink, "asm_interrupt_dlink");
+  declare_builtin ((unsigned long)asm_primitive_apply, "asm_primitive_apply");
+  declare_builtin ((unsigned long)asm_primitive_lexpr_apply, "asm_primitive_lexpr_apply");
+  declare_builtin ((unsigned long)asm_assignment_trap, "asm_assignment_trap");
+  declare_builtin ((unsigned long)asm_reference_trap, "asm_reference_trap");
+  declare_builtin ((unsigned long)asm_safe_reference_trap, "asm_safe_reference_trap");
+  declare_builtin ((unsigned long)asm_link, "asm_link");
+  declare_builtin ((unsigned long)asm_error, "asm_error");
+  declare_builtin ((unsigned long)asm_primitive_error, "asm_primitive_error");
+  declare_builtin ((unsigned long)asm_generic_add, "asm_generic_add");
+  declare_builtin ((unsigned long)asm_generic_subtract, "asm_generic_subtract");
+  declare_builtin ((unsigned long)asm_generic_multiply, "asm_generic_multiply");
+  declare_builtin ((unsigned long)asm_generic_divide, "asm_generic_divide");
+  declare_builtin ((unsigned long)asm_generic_equal, "asm_generic_equal");
+  declare_builtin ((unsigned long)asm_generic_less, "asm_generic_less");
+  declare_builtin ((unsigned long)asm_generic_greater, "asm_generic_greater");
+  declare_builtin ((unsigned long)asm_generic_increment, "asm_generic_increment");
+  declare_builtin ((unsigned long)asm_generic_decrement, "asm_generic_decrement");
+  declare_builtin ((unsigned long)asm_generic_zero, "asm_generic_zero");
+  declare_builtin ((unsigned long)asm_generic_positive, "asm_generic_positive");
+  declare_builtin ((unsigned long)asm_generic_negative, "asm_generic_negative");
+  declare_builtin ((unsigned long)asm_generic_quotient, "asm_generic_quotient");
+  declare_builtin ((unsigned long)asm_generic_remainder, "asm_generic_remainder");
+  declare_builtin ((unsigned long)asm_generic_modulo, "asm_generic_modulo");
+  declare_builtin ((unsigned long)asm_sc_apply, "asm_sc_apply");
+  declare_builtin ((unsigned long)asm_sc_apply_size_1, "asm_sc_apply_size_1");
+  declare_builtin ((unsigned long)asm_sc_apply_size_2, "asm_sc_apply_size_2");
+  declare_builtin ((unsigned long)asm_sc_apply_size_3, "asm_sc_apply_size_3");
+  declare_builtin ((unsigned long)asm_sc_apply_size_4, "asm_sc_apply_size_4");
+  declare_builtin ((unsigned long)asm_sc_apply_size_5, "asm_sc_apply_size_5");
+  declare_builtin ((unsigned long)asm_sc_apply_size_6, "asm_sc_apply_size_6");
+  declare_builtin ((unsigned long)asm_sc_apply_size_7, "asm_sc_apply_size_7");
+  declare_builtin ((unsigned long)asm_sc_apply_size_8, "asm_sc_apply_size_8");
+  declare_builtin ((unsigned long)asm_interrupt_continuation_2, "asm_interrupt_continuation_2");
+  declare_builtin ((unsigned long)asm_fixnum_shift, "asm_fixnum_shift");
+
+#ifdef _MACH_UNIX
+  {
+    vm_address_t addr;
+    vm_size_t size;
+    vm_prot_t prot;
+    vm_prot_t max_prot;
+    vm_inherit_t inheritance;
+    boolean_t shared;
+    port_t object;
+    vm_offset_t offset;
+
+    addr = ((vm_address_t) Heap);
+    if ((vm_region ((task_self ()), &addr, &size, &prot, &max_prot,
+                   &inheritance, &shared, &object, &offset))
+       != KERN_SUCCESS)
+      {
+       outf_fatal ( "compiler_reset: vm_region() failed.\n");
+       Microcode_Termination (TERM_EXIT);
+       /*NOTREACHED*/
+      }
+    if ((prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
+      {
+       if ((max_prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
+         {
+           outf_fatal (
+                       "compiler_reset: inadequate protection for Heap.\n");
+           outf_fatal ( "maximum = 0x%lx; desired = 0x%lx\n",
+                       ((unsigned long) (max_prot & VM_PROT_SCHEME)),
+                       ((unsigned long) VM_PROT_SCHEME));
+           Microcode_Termination (TERM_EXIT);
+           /*NOTREACHED*/
+         }
+       if ((vm_protect ((task_self ()), ((vm_address_t) Heap),
+                        (((char *) constant_end) - ((char *) Heap)),
+                        0, VM_PROT_SCHEME))
+           != KERN_SUCCESS)
+         {
+           outf_fatal ("Unable to change protection for Heap.\n");
+           outf_fatal ("actual = 0x%lx; desired = 0x%lx\n",
+                       ((unsigned long) (prot & VM_PROT_SCHEME)),
+                       ((unsigned long) VM_PROT_SCHEME));
+           Microcode_Termination (TERM_EXIT);
+           /*NOTREACHED*/
+         }
+      }
+  }
+#endif /* _MACH_UNIX */
+}
+
 #define SETUP_REGISTER(hook) do                                                \
 {                                                                      \
   (* ((unsigned long *) (rsi_value + offset)))                         \
     = ((unsigned long) (hook));                                                \
   offset += (COMPILER_HOOK_SIZE * (sizeof (SCHEME_OBJECT)));           \
-  declare_builtin (((unsigned long) hook), #hook);                     \
 } while (0)
 
 void
@@ -224,8 +319,6 @@ x86_64_reset_hook (void)
   int offset = (COMPILER_REGBLOCK_N_FIXED * (sizeof (SCHEME_OBJECT)));
   unsigned char * rsi_value = ((unsigned char *) Registers);
 
-  x86_64_interface_initialize ();
-
   /* These must match machines/x86-64/lapgen.scm */
 
   SETUP_REGISTER (asm_scheme_to_interface);            /* 0 */
@@ -282,54 +375,6 @@ x86_64_reset_hook (void)
   SETUP_REGISTER (asm_interrupt_continuation_2);       /* 39 */
 
   SETUP_REGISTER (asm_fixnum_shift);                   /* 40 */
-
-#ifdef _MACH_UNIX
-  {
-    vm_address_t addr;
-    vm_size_t size;
-    vm_prot_t prot;
-    vm_prot_t max_prot;
-    vm_inherit_t inheritance;
-    boolean_t shared;
-    port_t object;
-    vm_offset_t offset;
-
-    addr = ((vm_address_t) Heap);
-    if ((vm_region ((task_self ()), &addr, &size, &prot, &max_prot,
-                   &inheritance, &shared, &object, &offset))
-       != KERN_SUCCESS)
-      {
-       outf_fatal ( "compiler_reset: vm_region() failed.\n");
-       Microcode_Termination (TERM_EXIT);
-       /*NOTREACHED*/
-      }
-    if ((prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
-      {
-       if ((max_prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
-         {
-           outf_fatal (
-                       "compiler_reset: inadequate protection for Heap.\n");
-           outf_fatal ( "maximum = 0x%lx; desired = 0x%lx\n",
-                       ((unsigned long) (max_prot & VM_PROT_SCHEME)),
-                       ((unsigned long) VM_PROT_SCHEME));
-           Microcode_Termination (TERM_EXIT);
-           /*NOTREACHED*/
-         }
-       if ((vm_protect ((task_self ()), ((vm_address_t) Heap),
-                        (((char *) constant_end) - ((char *) Heap)),
-                        0, VM_PROT_SCHEME))
-           != KERN_SUCCESS)
-         {
-           outf_fatal ("Unable to change protection for Heap.\n");
-           outf_fatal ("actual = 0x%lx; desired = 0x%lx\n",
-                       ((unsigned long) (prot & VM_PROT_SCHEME)),
-                       ((unsigned long) VM_PROT_SCHEME));
-           Microcode_Termination (TERM_EXIT);
-           /*NOTREACHED*/
-         }
-      }
-  }
-#endif /* _MACH_UNIX */
 }
 
 #ifndef HAVE_FENV_H
index 0c9503d74ff930233916859bd7f7b22301038f8d..625b7e880fec509a0547c68ce512f69e38b099d3 100644 (file)
@@ -117,6 +117,7 @@ entry       0               MOV     AL,code         0xB0, code-byte
 
 */
 \f
+#define ADM_INIT_HOOK x86_64_init_hook
 #define ASM_RESET_HOOK x86_64_reset_hook
 
 #define CMPINT_USE_STRUCS 1
@@ -133,6 +134,8 @@ entry       0               MOV     AL,code         0xB0, code-byte
 #define COMPILER_REGBLOCK_EXTRA_SIZE                                   \
   (COMPILER_REGBLOCK_N_HOOKS * COMPILER_HOOK_SIZE)
 
+#define REGBLOCK_ALLOCATED_BY_INTERFACE true
+
 typedef byte_t insn_t;
 
 /* Number of insn_t units preceding entry address in which header
@@ -238,6 +241,7 @@ extern void asm_trampoline_to_interface (void);
 
 extern insn_t * read_compiled_closure_target (insn_t *);
 extern insn_t * read_uuo_target (SCHEME_OBJECT *);
+extern void x86_64_init_hook (void);
 extern void x86_64_reset_hook (void);
 
 #ifndef HAVE_FENV_H
index c944954d8934d3eb2f166fc091c8288892b75b75..aeeca86c22522114e99584d74ba41141c13a91c0 100644 (file)
@@ -37,7 +37,7 @@ USA.
    extern SCHEME_OBJECT * RegistersPtr;
 #  define Registers RegistersPtr
 #else
-   extern SCHEME_OBJECT Registers [];
+   extern __thread SCHEME_OBJECT Registers [];
 #endif
 
 #define GET_REG_O(i) (Registers[REGBLOCK_##i])
@@ -138,7 +138,7 @@ extern void set_ulong_register (unsigned int, unsigned long);
 #  define Bignum_Debug 0
 #endif
 
-extern SCHEME_OBJECT * Free;
+extern __thread SCHEME_OBJECT * Free;
 extern __thread SCHEME_OBJECT * Free_primitive;
 extern __thread SCHEME_OBJECT * heap_alloc_limit;
 extern __thread SCHEME_OBJECT * heap_start;
@@ -150,7 +150,7 @@ extern SCHEME_OBJECT * shared_heap_free;
 extern SCHEME_OBJECT * shared_heap_end;
 #endif
 
-extern SCHEME_OBJECT * stack_pointer;
+extern __thread SCHEME_OBJECT * stack_pointer;
 extern __thread SCHEME_OBJECT * stack_guard;
 extern __thread SCHEME_OBJECT * stack_start;
 extern __thread SCHEME_OBJECT * stack_end;
index b1570561db5b5385ceb519bd76b3b047decab9a6..e4bdb3a25821ead93ea431fab9862b93483b33c2 100755 (executable)
@@ -52,7 +52,8 @@ touch "${TMP_FILE}"
 
 if [ $# = 0 ]
 then
-  sed -e '/^#/D' | run_m4 | sed -e 's/@/$/g' -e 's/^\f$//'
+  sed -e '/^#/D' | run_m4 \
+  | sed -e 's/\([^\]\)@/\1$/g' -e 's/\\@/@/g' -e 's/^\f$//'
 else
   SEEN_INPUT=0
   while [ $# != 0 ]; do
@@ -68,7 +69,8 @@ else
   if [ ${SEEN_INPUT} -eq 0 ]; then
     sed -e '/^#/D' >> "${TMP_FILE}"
   fi
-  run_m4 < "${TMP_FILE}" | sed -e 's/@/$/g' -e 's/^\f$//'
+  run_m4 < "${TMP_FILE}" \
+  | sed -e 's/\([^\]\)@/\1$/g' -e 's/\\@/@/g' -e 's/^\f$//'
 fi
 
 # If m4 was successful, run_m4 has deleted the temporary file.  If
index 3a8c119d1e475a325dd45c4fc234c9577ccdc31c..b15e596d3a0ea3197b745b7dc32fbd2873bcd7df 100644 (file)
@@ -33,13 +33,17 @@ USA.
 #endif
 
 /* next free word in heap */
+#ifndef ENABLE_SMP
 SCHEME_OBJECT * Free;
+#endif
 
 /* value of Free on entry to primitive, or 0 if not in primitive */
 __thread SCHEME_OBJECT * Free_primitive = 0;
 
 /* strict limit for Free */
-__thread SCHEME_OBJECT * heap_alloc_limit;
+#ifndef ENABLE_SMP
+SCHEME_OBJECT * heap_alloc_limit;
+#endif
 
 #ifdef ENABLE_SMP
 /* the start of From space */
@@ -55,16 +59,24 @@ SCHEME_OBJECT * shared_heap_free;
 
 /* limits of local heap */
 __thread SCHEME_OBJECT * heap_start;
-__thread SCHEME_OBJECT * heap_end;
+#ifndef ENABLE_SMP
+SCHEME_OBJECT * heap_end;
+#endif
 
 /* pointer to most-recently pushed item */
+#ifndef ENABLE_SMP
 SCHEME_OBJECT * stack_pointer;
+#endif
 
 /*-strict limit for stack_pointer */
-__thread SCHEME_OBJECT * stack_guard;
+#ifndef ENABLE_SMP
+SCHEME_OBJECT * stack_guard;
+#endif
 
 /* limits of stack */
-__thread SCHEME_OBJECT * stack_start;
+#ifndef ENABLE_SMP
+SCHEME_OBJECT * stack_start;
+#endif
 __thread SCHEME_OBJECT * stack_end;
 
 /* next free word in constant space */