[pypy-commit] pypy stm-gc: Hack at et.c until it starts to make sense in the new world

arigo noreply at buildbot.pypy.org
Sat Feb 4 20:47:01 CET 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: stm-gc
Changeset: r52098:cd56dce052b4
Date: 2012-02-04 20:43 +0100
http://bitbucket.org/pypy/pypy/changeset/cd56dce052b4/

Log:	Hack at et.c until it starts to make sense in the new world

diff --git a/pypy/rpython/memory/gc/stmgc.py b/pypy/rpython/memory/gc/stmgc.py
--- a/pypy/rpython/memory/gc/stmgc.py
+++ b/pypy/rpython/memory/gc/stmgc.py
@@ -12,8 +12,8 @@
 
 first_gcflag = 1 << (LONG_BIT//2)
 
-GCFLAG_GLOBAL     = first_gcflag << 0
-GCFLAG_WAS_COPIED = first_gcflag << 1
+GCFLAG_GLOBAL     = first_gcflag << 0     # keep in sync with et.c
+GCFLAG_WAS_COPIED = first_gcflag << 1     # keep in sync with et.c
 
 
 def always_inline(fn):
@@ -199,29 +199,30 @@
     def declare_readers(self):
         # Reading functions.  Defined here to avoid the extra burden of
         # passing 'self' explicitly.
-        stm_operations = self.stm_operations
+        stm_read_word = self.stm_operations.stm_read_word
         #
         @always_inline
         def read_signed(obj, offset):
             if self.header(obj).tid & GCFLAG_GLOBAL == 0:
                 return (obj + offset).signed[0]    # local obj: read directly
             else:
-                return _read_word_global(obj, offset)   # else: call a helper
+                return stm_read_word(obj, offset)  # else: call a helper
         self.read_signed = read_signed
         #
-        @dont_inline
-        def _read_word_global(obj, offset):
-            hdr = self.header(obj)
-            if hdr.tid & GCFLAG_WAS_COPIED != 0:
-                #
-                # Look up in the thread-local dictionary.
-                localobj = stm_operations.tldict_lookup(obj)
-                if localobj:
-                    ll_assert(self.header(localobj).tid & GCFLAG_GLOBAL == 0,
-                              "stm_read: tldict_lookup() -> GLOBAL obj")
-                    return (localobj + offset).signed[0]
-            #
-            return stm_operations.stm_read_word(obj, offset)
+        # the following logic was moved to et.c to avoid a double call
+##        @dont_inline
+##        def _read_word_global(obj, offset):
+##            hdr = self.header(obj)
+##            if hdr.tid & GCFLAG_WAS_COPIED != 0:
+##                #
+##                # Look up in the thread-local dictionary.
+##                localobj = stm_operations.tldict_lookup(obj)
+##                if localobj:
+##                    ll_assert(self.header(localobj).tid & GCFLAG_GLOBAL == 0,
+##                              "stm_read: tldict_lookup() -> GLOBAL obj")
+##                    return (localobj + offset).signed[0]
+##            #
+##            return stm_operations.stm_read_word(obj, offset)
 
 
     def declare_write_barrier(self):
diff --git a/pypy/translator/stm/src_stm/et.c b/pypy/translator/stm/src_stm/et.c
--- a/pypy/translator/stm/src_stm/et.c
+++ b/pypy/translator/stm/src_stm/et.c
@@ -29,29 +29,29 @@
 
 /************************************************************/
 
+/* This is the same as the object header structure HDR
+ * declared in stmgc.py, and the same two flags */
+
+typedef struct {
+  long tid;
+  long version;
+} orec_t;
+
+enum {
+  first_gcflag      = 1 << (PYPY_LONG_BIT / 2),
+  GCFLAG_GLOBAL     = first_gcflag << 0,
+  GCFLAG_WAS_COPIED = first_gcflag << 1
+};
+
+/************************************************************/
+
 #define IS_LOCKED(num)  ((num) < 0)
 #define IS_LOCKED_OR_NEWER(num, max_age) \
   __builtin_expect(((unsigned long)(num)) > ((unsigned long)(max_age)), 0)
+
 typedef long owner_version_t;
 
-typedef volatile owner_version_t orec_t;
-
-/*** Specify the number of orecs in the global array. */
-#define NUM_STRIPES  1048576
-
-/*** declare the table of orecs */
-static char orecs[NUM_STRIPES * sizeof(orec_t)];
-
-/*** map addresses to orec table entries */
-inline static orec_t *get_orec(void* addr)
-{
-  unsigned long index = (unsigned long)addr;
-#ifdef RPY_STM_ASSERT
-  assert(!(index & (sizeof(orec_t)-1)));
-#endif
-  char *p = orecs + (index & ((NUM_STRIPES-1) * sizeof(orec_t)));
-  return (orec_t *)p;
-}
+#define get_orec(addr)  ((volatile orec_t *)(addr))
 
 #include "src_stm/lists.c"
 
@@ -59,40 +59,33 @@
 
 #define ABORT_REASONS 8
 #define SPINLOOP_REASONS 10
-#define OTHERINEV_REASONS 5
 
 struct tx_descriptor {
   void *rpython_tls_object;
+  long (*rpython_get_size)(void*);
   jmp_buf *setjmp_buf;
   owner_version_t start_time;
   owner_version_t end_time;
-  unsigned long last_known_global_timestamp;
+  /*unsigned long last_known_global_timestamp;*/
   struct OrecList reads;
   unsigned num_commits;
   unsigned num_aborts[ABORT_REASONS];
   unsigned num_spinloops[SPINLOOP_REASONS];
-  unsigned int spinloop_counter;
-  int transaction_active;
+  /*unsigned int spinloop_counter;*/
   owner_version_t my_lock_word;
   struct RedoLog redolog;   /* last item, because it's the biggest one */
 };
 
-static const struct tx_descriptor null_tx = {
-  .transaction_active = 0,
-  .my_lock_word = 0
-};
-#define NULL_TX  ((struct tx_descriptor *)(&null_tx))
-
 /* global_timestamp contains in its lowest bit a flag equal to 1
    if there is an inevitable transaction running */
 static volatile unsigned long global_timestamp = 2;
-static __thread struct tx_descriptor *thread_descriptor = NULL_TX;
+static __thread struct tx_descriptor *thread_descriptor = NULL;
 
 /************************************************************/
 
 static unsigned long get_global_timestamp(struct tx_descriptor *d)
 {
-  return (d->last_known_global_timestamp = global_timestamp);
+  return (/*d->last_known_global_timestamp =*/ global_timestamp);
 }
 
 static _Bool change_global_timestamp(struct tx_descriptor *d,
@@ -101,7 +94,7 @@
 {
   if (bool_cas(&global_timestamp, old, new))
     {
-      d->last_known_global_timestamp = new;
+      /*d->last_known_global_timestamp = new;*/
       return 1;
     }
   return 0;
@@ -110,7 +103,7 @@
 static void set_global_timestamp(struct tx_descriptor *d, unsigned long new)
 {
   global_timestamp = new;
-  d->last_known_global_timestamp = new;
+  /*d->last_known_global_timestamp = new;*/
 }
 
 static void tx_abort(int);
@@ -123,7 +116,8 @@
   d->num_spinloops[num]++;
 
   //printf("tx_spinloop(%d)\n", num);
-  
+
+#if 0
   c = d->spinloop_counter;
   d->spinloop_counter = c * 9;
   i = c & 0xff0000;
@@ -131,41 +125,41 @@
     spinloop();
     i -= 0x10000;
   }
-}
-
-static _Bool is_inevitable_or_inactive(struct tx_descriptor *d)
-{
-  return d->setjmp_buf == NULL;
+#else
+  spinloop();
+#endif
 }
 
 static _Bool is_inevitable(struct tx_descriptor *d)
 {
-  assert(d->transaction_active);
-  return is_inevitable_or_inactive(d);
+  return d->setjmp_buf == NULL;
 }
 
 /*** run the redo log to commit a transaction, and release the locks */
 static void tx_redo(struct tx_descriptor *d)
 {
-  abort();
-#if 0
   owner_version_t newver = d->end_time;
   wlog_t *item;
   /* loop in "forward" order: in this order, if there are duplicate orecs
      then only the last one has p != -1. */
   REDOLOG_LOOP_FORWARD(d->redolog, item)
     {
-      *item->addr = item->val;
+      void *globalobj = item->addr;
+      void *localobj = item->val;
+      owner_version_t p = item->p;
+      long size = d->rpython_get_size(localobj);
+      memcpy(((char *)globalobj) + sizeof(orec_t),
+             ((char *)localobj) + sizeof(orec_t),
+             size - sizeof(orec_t));
       /* but we must only unlock the orec if it's the last time it
          appears in the redolog list.  If it's not, then p == -1. */
-      if (item->p != -1)
+      if (p != -1)
         {
-          orec_t* o = get_orec(item->addr);
+          volatile orec_t* o = get_orec(globalobj);
           CFENCE;
-          *o = newver;
+          o->version = newver;
         }
     } REDOLOG_LOOP_END;
-#endif
 }
 
 /*** on abort, release locks and restore the old version number. */
@@ -176,8 +170,8 @@
     {
       if (item->p != -1)
         {
-          orec_t* o = get_orec(item->addr);
-          *o = item->p;
+          volatile orec_t* o = get_orec(item->addr);
+          o->version = item->p;
         }
     } REDOLOG_LOOP_END;
 }
