guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 14/27: VM support for raw slots


From: Andy Wingo
Subject: [Guile-commits] 14/27: VM support for raw slots
Date: Wed, 11 Nov 2015 11:39:11 +0000

wingo pushed a commit to branch master
in repository guile.

commit e7660a607cabdb0061784ada2869e47db946275b
Author: Andy Wingo <address@hidden>
Date:   Wed Oct 28 16:40:53 2015 +0000

    VM support for raw slots
    
    * libguile/loader.c (scm_find_slot_map_unlocked): Rename from
      scm_find_dead_slot_map_unlocked.
    
    * libguile/vm.c (struct slot_map_cache_entry, struct slot_map_cache)
      (find_slot_map): Rename, changing "dead_slot" to "slot".
      (enum slot_desc): New type.
      (scm_i_vm_mark_stack): Interpret slot maps as having two bits per
      slot, allowing us to indicate that a slot is live but not a pointer.
    
    * module/language/cps/compile-bytecode.scm (compile-function): Adapt to
      emit-slot-map name change.
    
    * module/system/vm/assembler.scm (<asm>): Rename dead-slot-maps field to
      slot-maps.
      (emit-slot-map): Rename from emit-dead-slot-map.
      (link-frame-maps): 2 bits per slot.
    
    * module/language/cps/slot-allocation.scm (lookup-slot-map): Rename from
      lookup-dead-slot-map.
      (compute-var-representations): New function.
      (allocate-slots): Adapt to encode two-bit slot representations.
---
 doc/ref/vm.texi                          |    4 ++
 libguile/loader.c                        |    4 +-
 libguile/loader.h                        |    4 +-
 libguile/vm.c                            |   77 ++++++++++++++++-----------
 module/language/cps/compile-bytecode.scm |    3 +-
 module/language/cps/slot-allocation.scm  |   85 +++++++++++++++++++++++++----
 module/system/vm/assembler.scm           |   26 ++++-----
 7 files changed, 139 insertions(+), 64 deletions(-)

diff --git a/doc/ref/vm.texi b/doc/ref/vm.texi
index 420671a..f97a009 100644
--- a/doc/ref/vm.texi
+++ b/doc/ref/vm.texi
@@ -427,6 +427,10 @@ A table mapping addresses in the @code{.rtl-text} to 
procedure names.
 @itemx .guile.docstrs
 @itemx .guile.docstrs.strtab
 Side tables of procedure properties, arities, and docstrings.
address@hidden .guile.docstrs.strtab
+Side table of frame maps, describing the set of live slots for ever
+return point in the program text, and whether those slots are pointers
+are not.  Used by the garbage collector.
 @item .debug_info
 @itemx .debug_abbrev
 @itemx .debug_str
