### 2) The C compiler divides registers into three groups:
### - Linkage registers, used for procedure calls and global
### references. On i386 (gcc and Zortech C): %ebp, %esp.
-### - super temporaries, not preserved accross procedure calls and
+### - super temporaries, not preserved across procedure calls and
### always usable. On i386 (gcc and Zortech C): %eax, %edx, %ecx.
### - preserved registers saved by the callee if they are written.
### On i386 (gcc and Zortech C): all others (%ebx, %esi, %edi).
ifdef(`SUPPRESS_LEADING_UNDERSCORE',
`define(EVR,`$1')',
`define(EVR,`_$1')')
+ifdef(`ENABLE_SMP',
+ `define(TLVR,`%gs:$1\@ntpoff')',
+ `define(TLVR,`EVR($1)')')
# When using the Watcom C compiler with register-based calling
# conventions, source-code function names normally expand to `FOO_',
IFDASM(`.586p
.model flat')
+use_external_data(EVR(utility_table))
+
+ifdef(`ENABLE_SMP',`
+ .section .tbss,"awT",\@nobits
+ .align 4
+define(`define_tllong',`
+ .globl $1
+ .type $1 STT_TLS
+ .size $1, 4
+$1:
+ .zero 4
+')
+ 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)
+
+ .zero 128
+ .globl Registers
+ .type Registers STT_TLS
+ .size Registers, eval(REGBLOCK_SIZE_IN_OBJECTS*4)
+Registers:
+ .zero eval(REGBLOCK_SIZE_IN_OBJECTS*4)
+',`
+ifdef(`WIN32',`
+use_external_data(EVR(RegistersPtr))
+',`
+
DECLARE_DATA_SEGMENT()
declare_alignment(2)
use_external_data(EVR(stack_guard))
use_external_data(EVR(stack_pointer))
use_external_data(EVR(stack_start))
-use_external_data(EVR(utility_table))
-ifdef(`WIN32',`
-use_external_data(EVR(RegistersPtr))
-',`
define_data(Regstart)
allocate_space(Regstart,128)
define_data(Registers)
allocate_space(Registers,eval(REGBLOCK_SIZE_IN_OBJECTS*4))
-')
-
-define_data(i387_presence)
-allocate_longword(i387_presence)
-
-define_data(sse_presence)
-allocate_longword(sse_presence)
define_data(C_Stack_Pointer)
allocate_longword(C_Stack_Pointer)
define_data(C_Frame_Pointer)
allocate_longword(C_Frame_Pointer)
+')')
+
+define_data(i387_presence)
+allocate_longword(i387_presence)
+
+define_data(sse_presence)
+allocate_longword(sse_presence)
define_data(ia32_cpuid_supported)
allocate_longword(ia32_cpuid_supported)
# set esp to something funny.
define_c_label(within_c_stack)
- OP(mov,l) TW(EVR(C_Stack_Pointer),REG(eax))
+ OP(mov,l) TW(TLVR(C_Stack_Pointer),REG(eax))
# Are we currently in C, signalled by having no saved C stack pointer?
OP(cmp,l) TW(IMM(0),REG(eax))
# Yes: just call the function without messing with esp.
OP(push,l) REG(ebp) # Save frame pointer
OP(mov,l) TW(REG(esp),REG(ebp))
OP(mov,l) TW(REG(eax),REG(esp)) # Switch to C stack
- OP(mov,l) TW(IMM(0),EVR(C_Stack_Pointer))
+ OP(mov,l) TW(IMM(0),TLVR(C_Stack_Pointer))
OP(push,l) IMM(0) # Align sp to 16 bytes
OP(push,l) REG(ebp) # Save stack pointer
OP(push,l) LOF(HEX(c),REG(ebp)) # Push argument
OP(pop,l) REG(eax) # Pop argument
OP(mov,l) TW(REG(esp),REG(eax)) # Restore C stack ptr
OP(add,l) TW(IMM(8),REG(eax))
- OP(mov,l) TW(REG(eax),EVR(C_Stack_Pointer))
+ OP(mov,l) TW(REG(eax),TLVR(C_Stack_Pointer))
OP(pop,l) REG(esp) # Restore stack pointer
# and switch back to
# Scheme stack
OP(push,l) REG(ebx)
OP(mov,l) TW(LOF(8,REG(ebp)),REG(edx)) # Entry point
# Preserve frame ptr
- OP(mov,l) TW(REG(ebp),EVR(C_Frame_Pointer))
+ OP(mov,l) TW(REG(ebp),TLVR(C_Frame_Pointer))
# Preserve stack ptr
- OP(mov,l) TW(REG(esp),EVR(C_Stack_Pointer))
+ OP(mov,l) TW(REG(esp),TLVR(C_Stack_Pointer))
# Register block = %esi
# Scheme offset in NT
ifdef(`WIN32',
` OP(mov,l) TW(ABS(EVR(RegistersPtr)),regs)',
-` OP(lea,l) TW(ABS(EVR(Registers)),regs)')
+`ifdef(`ENABLE_SMP',
+` OP(mov,l) TW(%gs:0,regs)
+ OP(add,l) TW($Registers\@ntpoff,regs)',
+` OP(lea,l) TW(ABS(EVR(Registers)),regs)')')
jmp EPFR(interface_to_scheme)
define_hook_label(trampoline_to_interface)
# These two moves must happen _before_ the ffree instructions below.
# Otherwise recovery from SIGFPE there will fail.
- OP(mov,l) TW(REG(esp),EVR(stack_pointer))
- OP(mov,l) TW(rfree,EVR(Free))
+ OP(mov,l) TW(REG(esp),TLVR(stack_pointer))
+ OP(mov,l) TW(rfree,TLVR(Free))
IF387(`
OP(cmp,l) TW(IMM(0),ABS(EVR(i387_presence)))
scheme_to_interface_proceed:
')
- OP(mov,l) TW(EVR(C_Stack_Pointer),REG(esp))
- OP(mov,l) TW(EVR(C_Frame_Pointer),REG(ebp))
+ OP(mov,l) TW(TLVR(C_Stack_Pointer),REG(esp))
+ OP(mov,l) TW(TLVR(C_Frame_Pointer),REG(ebp))
# Signal to within_c_stack that we are now in C land.
- OP(mov,l) TW(IMM(0),EVR(C_Stack_Pointer))
+ OP(mov,l) TW(IMM(0),TLVR(C_Stack_Pointer))
OP(sub,l) TW(IMM(8),REG(esp)) # alloc struct return
ffree ST(7)
interface_to_scheme_proceed:
')
- OP(mov,l) TW(EVR(Free),rfree) # Free pointer = %edi
+ OP(mov,l) TW(TLVR(Free),rfree) # Free pointer = %edi
OP(mov,l) TW(LOF(REGBLOCK_VAL(),regs),REG(eax)) # Value/dynamic link
OP(mov,l) TW(IMM(ADDRESS_MASK),rmask) # = %ebp
# Restore the C stack pointer, which we zeroed back in
# scheme_to_interface, for within_c_stack.
- OP(mov,l) TW(REG(esp),EVR(C_Stack_Pointer))
- OP(mov,l) TW(EVR(stack_pointer),REG(esp))
+ OP(mov,l) TW(REG(esp),TLVR(C_Stack_Pointer))
+ OP(mov,l) TW(TLVR(stack_pointer),REG(esp))
OP(mov,l) TW(REG(eax),REG(ecx)) # Preserve if used
OP(and,l) TW(rmask,REG(ecx)) # Restore potential dynamic link
OP(mov,l) TW(REG(ecx),LOF(REGBLOCK_DLINK(),regs))
# If GC is enabled, set memtop to the heap allocation limit.
OP(test,l) TW(IMM(INT_GC),REG(ecx))
jz set_interrupt_enables_memtop_2
- OP(mov,l) TW(ABS(EVR(heap_alloc_limit)),REG(edx))
+ OP(mov,l) TW(ABS(TLVR(heap_alloc_limit)),REG(edx))
jmp set_interrupt_enables_set_memtop
set_interrupt_enables_memtop_2:
# Otherwise, there is no interrupt pending, and GC is not
# enabled, so set memtop to the absolute heap end.
- OP(mov,l) TW(ABS(EVR(heap_end)),REG(edx))
+ OP(mov,l) TW(ABS(TLVR(heap_end)),REG(edx))
set_interrupt_enables_set_memtop:
OP(mov,l) TW(REG(edx),LOF(REGBLOCK_MEMTOP(),regs))
set_interrupt_enables_determine_stack_guard:
OP(test,l) TW(IMM(INT_Stack_Overflow),REG(ecx))
jz set_interrupt_enables_stack_guard_1
- OP(mov,l) TW(ABS(EVR(stack_guard)),REG(edx))
+ OP(mov,l) TW(ABS(TLVR(stack_guard)),REG(edx))
jmp set_interrupt_enables_set_stack_guard
set_interrupt_enables_stack_guard_1:
- OP(mov,l) TW(ABS(EVR(stack_start)),REG(edx))
+ OP(mov,l) TW(ABS(TLVR(stack_start)),REG(edx))
set_interrupt_enables_set_stack_guard:
OP(mov,l) TW(REG(edx),LOF(REGBLOCK_STACK_GUARD(),regs))
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])
# define Bignum_Debug 0
#endif
-extern SCHEME_OBJECT * Free;
-extern SCHEME_OBJECT * Free_primitive;
-extern SCHEME_OBJECT * heap_alloc_limit;
-extern SCHEME_OBJECT * heap_start;
-extern SCHEME_OBJECT * heap_end;
+extern __thread SCHEME_OBJECT * Free;
+extern __thread SCHEME_OBJECT * Free_primitive;
+extern __thread SCHEME_OBJECT * heap_alloc_limit;
+extern __thread SCHEME_OBJECT * heap_start;
+extern __thread SCHEME_OBJECT * heap_end;
#ifdef ENABLE_SMP
extern SCHEME_OBJECT * p0_heap_start;
extern SCHEME_OBJECT * shared_heap_start;
extern SCHEME_OBJECT * shared_heap_end;
#endif
-extern SCHEME_OBJECT * stack_pointer;
-extern SCHEME_OBJECT * stack_guard;
-extern SCHEME_OBJECT * stack_start;
-extern SCHEME_OBJECT * stack_end;
+extern __thread SCHEME_OBJECT * stack_pointer;
+extern __thread SCHEME_OBJECT * stack_guard;
+extern __thread SCHEME_OBJECT * stack_start;
+extern __thread SCHEME_OBJECT * stack_end;
extern SCHEME_OBJECT * constant_alloc_next;
extern SCHEME_OBJECT * constant_start;
\f
/* Address of the most recent return code in the stack. This is
only meaningful while in compiled code. */
-extern SCHEME_OBJECT * last_return_code;
+extern __thread SCHEME_OBJECT * last_return_code;
extern SCHEME_OBJECT fixed_objects;
extern SCHEME_OBJECT ephemeron_array;
extern const char * term_messages [];
extern const char * fixed_objects_names [];
-extern bool trapping;
+extern __thread bool trapping;
extern const char * scheme_program_name;
extern const char * OS_Name;
extern unsigned long heap_reserved;
/* Amount of space needed when GC requested */
-extern unsigned long gc_space_needed;
+extern __thread unsigned long gc_space_needed;
#ifdef ENABLE_SMP
-extern unsigned long gc_shared_space_needed;
+extern __thread unsigned long gc_shared_space_needed;
#endif
/* Number of new ephemerons requested from the GC. */