@@ -190,8 +184,8 @@
     {
       if (item->p != -1)
         {
-          orec_t* o = get_orec(item->addr);
-          *o = item->p;
+          volatile orec_t* o = get_orec(item->addr);
+          o->version = item->p;
           item->p = -1;
         }
     } REDOLOG_LOOP_END;
@@ -205,11 +199,11 @@
   REDOLOG_LOOP_BACKWARD(d->redolog, item)
     {
       // get orec, read its version#
-      orec_t* o = get_orec(item->addr);
+      volatile orec_t* o = get_orec(item->addr);
       owner_version_t ovt;
 
     retry:
-      ovt = *o;
+      ovt = o->version;
 
       // if orec not locked, lock it
       //
@@ -217,7 +211,7 @@
       // reads.  Since most writes are also reads, we'll just abort under this
       // condition.  This can introduce false conflicts
       if (!IS_LOCKED_OR_NEWER(ovt, d->start_time)) {
-        if (!bool_cas(o, ovt, d->my_lock_word))
+        if (!bool_cas(&o->version, ovt, d->my_lock_word))
           goto retry;
         // save old version to item->p.  Now we hold the lock.
         // in case of duplicate orecs, only the last one has p != -1.
@@ -247,9 +241,6 @@
 {
   d->reads.size = 0;
   redolog_clear(&d->redolog);
-  assert(d->transaction_active);
-  d->transaction_active = 0;
-  d->setjmp_buf = NULL;
 }
 
 static void tx_cleanup(struct tx_descriptor *d)
@@ -262,10 +253,9 @@
 
 static void tx_restart(struct tx_descriptor *d)
 {
-  jmp_buf *env = d->setjmp_buf;
   tx_cleanup(d);
   tx_spinloop(0);
-  longjmp(*env, 1);
+  longjmp(*d->setjmp_buf, 1);
 }
 
 /*** increase the abort count and restart the transaction */
@@ -295,7 +285,7 @@
   for (i=0; i<d->reads.size; i++)
     {
     retry:
-      ovt = *(d->reads.items[i]);
+      ovt = d->reads.items[i]->version;
       if (IS_LOCKED_OR_NEWER(ovt, d->start_time))
         {
           // If locked, we wait until it becomes unlocked.  The chances are
@@ -325,7 +315,7 @@
   assert(!is_inevitable(d));
   for (i=0; i<d->reads.size; i++)
     {
-      ovt = *(d->reads.items[i]);      // read this orec
+      ovt = d->reads.items[i]->version;      // read this orec
       if (IS_LOCKED_OR_NEWER(ovt, d->start_time))
         {
           if (!IS_LOCKED(ovt))
@@ -421,28 +411,29 @@
 }
 
 /* lazy/lazy read instrumentation */
-long stm_read_word(long* addr)
+long stm_read_word(void* addr, long offset)
 {
   struct tx_descriptor *d = thread_descriptor;
+  volatile orec_t *o = get_orec(addr);
+  owner_version_t ovt;
+
+  if ((o->tid & GCFLAG_WAS_COPIED) != 0)
+    {
+      /* Look up in the thread-local dictionary. */
+      wlog_t *found;
+      REDOLOG_FIND(d->redolog, addr, found, goto not_found);
+      orec_t *localobj = (orec_t *)found->val;
 #ifdef RPY_STM_ASSERT
-  assert((((long)addr) & (sizeof(void*)-1)) == 0);
+      assert((localobj->tid & GCFLAG_GLOBAL) == 0);
 #endif
-  if (!d->transaction_active)
-    return *addr;
+      return *(long *)(((char *)localobj) + offset);
 
-  // check writeset first
-  wlog_t* found;
-  REDOLOG_FIND(d->redolog, addr, found, goto not_found);
-  return found->val;
-
- not_found:;
-  // get the orec addr
-  orec_t* o = get_orec((void*)addr);
-  owner_version_t ovt;
+    not_found:;
+    }
 
  retry:
   // read the orec BEFORE we read anything else
-  ovt = *o;
+  ovt = o->version;
   CFENCE;
 
   // this tx doesn't hold any locks, so if the lock for this addr is held,
@@ -461,33 +452,22 @@
     }
 
   // orec is unlocked, with ts <= start_time.  read the location
-  long tmp = *addr;
+  long tmp = *(long *)(((char *)addr) + offset);
 
   // postvalidate AFTER reading addr:
   CFENCE;
-  if (*o != ovt)
+  if (__builtin_expect(o->version != ovt, 0))
     goto retry;       /* oups, try again */
 
-  oreclist_insert(&d->reads, o);
+  oreclist_insert(&d->reads, (orec_t*)o);
 
   return tmp;
 }
 
-void stm_write_word(long* addr, long val)
-{
-  struct tx_descriptor *d = thread_descriptor;
-  assert((((long)addr) & (sizeof(void*)-1)) == 0);
-  if (!d->transaction_active) {
-    *addr = val;
-    return;
-  }
-  redolog_insert(&d->redolog, addr, val);
-}
-
 
 static struct tx_descriptor *descriptor_init(void)
 {
-  assert(thread_descriptor == NULL_TX);
+  assert(thread_descriptor == NULL);
   if (1)  /* for hg diff */
     {
       struct tx_descriptor *d = malloc(sizeof(struct tx_descriptor));
@@ -502,7 +482,7 @@
       if (!IS_LOCKED(d->my_lock_word))
         d->my_lock_word = ~d->my_lock_word;
       assert(IS_LOCKED(d->my_lock_word));
-      d->spinloop_counter = (unsigned int)(d->my_lock_word | 1);
+      /*d->spinloop_counter = (unsigned int)(d->my_lock_word | 1);*/
 
       thread_descriptor = d;
 
@@ -518,9 +498,9 @@
 static void descriptor_done(void)
 {
   struct tx_descriptor *d = thread_descriptor;
-  assert(d != NULL_TX);
+  assert(d != NULL);
 
-  thread_descriptor = NULL_TX;
+  thread_descriptor = NULL;
 
 #ifdef RPY_STM_DEBUG_PRINT
   PYPY_DEBUG_START("stm-done");
@@ -559,10 +539,11 @@
 static void begin_transaction(jmp_buf* buf)
 {
   struct tx_descriptor *d = thread_descriptor;
-  assert(!d->transaction_active);
-  d->transaction_active = 1;
+  /* you need to call descriptor_init() before calling
+     stm_perform_transaction() */
+  assert(d != NULL);
   d->setjmp_buf = buf;
-  d->start_time = d->last_known_global_timestamp & ~1;
+  d->start_time = (/*d->last_known_global_timestamp*/ global_timestamp) & ~1;
 }
 
 static long commit_transaction(void)
@@ -635,9 +616,6 @@
   jmp_buf _jmpbuf;
   volatile long v_counter = 0;
   long counter;
-  /* you need to call descriptor_init() before calling
-     stm_perform_transaction() */
-  assert(thread_descriptor != NULL_TX);
   setjmp(_jmpbuf);
   begin_transaction(&_jmpbuf);
   counter = v_counter;
@@ -647,6 +625,7 @@
   return result;
 }
 
+#if 0
 void stm_try_inevitable(STM_CCHARP1(why))
 {
   /* when a transaction is inevitable, its start_time is equal to
@@ -703,135 +682,17 @@
   PYPY_DEBUG_STOP("stm-inevitable");
 #endif
 }
+#endif
 
 void stm_abort_and_retry(void)
 {
   tx_abort(7);     /* manual abort */
 }
 
-// XXX little-endian only!
-#define READ_PARTIAL_WORD(T, fieldsize, addr)           \
-  int misalignment = ((long)addr) & (sizeof(void*)-1);  \
-  long *p = (long*)(((char *)addr) - misalignment);     \
-  unsigned long word = stm_read_word(p);                \
-  assert(sizeof(T) == fieldsize);                       \
-  return (T)(word >> (misalignment * 8));
-
-unsigned char stm_read_partial_1(void *addr) {
-  READ_PARTIAL_WORD(unsigned char, 1, addr)
-}
-unsigned short stm_read_partial_2(void *addr) {
-  READ_PARTIAL_WORD(unsigned short, 2, addr)
-}
-#if PYPY_LONG_BIT == 64
-unsigned int stm_read_partial_4(void *addr) {
-  READ_PARTIAL_WORD(unsigned int, 4, addr)
-}
-#endif
-
-// XXX little-endian only!
-#define WRITE_PARTIAL_WORD(fieldsize, addr, nval)                       \
-  int misalignment = ((long)addr) & (sizeof(void*)-1);                  \
-  long *p = (long*)(((char *)addr) - misalignment);                     \
-  long val = ((long)nval) << (misalignment * 8);                        \
-  long word = stm_read_word(p);                                         \
-  long mask = ((1L << (fieldsize * 8)) - 1) << (misalignment * 8);      \
-  val = (val & mask) | (word & ~mask);                                  \
-  stm_write_word(p, val);
-
-void stm_write_partial_1(void *addr, unsigned char nval) {
-  WRITE_PARTIAL_WORD(1, addr, nval)
-}
-void stm_write_partial_2(void *addr, unsigned short nval) {
-  WRITE_PARTIAL_WORD(2, addr, nval)
-}
-#if PYPY_LONG_BIT == 64
-void stm_write_partial_4(void *addr, unsigned int nval) {
-  WRITE_PARTIAL_WORD(4, addr, nval)
-}
-#endif
-
-
-#if PYPY_LONG_BIT == 32
-long long stm_read_doubleword(long *addr)
-{
-  /* 32-bit only */
-  unsigned long res0 = (unsigned long)stm_read_word(addr);
-  unsigned long res1 = (unsigned long)stm_read_word(addr + 1);
-  return (((unsigned long long)res1) << 32) | res0;
-}
-
-void stm_write_doubleword(long *addr, long long val)
-{
-  /* 32-bit only */
-  stm_write_word(addr, (long)val);
-  stm_write_word(addr + 1, (long)(val >> 32));
-}
-#endif
-
-double stm_read_double(long *addr)
-{
-  long long x;
-  double dd;
-#if PYPY_LONG_BIT == 32
-  x = stm_read_doubleword(addr);   /* 32 bits */
-#else
-  x = stm_read_word(addr);         /* 64 bits */
-#endif
-  assert(sizeof(double) == 8 && sizeof(long long) == 8);
-  memcpy(&dd, &x, 8);
-  return dd;
-}
-
-void stm_write_double(long *addr, double val)
-{
-  long long ll;
-  assert(sizeof(double) == 8 && sizeof(long long) == 8);
-  memcpy(&ll, &val, 8);
-#if PYPY_LONG_BIT == 32
-  stm_write_doubleword(addr, ll);   /* 32 bits */
-#else
-  stm_write_word(addr, ll);         /* 64 bits */
-#endif
-}
-
-float stm_read_float(long *addr)
-{
-  unsigned int x;
-  float ff;
-#if PYPY_LONG_BIT == 32
-  x = stm_read_word(addr);         /* 32 bits */
-#else
-  if (((long)(char*)addr) & 7) {
-    addr = (long *)(((char *)addr) - 4);
-    x = (unsigned int)(stm_read_word(addr) >> 32);   /* 64 bits, unaligned */
-  }
-  else
-    x = (unsigned int)stm_read_word(addr);           /* 64 bits, aligned */
-#endif
-  assert(sizeof(float) == 4 && sizeof(unsigned int) == 4);
-  memcpy(&ff, &x, 4);
-  return ff;
-}
-
-void stm_write_float(long *addr, float val)
-{
-  unsigned int ii;
-  assert(sizeof(float) == 4 && sizeof(unsigned int) == 4);
-  memcpy(&ii, &val, 4);
-#if PYPY_LONG_BIT == 32
-  stm_write_word(addr, ii);         /* 32 bits */
-#else
-  stm_write_partial_4(addr, ii);    /* 64 bits */
-#endif
-}
-
 long stm_debug_get_state(void)
 {
   struct tx_descriptor *d = thread_descriptor;
-  if (d == NULL_TX)
-    return -1;
-  if (!d->transaction_active)
+  if (d == NULL)
     return 0;
   if (!is_inevitable(d))
     return 1;
@@ -846,9 +707,11 @@
 }
 
 
-void stm_set_tls(void *newtls)
+void stm_set_tls(void *newtls, long (*getsize)(void*))
 {
-  descriptor_init()->rpython_tls_object = newtls;
+  struct tx_descriptor *d = descriptor_init();
+  d->rpython_tls_object = newtls;
+  d->rpython_get_size = getsize;
 }
 
 void *stm_get_tls(void)
diff --git a/pypy/translator/stm/src_stm/et.h b/pypy/translator/stm/src_stm/et.h
--- a/pypy/translator/stm/src_stm/et.h
+++ b/pypy/translator/stm/src_stm/et.h
@@ -12,7 +12,7 @@
 #include "src/commondefs.h"
 
 
-void stm_set_tls(void *);
+void stm_set_tls(void *, long(*)(void*));
 void *stm_get_tls(void);
 void stm_del_tls(void);
 
@@ -20,8 +20,11 @@
 void stm_tldict_add(void *, void *);
 void stm_tlidct_enum(void(*)(void*, void*));
 
+long stm_read_word(void *, long);
 
 
+#if 0
+
 #ifdef RPY_STM_ASSERT
 #  define STM_CCHARP1(arg)    char* arg
 #  define STM_EXPLAIN1(info)  info
@@ -69,5 +72,7 @@
 void stm_write_doubleword(long *addr, long long val);
 #endif
 
+#endif  /* 0 */
+
 
 #endif  /* _ET_H */
diff --git a/pypy/translator/stm/stmgcintf.py b/pypy/translator/stm/stmgcintf.py
--- a/pypy/translator/stm/stmgcintf.py
+++ b/pypy/translator/stm/stmgcintf.py
@@ -6,6 +6,7 @@
     return staticmethod(_rffi_stm.llexternal(name, args, result))
 
 CALLBACK = lltype.Ptr(lltype.FuncType([llmemory.Address] * 2, lltype.Void))
+GETSIZE  = lltype.Ptr(lltype.FuncType([llmemory.Address], lltype.Signed))
 
 
 class StmOperations(object):
@@ -13,7 +14,8 @@
     def _freeze_(self):
         return True
 
-    set_tls = smexternal('stm_set_tls', [llmemory.Address], lltype.Void)
+    set_tls = smexternal('stm_set_tls', [llmemory.Address, GETSIZE],
+                         lltype.Void)
     get_tls = smexternal('stm_get_tls', [], llmemory.Address)
     del_tls = smexternal('stm_del_tls', [], lltype.Void)
 
diff --git a/pypy/translator/stm/test/test_stmgcintf.py b/pypy/translator/stm/test/test_stmgcintf.py
--- a/pypy/translator/stm/test/test_stmgcintf.py
+++ b/pypy/translator/stm/test/test_stmgcintf.py
@@ -1,7 +1,7 @@
 import random
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.annlowlevel import llhelper
-from pypy.translator.stm.stmgcintf import StmOperations, CALLBACK
+from pypy.translator.stm.stmgcintf import StmOperations, CALLBACK, GETSIZE
 
 stm_operations = StmOperations()
 
@@ -12,7 +12,7 @@
     # assume that they are really thread-local; not checked here
     s = lltype.malloc(lltype.Struct('S'), flavor='raw')
     a = llmemory.cast_ptr_to_adr(s)
-    stm_operations.set_tls(a)
+    stm_operations.set_tls(a, lltype.nullptr(GETSIZE.TO))
     assert stm_operations.get_tls() == a
     stm_operations.del_tls()
     lltype.free(s, flavor='raw')
@@ -25,11 +25,15 @@
         s = lltype.malloc(TLS, flavor='raw', immortal=True)
         self.tls = s
         a = llmemory.cast_ptr_to_adr(s)
-        stm_operations.set_tls(a)
+        getsize = llhelper(GETSIZE, self.getsize)
+        stm_operations.set_tls(a, getsize)
 
     def teardown_method(self, meth):
         stm_operations.del_tls()
 
+    def getsize(self, obj):
+        xxx
+
     def test_set_get_del(self):
         a = llmemory.cast_ptr_to_adr(self.tls)
         assert stm_operations.get_tls() == a


More information about the pypy-commit mailing list