diff --git a/libguile/loader.c b/libguile/loader.c
index a55bd15..97effb3 100644
--- a/libguile/loader.c
+++ b/libguile/loader.c
@@ -1,5 +1,5 @@
 /* Copyright (C) 2001, 2009, 2010, 2011, 2012
- *    2013, 2014 Free Software Foundation, Inc.
+ *    2013, 2014, 2015 Free Software Foundation, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -748,7 +748,7 @@ verify (sizeof (struct frame_map_prefix) == 8);
 verify (sizeof (struct frame_map_header) == 8);
 
 const scm_t_uint8 *
-scm_find_dead_slot_map_unlocked (const scm_t_uint32 *ip)
+scm_find_slot_map_unlocked (const scm_t_uint32 *ip)
 {
   struct mapped_elf_image *image;
   char *base;
diff --git a/libguile/loader.h b/libguile/loader.h
index 6fd9502..5c719cb 100644
--- a/libguile/loader.h
+++ b/libguile/loader.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013, 2014 Free Software 
Foundation, Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software 
Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -25,7 +25,7 @@ SCM_API SCM scm_load_thunk_from_file (SCM filename);
 SCM_API SCM scm_load_thunk_from_memory (SCM bv);
 
 SCM_INTERNAL const scm_t_uint8 *
-scm_find_dead_slot_map_unlocked (const scm_t_uint32 *ip);
+scm_find_slot_map_unlocked (const scm_t_uint32 *ip);
 
 SCM_INTERNAL void scm_bootstrap_loader (void);
 SCM_INTERNAL void scm_init_loader (void);
diff --git a/libguile/vm.c b/libguile/vm.c
index 9d9cc31..5ea6b2b 100644
--- a/libguile/vm.c
+++ b/libguile/vm.c
@@ -895,31 +895,31 @@ return_unused_stack_to_os (struct scm_vm *vp)
 #endif
 }
 
-#define DEAD_SLOT_MAP_CACHE_SIZE 32U
-struct dead_slot_map_cache_entry
+#define SLOT_MAP_CACHE_SIZE 32U
+struct slot_map_cache_entry
 {
   scm_t_uint32 *ip;
   const scm_t_uint8 *map;
 };
 
-struct dead_slot_map_cache
+struct slot_map_cache
 {
-  struct dead_slot_map_cache_entry entries[DEAD_SLOT_MAP_CACHE_SIZE];
+  struct slot_map_cache_entry entries[SLOT_MAP_CACHE_SIZE];
 };
 
 static const scm_t_uint8 *
-find_dead_slot_map (scm_t_uint32 *ip, struct dead_slot_map_cache *cache)
+find_slot_map (scm_t_uint32 *ip, struct slot_map_cache *cache)
 {
   /* The lower two bits should be zero.  FIXME: Use a better hash
      function; we don't expose scm_raw_hashq currently.  */
-  size_t slot = (((scm_t_uintptr) ip) >> 2) % DEAD_SLOT_MAP_CACHE_SIZE;
+  size_t slot = (((scm_t_uintptr) ip) >> 2) % SLOT_MAP_CACHE_SIZE;
   const scm_t_uint8 *map;
 
   if (cache->entries[slot].ip == ip)
     map = cache->entries[slot].map;
   else
     {
-      map = scm_find_dead_slot_map_unlocked (ip);
+      map = scm_find_slot_map_unlocked (ip);
       cache->entries[slot].ip = ip;
       cache->entries[slot].map = map;
     }
@@ -927,21 +927,29 @@ find_dead_slot_map (scm_t_uint32 *ip, struct 
dead_slot_map_cache *cache)
   return map;
 }
 
