-
Notifications
You must be signed in to change notification settings - Fork 67
/
sqMemoryAccess.h
388 lines (354 loc) · 18.6 KB
/
sqMemoryAccess.h
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
/* sqMemoryAccess.h -- memory accessors (and associated type definitions)
*
* Author: Ian.Piumarta@squeakland.org
*
* Last edited: 2013-10-14 12:23:39 by eliot on McStalker
*/
/* Systematic use of the macros defined in this file within the Interpreter,
* ObjectMemory and plugins will permit all four combinations of 32/64-bit
* image and 32/64-bit host to compile and run correctly. (Code that uses
* explicit casts and/or integer constants in arithmetic on object pointers
* will invariably fail in at least one of the four possible combinations.)
*/
#ifndef __sqMemoryAccess_h
#define __sqMemoryAccess_h
#include "config.h"
#include "interp.h"
#ifndef SIZEOF_LONG
# if LLP64
# define SIZEOF_LONG 4
# else
# define SIZEOF_LONG SIZEOF_VOID_P /* default is sizeof(long)==sizeof(void *) */
# endif
#endif
#if (SQ_VI_BYTES_PER_WORD == 4)
# define SQ_IMAGE32 1
# define SQ_IMAGE64 0
#else
# define SQ_IMAGE64 1
# define SQ_IMAGE32 0
#endif
#if (SQ_IMAGE64 || SPURVM)
# define OBJECTS_64BIT_ALIGNED 1
# define OBJECTS_32BIT_ALIGNED 0
#else
# define OBJECTS_32BIT_ALIGNED 1
# define OBJECTS_64BIT_ALIGNED 0
#endif
#if (SIZEOF_VOID_P == 4)
# define SQ_HOST32 1
#elif (SIZEOF_VOID_P == 8)
# define SQ_HOST64 1
#else
# error host is neither 32- nor 64-bit?
#endif
/* sqInt is a signed integer with size adequate for holding an Object Oriented Pointer (or immediate value)
- that is 32bits long on a 32bits image or 64bits long on a 64bits image
we could use C99 int32_t and int64_t once retiring legacy compiler support this time has not yet come
usqInt is the unsigned flavour
SQABS is a macro for taking absolute value of an sqInt */
#if SQ_IMAGE32
typedef int sqInt;
typedef unsigned int usqInt;
#define PRIdSQINT "d"
#define PRIuSQINT "u"
#define PRIxSQINT "x"
#define PRIXSQINT "X"
# define SQABS abs
#elif SQ_HOST64 && (SIZEOF_LONG == 8)
typedef long sqInt;
typedef unsigned long usqInt;
#define PRIdSQINT "ld"
#define PRIuSQINT "lu"
#define PRIxSQINT "lx"
#define PRIXSQINT "lX"
# define SQABS labs
#elif (SIZEOF_LONG_LONG != 8)
# error long long integers are not 64-bits wide?
#else
typedef long long sqInt;
typedef unsigned long long usqInt;
#define PRIdSQINT "lld"
#define PRIuSQINT "llu"
#define PRIxSQINT "llx"
#define PRIXSQINT "llX"
# define SQABS llabs
#endif
/* sqLong is a signed integer with at least 64bits on both 32 and 64 bits images
usqLong is the unsigned flavour
SQLABS is a macro for taking absolute value of a sqLong */
#if !defined(sqLong)
# if SIZEOF_LONG == 8
# define sqLong long
# define usqLong unsigned long
# define SQLABS labs
# elif _MSC_VER
# define sqLong __int64
# define usqLong unsigned __int64
# define SQLABS llabs
# else
# define sqLong long long
# define usqLong unsigned long long
# define SQLABS llabs
# endif
#endif /* !defined(sqLong) */
/* sqIntptr_t is a signed integer with enough bits to hold a pointer
usqIntptr_t is the unsigned flavour
this is essentially C99 intptr_t and uintptr_t but we support legacy compilers
the C99 printf formats macros are also defined with SQ prefix */
#if SIZEOF_LONG == SIZEOF_VOID_P
typedef long sqIntptr_t;
typedef unsigned long usqIntptr_t;
#define PRIdSQPTR "ld"
#define PRIuSQPTR "lu"
#define PRIxSQPTR "lx"
#define PRIXSQPTR "lX"
#else
typedef long long sqIntptr_t;
typedef unsigned long long usqIntptr_t;
#define PRIdSQPTR "lld"
#define PRIuSQPTR "llu"
#define PRIxSQPTR "llx"
#define PRIXSQPTR "llX"
#endif
#if SQ_HOST64 && SQ_IMAGE32
extern char *sqMemoryBase;
# define SQ_FAKE_MEMORY_OFFSET 16 // (1*1024*1024) /* nonzero to debug addr xlation */
#else
# define sqMemoryBase 0
#endif
#ifdef USE_INLINE_MEMORY_ACCESSORS
/* Use static inline functions when the compiler produces efficient code for small accessors.
These are preferred because static type checking will prevent inadvertent confusion of pointers and oops. */
static inline sqInt byteAtPointer(char *ptr) { return (sqInt)(*((unsigned char *)ptr)); }
static inline sqInt byteAtPointerput(char *ptr, int val) { return (sqInt)(*((unsigned char *)ptr)= (unsigned char)val); }
static inline sqInt shortAtPointer(char *ptr) { return (sqInt)(*((short *)ptr)); }
static inline sqInt shortAtPointerput(char *ptr, int val) { return (sqInt)(*((short *)ptr)= (short)val); }
static inline sqInt intAtPointer(char *ptr) { return (sqInt)(*((int *)ptr)); }
static inline sqInt intAtPointerput(char *ptr, int val) { return (sqInt)(*((int *)ptr)= val); }
static inline sqInt longAtPointer(char *ptr) { return *(sqInt *)ptr; }
static inline sqInt longAtPointerput(char *ptr, sqInt val) { return *(sqInt *)ptr= val; }
static inline usqInt unsignedLongAtPointer(char *ptr) { return *(usqInt *)ptr; }
static inline usqInt unsignedLongAtPointerput(char *ptr, usqInt val) { return *(usqInt *)ptr= val; }
static inline sqLong long64AtPointer(char *ptr) { return *(sqLong *)ptr; }
static inline sqLong long64AtPointerput(char *ptr, sqLong val) { return *(sqLong *)ptr= val; }
static inline float singleFloatAtPointer(char *ptr) { return *(float *)ptr; }
static inline float singleFloatAtPointerput(char *ptr, float val) { return *(float *)ptr= val; }
static inline double floatAtPointer(char *ptr) { return *(double *)ptr; }
static inline double floatAtPointerput(char *ptr, double val) { return *(double *)ptr= val; }
static inline float float32At(char *ptr) { return *(float *)ptr; }
static inline float float32Atput(char *ptr, float val) { return *(float *)ptr= val; }
static inline double float64At(char *ptr) { return *(double *)ptr; }
static inline double float64Atput(char *ptr, double val) { return *(double *)ptr= val; }
static inline sqInt oopAtPointer(char *ptr) { return *(sqInt *)ptr; }
static inline sqInt oopAtPointerput(char *ptr, sqInt val) { return (sqInt)(*(sqInt *)ptr= val); }
# if defined(sqMemoryBase) && !sqMemoryBase
static inline char *pointerForOop(usqInt oop) { return (char *)oop; }
static inline sqInt oopForPointer(void *ptr) { return (sqInt)ptr; }
# else
static inline char *pointerForOop(usqInt oop) { return sqMemoryBase + oop; }
static inline sqInt oopForPointer(void *ptr) { return (sqInt)(ptr - sqMemoryBase); }
# endif
static inline sqInt byteAt(sqInt oop) { return byteAtPointer(pointerForOop(oop)); }
static inline sqInt uint8At(sqInt oop) { return byteAt(oop); }
static inline sqInt byteAtput(sqInt oop, int val) { return byteAtPointerput(pointerForOop(oop), val); }
static inline sqInt shortAt(sqInt oop) { return shortAtPointer(pointerForOop(oop)); }
static inline sqInt uint16At(sqInt oop) { return shortAt(oop); }
static inline sqInt shortAtput(sqInt oop, int val) { return shortAtPointerput(pointerForOop(oop), val); }
static inline sqInt intAt(sqInt oop) { return intAtPointer(pointerForOop(oop)); }
static inline sqInt intAtput(sqInt oop, int val) { return intAtPointerput(pointerForOop(oop), val); }
static inline sqInt longAt(sqInt oop) { return longAtPointer(pointerForOop(oop)); }
static inline sqInt uint32At(sqInt oop) { return longAt(oop); }
static inline sqInt longAtput(sqInt oop, sqInt val) { return longAtPointerput(pointerForOop(oop), val); }
static inline usqInt unsignedLongAt(sqInt oop) { return unsignedLongAtPointer(pointerForOop(oop)); }
static inline usqInt unsignedLongAtput(sqInt oop, usqInt val) { return unsignedLongAtPointerput(pointerForOop(oop), val); }
static inline sqLong long64At(sqInt oop) { return long64AtPointer(pointerForOop(oop)); }
static inline sqInt uint64At(sqInt oop) { return long64At(oop); }
static inline sqLong long64Atput(sqInt oop, sqLong val) { return long64AtPointerput(pointerForOop(oop), val); }
static inline sqInt oopAt(sqInt oop) { return oopAtPointer(pointerForOop(oop)); }
static inline sqInt oopAtput(sqInt oop, sqInt val) { return oopAtPointerput(pointerForOop(oop), val); }
static inline char* pointerAtPointer(char *ptr) { return *(char **)ptr; }
static inline char* pointerAtPointerput(char *ptr, char* val) { return *(char **)ptr = val; }
static inline signed char int8AtPointer(char *ptr) { return (*((signed char *)ptr)); }
static inline signed char int8AtPointerput(char *ptr, signed char val) { return (*((signed char *)ptr)= val); }
static inline unsigned char uint8AtPointer(char *ptr) { return (*((unsigned char *)ptr)); }
static inline unsigned char uint8AtPointerput(char *ptr, unsigned char val) { return (*((unsigned char *)ptr)= val); }
static inline short int16AtPointer(char *ptr) { return (*((short *)ptr)); }
static inline short int16AtPointerput(char *ptr, short val) { return (*((short *)ptr)= val); }
static inline unsigned short uint16AtPointer(char *ptr) { return (*((unsigned short *)ptr)); }
static inline unsigned short uint16AtPointerput(char *ptr, unsigned short val) { return (*((unsigned short *)ptr)= val); }
static inline int int32AtPointer(char *ptr) { return (*((int *)ptr)); }
static inline int int32AtPointerput(char *ptr, int val) { return (*((int *)ptr)= val); }
static inline unsigned int uint32AtPointer(char *ptr) { return (*((unsigned int *)ptr)); }
static inline unsigned int uint32AtPointerput(char *ptr, unsigned int val) { return (*((unsigned int *)ptr)= val); }
static inline sqLong int64AtPointer(char *ptr) { return (*((sqLong *)ptr)); }
static inline sqLong int64AtPointerput(char *ptr, sqLong val) { return (*((sqLong *)ptr)= val); }
static inline usqLong uint64AtPointer(char *ptr) { return (*((usqLong *)ptr)); }
static inline usqLong uint64AtPointerput(char *ptr, usqLong val) { return (*((usqLong *)ptr)= val); }
static inline sqLong asIEEE64BitWord(double val) {return *((sqLong*)&val); }
static inline unsigned int asIEEE32BitWord(float val) {return *((unsigned int*)&val); }
#else /* USE_INLINE_MEMORY_ACCESSORS */
/* Use macros when static inline functions aren't efficient. */
# define byteAtPointer(ptr) ((sqInt)(*((unsigned char *)(ptr))))
# define byteAtPointerput(ptr,val) ((sqInt)(*((unsigned char *)(ptr))= (unsigned char)(val)))
# define shortAtPointer(ptr) ((sqInt)(*((short *)(ptr))))
# define shortAtPointerput(ptr,val) ((sqInt)(*((short *)(ptr))= (short)(val)))
# define intAtPointer(ptr) ((sqInt)(*((int *)(ptr))))
# define intAtPointerput(ptr,val) ((sqInt)(*((int *)(ptr))= (int)(val)))
# define longAtPointer(ptr) (*(sqInt *)(ptr))
# define longAtPointerput(ptr,val) (*(sqInt *)(ptr)= (sqInt)(val))
# define unsignedLongAtPointer(ptr) (*(usqInt *)(ptr))
# define unsignedLongAtPointerput(ptr,val) (*(usqInt *)(ptr)= (usqInt)(val))
# define long64AtPointer(ptr) (*(sqLong *)(ptr))
# define long64AtPointerput(ptr,val) (*(sqLong *)(ptr)= (sqLong)(val))
# define long32AtPointer(ptr) (*(int32_t *)(ptr))
# define long32AtPointerput(ptr,val) (*(int32_t *)(ptr)= (int32_t)(val))
# define singleFloatAtPointer(ptr) (*(float*)(ptr))
# define singleFloatAtPointerput(ptr, val) (*(float*)(ptr) = val)
# define floatAtPointer(ptr) (*(double*)(ptr))
# define floatAtPointerput(ptr, val) (*(double*)(ptr) = val)
# define float32At(ptr) (*(float*)(ptr))
# define float32Atput(ptr, val) (*(float*)(ptr) = val)
# define float64At(ptr) (*(double*)(ptr))
# define float64Atput(ptr, val) (*(double*)(ptr) = val)
# define pointerAtPointer(ptr) (*(char**)(ptr))
# define pointerAtPointerput(ptr, val) (*(char**)(ptr) = val)
# define oopAtPointer(ptr) (*(sqInt *)(ptr))
# define oopAtPointerput(ptr,val) (*(sqInt *)(ptr)= (sqInt)(val))
# if defined(sqMemoryBase) && !sqMemoryBase
# define pointerForOop(oop) ((char *)(oop))
# define oopForPointer(ptr) ((sqInt)(ptr))
# define atPointerArg(oop) oop
# else
# define pointerForOop(oop) ((char *)(sqMemoryBase + ((usqInt)(oop))))
# define oopForPointer(ptr) ((sqInt)(((char *)(ptr)) - (sqMemoryBase)))
# define atPointerArg(oop) sqMemoryBase + (usqInt)(oop)
# endif
# define byteAt(oop) byteAtPointer(atPointerArg(oop))
# define uint8At(oop) byteAt(oop)
# define byteAtput(oop,val) byteAtPointerput(atPointerArg(oop), val)
# define shortAt(oop) shortAtPointer(atPointerArg(oop))
# define uint16At(oop) shortAt(oop)
# define shortAtput(oop,val) shortAtPointerput(atPointerArg(oop), val)
# define longAt(oop) longAtPointer(atPointerArg(oop))
# define uint32At(oop) longAt(oop)
# define longAtput(oop,val) longAtPointerput(atPointerArg(oop), val)
# define unsignedLongAt(oop) unsignedLongAtPointer(atPointerArg(oop))
# define unsignedLongAtput(oop,val) unsignedLongAtPointerput(atPointerArg(oop), val)
# define long64At(oop) long64AtPointer(atPointerArg(oop))
# define uint64At(oop) long64At(oop)
# define long64Atput(oop,val) long64AtPointerput(atPointerArg(oop), val)
# define long32At(oop) long32AtPointer(atPointerArg(oop))
# define long32Atput(oop,val) long32AtPointerput(atPointerArg(oop), val)
# define intAt(oop) intAtPointer(atPointerArg(oop))
# define intAtput(oop,val) intAtPointerput(atPointerArg(oop), val)
# define oopAt(oop) oopAtPointer(atPointerArg(oop))
# define oopAtput(oop,val) oopAtPointerput(atPointerArg(oop), val)
# define int8AtPointer(ptr) (*(signed char*)(ptr))
# define int8AtPointerput(ptr, val) (*(signed char*)(ptr) = val)
# define uint8AtPointer(ptr) (*(unsigned char*)(ptr))
# define uint8AtPointerput(ptr, val) (*(unsigned char*)(ptr) = val)
# define int16AtPointer(ptr) (*(signed short*)(ptr))
# define int16AtPointerput(ptr, val) (*(signed short*)(ptr) = val)
# define uint16AtPointer(ptr) (*(unsigned short*)(ptr))
# define uint16AtPointerput(ptr, val) (*(unsigned short*)(ptr) = val)
# define int32AtPointer(ptr) (*(signed int*)(ptr))
# define int32AtPointerput(ptr, val) (*(signed int*)(ptr) = val)
# define uint32AtPointer(ptr) (*(unsigned int*)(ptr))
# define uint32AtPointerput(ptr, val) (*(unsigned int*)(ptr) = val)
# define int64AtPointer(ptr) (*(sqLong*)(ptr))
# define int64AtPointerput(ptr, val) (*(sqLong*)(ptr) = val)
# define uint64AtPointer(ptr) (*(usqLong*)(ptr))
# define uint64AtPointerput(ptr, val) (*(usqLong*)(ptr) = val)
# define asIEEE64BitWord(val) (*((sqLong*)&val))
# define asIEEE32BitWord(val) (*((unsigned int*)&val))
#endif /* USE_INLINE_MEMORY_ACCESSORS */
#define long32At intAt
#define long32Atput intAtput
/* platform-dependent float conversion macros.
* Note: Second argument must be a variable name, not an expression!
* Pre-Cog systems stored floats in Mac PowerPC big-endian format.
* BigEndianFloats selects this behaviour for backwards-compatibility.
* RISC systems typically insist on double-word alignment of double-words, but
* the heap is only word-aligned. OBJECTS_32BIT_ALIGNED selects word access.
*/
#if BigEndianFloats && !VMBIGENDIAN
/* this is to allow strict aliasing assumption in the optimizer */
typedef union { double d; int i[sizeof(double) / sizeof(int)]; } _swapper;
/* word-based copy with swapping for non-PowerPC order */
# define storeFloatAtPointerfrom(intPointerToFloat, doubleVar) do { \
*((int *)(intPointerToFloat) + 0) = ((_swapper *)(&doubleVar))->i[1]; \
*((int *)(intPointerToFloat) + 1) = ((_swapper *)(&doubleVar))->i[0]; \
} while (0)
# define fetchFloatAtPointerinto(intPointerToFloat, doubleVar) do { \
((_swapper *)(&doubleVar))->i[1] = *((int *)(intPointerToFloat) + 0); \
((_swapper *)(&doubleVar))->i[0] = *((int *)(intPointerToFloat) + 1); \
} while (0)
# else
# define storeFloatAtPointerfrom(intPointerToFloat, doubleVar) \
memcpy((char *)intPointerToFloat,&doubleVar,sizeof(double));
# define fetchFloatAtPointerinto(intPointerToFloat, doubleVar) \
memcpy(&doubleVar,(char *)intPointerToFloat,sizeof(double));
#endif /* !(BigEndianFloats && !VMBIGENDIAN) && !OBJECTS_32BIT_ALIGNED */
# define storeSingleFloatAtPointerfrom(intPointerToFloat, floatVar) \
do {float __f=floatVar; memcpy((char *)intPointerToFloat,&__f,sizeof(float));} while(0)
# define fetchSingleFloatAtPointerinto(intPointerToFloat, floatVar) \
do {float __f; memcpy(&__f,(char *)intPointerToFloat,sizeof(float)); floatVar=__f;} while(0)
#define storeFloatAtfrom(i, doubleVar) storeFloatAtPointerfrom(pointerForOop(i), doubleVar)
#define fetchFloatAtinto(i, doubleVar) fetchFloatAtPointerinto(pointerForOop(i), doubleVar)
#define storeSingleFloatAtfrom(i, floatVar) storeSingleFloatAtPointerfrom(pointerForOop(i), floatVar)
#define fetchSingleFloatAtinto(i, floatVar) fetchSingleFloatAtPointerinto(pointerForOop(i), floatVar)
/* These accessors are for accelerating byte swapping
whenever intrinsics or other fast functions are available */
/* Compatibility with non-clang compilers */
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
/* GCC and Clang recent versions provide intrinsic byte swaps via builtins */
#if (defined(__clang__) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64)) \
|| (defined(__GNUC__ ) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
# define SQ_SWAP_4_BYTES(x) __builtin_bswap32(x)
# define SQ_SWAP_8_BYTES(x) __builtin_bswap64(x)
#elif defined(__linux__)
# include <byteswap.h>
# define SQ_SWAP_4_BYTES(x) bswap_32(x)
# define SQ_SWAP_8_BYTES(x) bswap_64(x)
#elif defined(_MSC_VER)
# include <stdlib.h>
# define SQ_SWAP_4_BYTES(x) _byteswap_ulong(x)
# define SQ_SWAP_8_BYTES(x) _byteswap_uint64(x)
#else
# define SQ_SWAP_4_BYTES(x) \
(((unsigned int)(x) << 24) | \
(((unsigned int)(x) << 8) & 0xff0000U) | \
(((unsigned int)(x) >> 8) & 0xff00U) | \
( (unsigned int)(x) >> 24))
# define SQ_SWAP_8_BYTES(x) \
(((unsigned long long)(x) << 56) | \
(((unsigned long long)(x) << 40) & 0xff000000000000ULL) | \
(((unsigned long long)(x) << 24) & 0xff0000000000ULL) | \
(((unsigned long long)(x) << 8) & 0xff00000000ULL) | \
(((unsigned long long)(x) >> 8) & 0xff000000ULL) | \
(((unsigned long long)(x) >> 24) & 0xff0000ULL) | \
(((unsigned long long)(x) >> 40) & 0xff00ULL) | \
( (unsigned long long)(x) >> 56))
#endif
/* Since Large Integers are Bytes Oops allways stored as little endian,
the following macros are handy to retrieve 4 or 8 byte limbs */
#if VMBIGENDIAN
# define SQ_SWAP_4_BYTES_IF_BIGENDIAN(x) SQ_SWAP_4_BYTES(x)
# define SQ_SWAP_8_BYTES_IF_BIGENDIAN(x) SQ_SWAP_8_BYTES(x)
#else
# define SQ_SWAP_4_BYTES_IF_BIGENDIAN(x) (x)
# define SQ_SWAP_8_BYTES_IF_BIGENDIAN(x) (x)
#endif
/* This doesn't belong here, but neither do 'self flag: ...'s belong in the
image. We use a macro, not an inline function; we need no trace of flag.
*/
#define flag(foo) (void)0
/* heap debugging facilities in sqHeapMap.c */
extern void clearHeapMap(void);
extern int heapMapAtWord(void *wordPointer);
extern void heapMapAtWordPut(void *wordPointer, int bit);
#endif /* __sqMemoryAccess_h */