+enum slot_desc
+  {
+    SLOT_DESC_DEAD = 0,
+    SLOT_DESC_LIVE_RAW = 1,
+    SLOT_DESC_LIVE_SCM = 2,
+    SLOT_DESC_UNUSED = 3
+  };
+
 /* Mark the active VM stack region.  */
 struct GC_ms_entry *
 scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr,
                      struct GC_ms_entry *mark_stack_limit)
 {
   union scm_vm_stack_element *sp, *fp;
-  /* The first frame will be marked conservatively (without a dead
-     slot map).  This is because GC can happen at any point within the
-     hottest activation, due to multiple threads or per-instruction
-     hooks, and providing dead slot maps for all points in a program
-     would take a prohibitive amount of space.  */
-  const scm_t_uint8 *dead_slots = NULL;
+  /* The first frame will be marked conservatively (without a slot map).
+     This is because GC can happen at any point within the hottest
+     activation, due to multiple threads or per-instruction hooks, and
+     providing slot maps for all points in a program would take a
+     prohibitive amount of space.  */
+  const scm_t_uint8 *slot_map = NULL;
   void *upper = (void *) GC_greatest_plausible_heap_addr;
   void *lower = (void *) GC_least_plausible_heap_addr;
-  struct dead_slot_map_cache cache;
+  struct slot_map_cache cache;
 
   memset (&cache, 0, sizeof (cache));
 
@@ -953,24 +961,29 @@ scm_i_vm_mark_stack (struct scm_vm *vp, struct 
GC_ms_entry *mark_stack_ptr,
       size_t slot = nlocals - 1;
       for (slot = nlocals - 1; sp < fp; sp++, slot--)
         {
-          if (SCM_NIMP (sp->as_scm) &&
-              sp->as_ptr >= lower && sp->as_ptr <= upper)
+          enum slot_desc desc = SLOT_DESC_LIVE_SCM;
+
+          if (slot_map)
+            desc = (slot_map[slot / 4U] >> ((slot % 4U) * 2)) & 3U;
+
+          switch (desc)
             {
-              if (dead_slots)
-                {
-                  if (dead_slots[slot / 8U] & (1U << (slot % 8U)))
-                    {
-                      /* This value may become dead as a result of GC,
-                         so we can't just leave it on the stack.  */
-                      sp->as_scm = SCM_UNSPECIFIED;
-                      continue;
-                    }
-                }
-
-              mark_stack_ptr = GC_mark_and_push (sp->as_ptr,
-                                                 mark_stack_ptr,
-                                                 mark_stack_limit,
-                                                 NULL);
+            case SLOT_DESC_LIVE_RAW:
+              break;
+            case SLOT_DESC_UNUSED:
+            case SLOT_DESC_LIVE_SCM:
+              if (SCM_NIMP (sp->as_scm) &&
+                  sp->as_ptr >= lower && sp->as_ptr <= upper)
+                mark_stack_ptr = GC_mark_and_push (sp->as_ptr,
+                                                   mark_stack_ptr,
+                                                   mark_stack_limit,
+                                                   NULL);
+              break;
+            case SLOT_DESC_DEAD:
+              /* This value may become dead as a result of GC,
+                 so we can't just leave it on the stack.  */
+              sp->as_scm = SCM_UNSPECIFIED;
+              break;
             }
         }
       sp = SCM_FRAME_PREVIOUS_SP (fp);
@@ -978,7 +991,7 @@ scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry 
*mark_stack_ptr,
          Note that there may be other reasons to not have a dead slots
          map, e.g. if all of the frame's slots below the callee frame
          are live.  */
-      dead_slots = find_dead_slot_map (SCM_FRAME_RETURN_ADDRESS (fp), &cache);
+      slot_map = find_slot_map (SCM_FRAME_RETURN_ADDRESS (fp), &cache);
     }
 
   return_unused_stack_to_os (vp);
diff --git a/module/language/cps/compile-bytecode.scm 
b/module/language/cps/compile-bytecode.scm
index 1f7c664..6830d75 100644
--- a/module/language/cps/compile-bytecode.scm
+++ b/module/language/cps/compile-bytecode.scm
@@ -379,8 +379,7 @@
                      ((src . dst) (emit-mov asm (from-sp dst) (from-sp src))))
                     (lookup-parallel-moves label allocation))
           (emit-call asm proc-slot nargs)
-          (emit-dead-slot-map asm proc-slot
-                              (lookup-dead-slot-map label allocation))
+          (emit-slot-map asm proc-slot (lookup-slot-map label allocation))
           (cond
            ((and (= 1 nreq) (and rest-var) (not (maybe-slot rest-var))
                  (match (lookup-parallel-moves k allocation)
diff --git a/module/language/cps/slot-allocation.scm 
b/module/language/cps/slot-allocation.scm
index 1e349ee..9189d86 100644
--- a/module/language/cps/slot-allocation.scm
+++ b/module/language/cps/slot-allocation.scm
@@ -40,7 +40,7 @@
             lookup-nlocals
             lookup-call-proc-slot
             lookup-parallel-moves
-            lookup-dead-slot-map))
+            lookup-slot-map))
 
 (define-record-type $allocation
   (make-allocation slots constant-values call-allocs shuffles frame-sizes)
@@ -84,10 +84,10 @@
   (frame-sizes allocation-frame-sizes))
 
 (define-record-type $call-alloc
-  (make-call-alloc proc-slot dead-slot-map)
+  (make-call-alloc proc-slot slot-map)
   call-alloc?
   (proc-slot call-alloc-proc-slot)
-  (dead-slot-map call-alloc-dead-slot-map))
+  (slot-map call-alloc-slot-map))
 
 (define (lookup-maybe-slot var allocation)
   (intmap-ref (allocation-slots allocation) var (lambda (_) #f)))
@@ -121,9 +121,9 @@
 (define (lookup-parallel-moves k allocation)
   (intmap-ref (allocation-shuffles allocation) k))
 
-(define (lookup-dead-slot-map k allocation)
-  (or (call-alloc-dead-slot-map (lookup-call-alloc k allocation))
-      (error "Call has no dead slot map" k)))
+(define (lookup-slot-map k allocation)
+  (or (call-alloc-slot-map (lookup-call-alloc k allocation))
+      (error "Call has no slot map" k)))
 
 (define (lookup-nlocals k allocation)
   (intmap-ref (allocation-frame-sizes allocation) k))
@@ -764,8 +764,52 @@ are comparable with eqv?.  A tmp slot may be used."
   (persistent-intmap
    (intmap-fold-right allocate-lazy cps slots)))
 
+(define (compute-var-representations cps)
+  (define (get-defs k)
+    (match (intmap-ref cps k)
+      (($ $kargs names vars) vars)
+      (_ '())))
+  (intmap-fold
+   (lambda (label cont representations)
+     (match cont
+       (($ $kargs _ _ ($ $continue k _ exp))
+        (match (get-defs k)
+          (() representations)
+          ((var)
+           (match exp
+             (($ $values (arg))
+              (intmap-add representations var
+                          (intmap-ref representations arg)))
+             ;; FIXME: Placeholder for as-yet-unwritten primitive
+             ;; operations that define unboxed f64 values.
+             (($ $primcall 'scm->f64)
+              (intmap-add representations var 'f64))
+             (_
+              (intmap-add representations var 'scm))))
+          (vars
+           (match exp
+             (($ $values args)
+              (fold (lambda (arg var representations)
+                      (intmap-add representations var
+                                  (intmap-ref representations arg)))
+                    representations args vars))))))
+       (($ $kfun src meta self)
+        (intmap-add representations self 'scm))
+       (($ $kclause arity body alt)
+        (fold1 (lambda (var representations)
+                 (intmap-add representations var 'scm))
+               (get-defs body) representations))
+       (($ $kreceive arity kargs)
+        (fold1 (lambda (var representations)
+                 (intmap-add representations var 'scm))
+               (get-defs kargs) representations))
+       (($ $ktail) representations)))
+   cps
+   empty-intmap))
+
 (define (allocate-slots cps)
   (let*-values (((defs uses) (compute-defs-and-uses cps))
+                ((representations) (compute-var-representations cps))
                 ((live-in live-out) (compute-live-variables cps defs uses))
                 ((constants) (compute-constant-values cps))
                 ((needs-slot) (compute-needs-slot cps defs uses))
@@ -809,6 +853,23 @@ are comparable with eqv?.  A tmp slot may be used."
     (define (compute-live-out-slots slots label)
       (compute-live-slots* slots label live-out))
 
+    (define slot-desc-dead 0)
+    (define slot-desc-live-raw 1)
+    (define slot-desc-live-scm 2)
+    (define slot-desc-unused 3)
+
+    (define (compute-slot-map slots live-vars nslots)
+      (intset-fold
+       (lambda (var slot-map)
+         (match (get-slot slots var)
+           (#f slot-map)
+           (slot
+            (let ((desc (match (intmap-ref representations var)
+                          ('f64 slot-desc-live-raw)
+                          ('scm slot-desc-live-scm))))
+              (logior slot-map (ash desc (* 2 slot)))))))
+       live-vars 0))
+
     (define (allocate var hint slots live)
       (cond
        ((not (intset-ref needs-slot var))
@@ -874,9 +935,9 @@ are comparable with eqv?.  A tmp slot may be used."
                   (let ((result-slots (integers (+ proc-slot 2)
                                                 (length results))))
                     (allocate* results result-slots slots post-live)))))
-              ((dead-slot-map) (logand (1- (ash 1 (- proc-slot 2)))
-                                       (lognot post-live)))
-              ((call) (make-call-alloc proc-slot dead-slot-map)))
+              ((slot-map) (compute-slot-map slots (intmap-ref live-out label)
+                                            (- proc-slot 2)))
+              ((call) (make-call-alloc proc-slot slot-map)))
            (values slots
                    (intmap-add! call-allocs label call))))))
     
@@ -909,8 +970,8 @@ are comparable with eqv?.  A tmp slot may be used."
          (let*-values
              (((handler-live) (compute-live-in-slots slots handler))
               ((proc-slot) (compute-prompt-handler-proc-slot handler-live))
-              ((dead-slot-map) (logand (1- (ash 1 (- proc-slot 2)))
-                                       (lognot handler-live)))
+              ((slot-map)  (compute-slot-map slots (intmap-ref live-in handler)
+                                             (- proc-slot 2)))
               ((result-vars) (match (get-cont kargs)
                                (($ $kargs names vars) vars)))
               ((value-slots) (integers (1+ proc-slot) (length result-vars)))
@@ -918,7 +979,7 @@ are comparable with eqv?.  A tmp slot may be used."
                                               slots handler-live)))
            (values slots
                    (intmap-add! call-allocs label
-                                (make-call-alloc proc-slot dead-slot-map)))))))
+                                (make-call-alloc proc-slot slot-map)))))))
 
     (define (allocate-cont label cont slots call-allocs)
       (match cont
diff --git a/module/system/vm/assembler.scm b/module/system/vm/assembler.scm
index c989ec6..379539f 100644
--- a/module/system/vm/assembler.scm
+++ b/module/system/vm/assembler.scm
@@ -326,7 +326,7 @@
             constants inits
             shstrtab next-section-number
             meta sources
-            dead-slot-maps)
+            slot-maps)
   asm?
 
   ;; We write bytecode into what is logically a growable vector,
@@ -404,12 +404,11 @@
   ;;
   (sources asm-sources set-asm-sources!)
 
-  ;; A list of (pos . dead-slot-map) pairs, indicating dead slot maps.
-  ;; POS is relative to the beginning of the text section.
-  ;; DEAD-SLOT-MAP is a bitfield of slots that are dead at call sites,
-  ;; as an integer.
+  ;; A list of (pos . slot-map) pairs, indicating slot maps.  POS is
+  ;; relative to the beginning of the text section.  SLOT-MAP is a
+  ;; bitfield describing the stack at call sites, as an integer.
   ;;
-  (dead-slot-maps asm-dead-slot-maps set-asm-dead-slot-maps!))
+  (slot-maps asm-slot-maps set-asm-slot-maps!))
 
 (define-inline (fresh-block)
   (make-u32vector *block-size*))
@@ -1187,12 +1186,11 @@ returned instead."
          (cell-label (intern-cache-cell asm key sym)))
     (emit-module-box asm dst cell-label mod-name-label sym-label bound?)))
 
-(define-macro-assembler (dead-slot-map asm proc-slot dead-slot-map)
-  (unless (zero? dead-slot-map)
-    (set-asm-dead-slot-maps! asm
-                             (cons
-                              (cons* (asm-start asm) proc-slot dead-slot-map)
-                              (asm-dead-slot-maps asm)))))
+(define-macro-assembler (slot-map asm proc-slot slot-map)
+  (unless (zero? slot-map)
+    (set-asm-slot-maps! asm (cons
+                             (cons* (asm-start asm) proc-slot slot-map)
+                             (asm-slot-maps asm)))))
 
 
 
@@ -1605,7 +1603,7 @@ needed."
 
 (define (link-frame-maps asm)
   (define (map-byte-length proc-slot)
-    (ceiling-quotient (- proc-slot 2) 8))
+    (ceiling-quotient (* 2 (- proc-slot 2)) 8))
   (define (make-frame-maps maps count map-len)
     (let* ((endianness (asm-endianness asm))
            (header-pos frame-maps-prefix-len)
@@ -1630,7 +1628,7 @@ needed."
                    (bytevector-u8-set! bv map-pos (logand map #xff))
                    (write-bytes (1+ map-pos) (ash map -8)
                                 (1- byte-length))))))))))
-  (match (asm-dead-slot-maps asm)
+  (match (asm-slot-maps asm)
     (() #f)
     (in
      (let lp ((in in) (out '()) (count 0) (map-len 0))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]