guile-commits
[Top][All Lists]
Advanced

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

[Guile-commits] GNU Guile branch, wip-rtl-halloween, updated. v2.1.0-344


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, wip-rtl-halloween, updated. v2.1.0-344-g581a4eb
Date: Thu, 07 Nov 2013 22:03:56 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=581a4eb82b1534970060e3cbd79b9a96d351edf9

The branch, wip-rtl-halloween has been updated
       via  581a4eb82b1534970060e3cbd79b9a96d351edf9 (commit)
       via  72b82b0f210ef47798133dabf2a81eef3e036ba6 (commit)
       via  e15aa022847507c3eeb84c180d20a4209ece1cb6 (commit)
       via  0128bb9c38b28e74675e72539a162b5cf9848845 (commit)
      from  4b8d21c17c9e72fb6f61747099c0798d5e264496 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 581a4eb82b1534970060e3cbd79b9a96d351edf9
Author: Andy Wingo <address@hidden>
Date:   Thu Nov 7 23:03:45 2013 +0100

    frame-instruction-pointer is absolute; rewrite (system vm coverage)
    
    * libguile/frames.c (scm_frame_source): Instead of assuming that
      scm_frame_procedure is correct, use the IP to get the source.
      (scm_frame_instruction_pointer): Return an absolute value instead of
      assuming that slot 0 is correct.  (It isn't, when preparing for a tail
      call.)
    
    * libguile/programs.h:
    * libguile/programs.c (scm_find_source_for_addr): New internal helper.
    
    * module/system/repl/debug.scm (print-registers): Readably print
      absolute instruction pointers.
    
    * module/system/vm/coverage.scm: Complete rewrite to use absolute IP's.
      We can't assume that frame-procedure is cheap if it is correct, or
      correct if it is cheap.  Anyway using the address is better anyway.
      (coverage-data->lcov): Disable per-function info temporarily.
      (loaded-modules, module-procedures, closest-source-line)
      (closed-over-procedures): Remove these.  Instead of going from
      procedures to source info, now we go from ELF image to source info.
    
    * module/system/vm/debug.scm (debug-context-length): New interface.
    
    * module/system/vm/program.scm (source-for-addr): New internal helper.

commit 72b82b0f210ef47798133dabf2a81eef3e036ba6
Author: Andy Wingo <address@hidden>
Date:   Thu Nov 7 18:11:00 2013 +0100

    scm_from_uintptr_t / scm_from_ptrdiff_t usage
    
    * libguile/frames.c:
    * libguile/programs.c: Use scm_from_ptrdiff_t and scm_from_uintptr_t
      where appropriate.

commit e15aa022847507c3eeb84c180d20a4209ece1cb6
Author: Andy Wingo <address@hidden>
Date:   Thu Nov 7 18:00:40 2013 +0100

    Program sources are always pre-retire now
    
    * module/system/repl/debug.scm (<debug>): Remove for-trap?.  Backtraces
      with RTL will always happen pre-retire on the top frame, source info
      is pre-retire, and continuations will always have a source-marked
      receive or receive-values or whatever with the right source marking,
      so we can remove this complication.
      (print-frame): Use frame-source.
      (print-frames): Remove for-trap? kw.
    
    * module/system/repl/command.scm (define-stack-command, backtrace)
      (up, down, frame): Remove for-trap? introduced local, and its uses.
      (repl-pop-continuation-resumer): Adapt to make-debug change.
    
    * module/system/repl/error-handling.scm (call-with-error-handling):
      Adapt to make-debug change.
    
    * module/system/vm/frame.scm (frame-next-source): Remove.  RTL sources
      are pre-retire.
    
    * module/system/vm/trap-state.scm (add-ephemeral-stepping-trap!): Adapt
      to use frame-source.  Still some work to do here.

commit 0128bb9c38b28e74675e72539a162b5cf9848845
Author: Andy Wingo <address@hidden>
Date:   Thu Nov 7 17:53:04 2013 +0100

    add fold-all-debug-contexts, fold-source-locations
    
    * module/system/vm/objcode.scm:
    * libguile/objcodes.c (scm_all_mapped_elf_images): New proc.
    
    * module/system/vm/debug.scm (fold-all-debug-contexts):
      (fold-source-locations): New public interfaces.

-----------------------------------------------------------------------

Summary of changes:
 libguile/frames.c                     |   47 +----
 libguile/objcodes.c                   |   23 ++
 libguile/programs.c                   |   19 ++-
 libguile/programs.h                   |    2 +
 module/system/repl/command.scm        |   26 +--
 module/system/repl/debug.scm          |   24 ++-
 module/system/repl/error-handling.scm |    6 +-
 module/system/vm/coverage.scm         |  362 +++++++++++++++------------------
 module/system/vm/debug.scm            |   51 +++++-
 module/system/vm/frame.scm            |   11 +-
 module/system/vm/objcode.scm          |    2 +-
 module/system/vm/program.scm          |    9 +
 module/system/vm/trap-state.scm       |    6 +-
 13 files changed, 308 insertions(+), 280 deletions(-)

diff --git a/libguile/frames.c b/libguile/frames.c
index b2973bf..d32f837 100644
--- a/libguile/frames.c
+++ b/libguile/frames.c
@@ -104,18 +104,9 @@ SCM_DEFINE (scm_frame_source, "frame-source", 1, 0, 0,
            "")
 #define FUNC_NAME s_scm_frame_source
 {
-  SCM proc;
-
   SCM_VALIDATE_VM_FRAME (1, frame);
 
-  proc = scm_frame_procedure (frame);
-
-  if (SCM_PROGRAM_P (proc) || SCM_RTL_PROGRAM_P (proc))
-    return scm_program_source (scm_frame_procedure (frame),
-                               scm_frame_instruction_pointer (frame),
-                               SCM_UNDEFINED);
-
-  return SCM_BOOL_F;
+  return scm_find_source_for_addr (scm_frame_instruction_pointer (frame));
 }
 #undef FUNC_NAME
 
@@ -142,7 +133,7 @@ SCM_DEFINE (scm_frame_num_locals, "frame-num-locals", 1, 0, 
0,
     /* The frame size of an RTL program is fixed, except in the case of
        passing a wrong number of arguments to the program.  So we do
        need to use an SP for determining the number of locals.  */
-    return scm_from_uint32 (sp + 1 - p);
+    return scm_from_ptrdiff_t (sp + 1 - p);
 
   sp = SCM_VM_FRAME_SP (frame);
   p = SCM_FRAME_STACK_ADDRESS (SCM_VM_FRAME_FP (frame));
@@ -234,7 +225,7 @@ SCM_DEFINE (scm_frame_address, "frame-address", 1, 0, 0,
 #define FUNC_NAME s_scm_frame_address
 {
   SCM_VALIDATE_VM_FRAME (1, frame);
-  return scm_from_unsigned_integer ((scm_t_bits) SCM_VM_FRAME_FP (frame));
+  return scm_from_uintptr_t ((scm_t_uintptr) SCM_VM_FRAME_FP (frame));
 }
 #undef FUNC_NAME
 
@@ -245,7 +236,7 @@ SCM_DEFINE (scm_frame_stack_pointer, "frame-stack-pointer", 
1, 0, 0,
 {
   SCM_VALIDATE_VM_FRAME (1, frame);
 
-  return scm_from_unsigned_integer ((scm_t_bits) SCM_VM_FRAME_SP (frame));
+  return scm_from_uintptr_t ((scm_t_uintptr) SCM_VM_FRAME_SP (frame));
 }
 #undef FUNC_NAME
 
@@ -254,22 +245,9 @@ SCM_DEFINE (scm_frame_instruction_pointer, 
"frame-instruction-pointer", 1, 0, 0,
            "")
 #define FUNC_NAME s_scm_frame_instruction_pointer
 {
-  SCM program;
-  const struct scm_objcode *c_objcode;
-
   SCM_VALIDATE_VM_FRAME (1, frame);
-  program = scm_frame_procedure (frame);
-
-  if (SCM_RTL_PROGRAM_P (program))
-    return scm_from_ptrdiff_t (SCM_VM_FRAME_IP (frame) -
-                               (scm_t_uint8 *) SCM_RTL_PROGRAM_CODE (program));
-
-  if (!SCM_PROGRAM_P (program))
-    return SCM_INUM0;
 
-  c_objcode = SCM_PROGRAM_DATA (program);
-  return scm_from_unsigned_integer ((SCM_VM_FRAME_IP (frame)
-                                     - SCM_C_OBJCODE_BASE (c_objcode)));
+  return scm_from_uintptr_t ((scm_t_uintptr) SCM_VM_FRAME_IP (frame));
 }
 #undef FUNC_NAME
 
@@ -279,9 +257,8 @@ SCM_DEFINE (scm_frame_return_address, 
"frame-return-address", 1, 0, 0,
 #define FUNC_NAME s_scm_frame_return_address
 {
   SCM_VALIDATE_VM_FRAME (1, frame);
-  return scm_from_unsigned_integer ((scm_t_bits)
-                                    (SCM_FRAME_RETURN_ADDRESS
-                                     (SCM_VM_FRAME_FP (frame))));
+  return scm_from_uintptr_t ((scm_t_uintptr) (SCM_FRAME_RETURN_ADDRESS
+                                              (SCM_VM_FRAME_FP (frame))));
 }
 #undef FUNC_NAME
 
@@ -291,9 +268,9 @@ SCM_DEFINE (scm_frame_mv_return_address, 
"frame-mv-return-address", 1, 0, 0,
 #define FUNC_NAME s_scm_frame_mv_return_address
 {
   SCM_VALIDATE_VM_FRAME (1, frame);
-  return scm_from_unsigned_integer ((scm_t_bits)
-                                    (SCM_FRAME_MV_RETURN_ADDRESS
-                                     (SCM_VM_FRAME_FP (frame))));
+  return scm_from_uintptr_t ((scm_t_uintptr)
+                             (SCM_FRAME_MV_RETURN_ADDRESS
+                              (SCM_VM_FRAME_FP (frame))));
 }
 #undef FUNC_NAME
 
@@ -304,8 +281,8 @@ SCM_DEFINE (scm_frame_dynamic_link, "frame-dynamic-link", 
1, 0, 0,
 {
   SCM_VALIDATE_VM_FRAME (1, frame);
   /* fixme: munge fp if holder is a continuation */
-  return scm_from_ulong
-    ((unsigned long)
+  return scm_from_uintptr_t
+    ((scm_t_uintptr)
      RELOC (frame,
             SCM_FRAME_DYNAMIC_LINK (SCM_VM_FRAME_FP (frame))));
 }
diff --git a/libguile/objcodes.c b/libguile/objcodes.c
index 734bdde..fa4e28b 100644
--- a/libguile/objcodes.c
+++ b/libguile/objcodes.c
@@ -741,6 +741,27 @@ scm_find_mapped_elf_image (SCM ip)
   return result;
 }
 
+static SCM
+scm_all_mapped_elf_images (void)
+{
+  SCM result = SCM_EOL;
+
+  scm_i_pthread_mutex_lock (&scm_i_misc_mutex);
+  {
+    size_t n;
+    for (n = 0; n < mapped_elf_images_count; n++)
+      {
+        signed char *data = (signed char *) mapped_elf_images[n].start;
+        size_t len = mapped_elf_images[n].end - mapped_elf_images[n].start;
+        result = scm_cons (scm_c_take_gc_bytevector (data, len, SCM_BOOL_F),
+                           result);
+      }
+  }
+  scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
+
+  return result;
+}
+
 
 /*
  * Scheme interface
@@ -881,6 +902,8 @@ scm_init_objcodes (void)
 
   scm_c_define_gsubr ("find-mapped-elf-image", 1, 0, 0,
                       (scm_t_subr) scm_find_mapped_elf_image);
+  scm_c_define_gsubr ("all-mapped-elf-images", 0, 0, 0,
+                      (scm_t_subr) scm_all_mapped_elf_images);
 
   scm_c_define ("word-size", scm_from_size_t (sizeof(SCM)));
   scm_c_define ("byte-order", scm_from_uint16 (SCM_BYTE_ORDER));
diff --git a/libguile/programs.c b/libguile/programs.c
index 5452112..3e228f7 100644
--- a/libguile/programs.c
+++ b/libguile/programs.c
@@ -106,8 +106,7 @@ SCM_DEFINE (scm_rtl_program_code, "rtl-program-code", 1, 0, 
0,
 {
   SCM_VALIDATE_RTL_PROGRAM (1, program);
 
-  /* FIXME: we need scm_from_uintptr ().  */
-  return scm_from_size_t ((size_t) SCM_RTL_PROGRAM_CODE (program));
+  return scm_from_uintptr_t ((scm_t_uintptr) SCM_RTL_PROGRAM_CODE (program));
 }
 #undef FUNC_NAME
 
@@ -400,6 +399,22 @@ scm_i_program_properties (SCM program)
 #undef FUNC_NAME
 
 SCM
+scm_find_source_for_addr (SCM ip)
+{
+  static SCM source_for_addr = SCM_BOOL_F;
+
+  if (scm_is_false (source_for_addr)) {
+    if (!scm_module_system_booted_p)
+      return SCM_BOOL_F;
+
+    source_for_addr =
+      scm_c_private_variable ("system vm program", "source-for-addr");
+  }
+
+  return scm_call_1 (scm_variable_ref (source_for_addr), ip);
+}
+
+SCM
 scm_program_source (SCM program, SCM ip, SCM sources)
 {
   static SCM program_source = SCM_BOOL_F;
diff --git a/libguile/programs.h b/libguile/programs.h
index f2518ca..0d33957 100644
--- a/libguile/programs.h
+++ b/libguile/programs.h
@@ -51,6 +51,8 @@ SCM_INTERNAL SCM scm_i_rtl_program_name (SCM program);
 SCM_INTERNAL SCM scm_i_rtl_program_documentation (SCM program);
 SCM_INTERNAL SCM scm_i_rtl_program_properties (SCM program);
 
+SCM_INTERNAL SCM scm_find_source_for_addr (SCM ip);
+
 /*
  * Programs
  */
diff --git a/module/system/repl/command.scm b/module/system/repl/command.scm
index ca080d2..1e6aaff 100644
--- a/module/system/repl/command.scm
+++ b/module/system/repl/command.scm
@@ -569,8 +569,6 @@ Trace execution."
                        (identifier-syntax (debug-frames debug)))
                       (#,(datum->syntax #'repl 'message)
                        (identifier-syntax (debug-error-message debug)))
-                      (#,(datum->syntax #'repl 'for-trap?)
-                       (identifier-syntax (debug-for-trap? debug)))
                       (#,(datum->syntax #'repl 'index)
                        (identifier-syntax
                         (id (debug-index debug))
@@ -592,8 +590,7 @@ If COUNT is negative, the last COUNT frames will be shown."
   (print-frames frames
                 #:count count
                 #:width width
-                #:full? full?
-                #:for-trap? for-trap?))
+                #:full? full?))
 
 (define-stack-command (up repl #:optional (count 1))
   "up [COUNT]
@@ -610,12 +607,10 @@ An argument says how many frames up to go."
       (format #t "Already at outermost frame.\n"))
      (else
       (set! index (1- (vector-length frames)))
-      (print-frame cur #:index index
-                   #:next-source? (and (zero? index) for-trap?)))))
+      (print-frame cur #:index index))))
    (else
     (set! index (+ count index))
-    (print-frame cur #:index index
-                 #:next-source? (and (zero? index) for-trap?)))))
+    (print-frame cur #:index index))))
 
 (define-stack-command (down repl #:optional (count 1))
   "down [COUNT]
@@ -632,11 +627,10 @@ An argument says how many frames down to go."
       (format #t "Already at innermost frame.\n"))
      (else
       (set! index 0)
-      (print-frame cur #:index index #:next-source? for-trap?))))
+      (print-frame cur #:index index))))
    (else
     (set! index (- index count))
-    (print-frame cur #:index index
-                 #:next-source? (and (zero? index) for-trap?)))))
+    (print-frame cur #:index index))))
 
 (define-stack-command (frame repl #:optional idx)
   "frame [IDX]
@@ -651,12 +645,10 @@ With an argument, select a frame by index, then show it."
       (format #t "Invalid argument to `frame': expected a non-negative integer 
for IDX.~%"))
      ((< idx (vector-length frames))
       (set! index idx)
-      (print-frame cur #:index index
-                   #:next-source? (and (zero? index) for-trap?)))
+      (print-frame cur #:index index))
      (else
       (format #t "No such frame.~%"))))
-   (else (print-frame cur #:index index
-                      #:next-source? (and (zero? index) for-trap?)))))
+   (else (print-frame cur #:index index))))
 
 (define-stack-command (procedure repl)
   "procedure
@@ -722,7 +714,7 @@ Note that the given source location must be inside a 
procedure."
                (format #t "Return values:~%")
                (for-each (lambda (x) (repl-print repl x)) values)))
          ((module-ref (resolve-interface '(system repl repl)) 'start-repl)
-          #:debug (make-debug stack 0 msg #t))))))
+          #:debug (make-debug stack 0 msg))))))
 
 (define-stack-command (finish repl)
   "finish
@@ -746,7 +738,7 @@ Resume execution, breaking when the current frame finishes."
                        (k (frame->stack-vector frame)))))))
        (format #t "~a~%" msg)
        ((module-ref (resolve-interface '(system repl repl)) 'start-repl)
-        #:debug (make-debug stack 0 msg #t)))))
+        #:debug (make-debug stack 0 msg)))))
 
 (define-stack-command (step repl)
   "step
diff --git a/module/system/repl/debug.scm b/module/system/repl/debug.scm
index cf40806..251cd89 100644
--- a/module/system/repl/debug.scm
+++ b/module/system/repl/debug.scm
@@ -1,6 +1,6 @@
 ;;; Guile VM debugging facilities
 
-;;; Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
+;;; Copyright (C) 2001, 2009, 2010, 2011, 2013 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
@@ -31,7 +31,7 @@
   #:use-module (system vm program)
   #:export (<debug>
             make-debug debug?
-            debug-frames debug-index debug-error-message debug-for-trap?
+            debug-frames debug-index debug-error-message
             terminal-width
             print-registers print-locals print-frame print-frames frame->module
             stack->vector narrow-stack->vector
@@ -55,7 +55,7 @@
 ;;; accessors, and provides some helper functions.
 ;;;
 
-(define-record <debug> frames index error-message for-trap?)
+(define-record <debug> frames index error-message)
 
 
 
@@ -94,7 +94,12 @@
     (format port fmt val))
   
   (format port "~aRegisters:~%" per-line-prefix)
-  (print "ip = ~d\n" (frame-instruction-pointer frame))
+  (print "ip = #x~x" (frame-instruction-pointer frame))
+  (when (rtl-program? (frame-procedure frame))
+    (let ((code (rtl-program-code (frame-procedure frame))))
+      (format port " (address@hidden)" code
+              (- (frame-instruction-pointer frame) code))))
+  (newline port)
   (print "sp = #x~x\n" (frame-stack-pointer frame))
   (print "fp = #x~x\n" (frame-address frame)))
 
@@ -125,7 +130,7 @@
     (if source
         (or (source:file source) "current input")
         "unknown file"))
-  (let* ((source ((if next-source? frame-next-source frame-source) frame))
+  (let* ((source (frame-source frame))
          (file (source:pretty-file source))
          (line (and=> source source:line-for-user))
          (col (and=> source source:column)))
@@ -141,7 +146,7 @@
 (define* (print-frames frames
                        #:optional (port (current-output-port))
                        #:key (width (terminal-width)) (full? #f)
-                       (forward? #f) count for-trap?)
+                       (forward? #f) count)
   (let* ((len (vector-length frames))
          (lower-idx (if (or (not count) (positive? count))
                         0
@@ -155,12 +160,9 @@
       (if (<= lower-idx i upper-idx)
           (let* ((frame (vector-ref frames i)))
             (print-frame frame port #:index i #:width width #:full? full?
-                         #:last-source last-source
-                         #:next-source? (and (zero? i) for-trap?))
+                         #:last-source last-source)
             (lp (+ i inc)
-                (if (and (zero? i) for-trap?)
-                    (frame-next-source frame)
-                    (frame-source frame))))))))
+                (frame-source frame)))))))
 
 ;; Ideally here we would have something much more syntactic, in that a set! to 
a
 ;; local var that is not settable would raise an error, and export etc forms
diff --git a/module/system/repl/error-handling.scm 
b/module/system/repl/error-handling.scm
index 0e31eb9..d0d7967 100644
--- a/module/system/repl/error-handling.scm
+++ b/module/system/repl/error-handling.scm
@@ -1,6 +1,6 @@
 ;;; Error handling in the REPL
 
-;; Copyright (C) 2001, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+;; Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 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
@@ -72,7 +72,7 @@
              (error-msg (if trap-idx
                             (format #f "Trap ~d: ~a" trap-idx trap-name)
                             trap-name))
-             (debug (make-debug stack 0 error-msg #t)))
+             (debug (make-debug stack 0 error-msg)))
         (with-saved-ports
          (lambda ()
            (if trap-idx
@@ -138,7 +138,7 @@
                               ;; the start-stack thunk has its own frame too.
                               0 (and tag 1)))
                       (error-msg (error-string stack key args))
-                      (debug (make-debug stack 0 error-msg #f)))
+                      (debug (make-debug stack 0 error-msg)))
                  (with-saved-ports
                   (lambda ()
                     (format #t "~a~%" error-msg)
diff --git a/module/system/vm/coverage.scm b/module/system/vm/coverage.scm
index 1ca8fee..4c9644e 100644
--- a/module/system/vm/coverage.scm
+++ b/module/system/vm/coverage.scm
@@ -20,10 +20,14 @@
   #:use-module (system vm vm)
   #:use-module (system vm frame)
   #:use-module (system vm program)
+  #:use-module (system vm debug)
+  #:use-module (ice-9 format)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-9 gnu)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-26)
+  #:use-module (ice-9 match)
   #:export (with-code-coverage
             coverage-data?
             instrumented-source-files
@@ -46,54 +50,20 @@
 ;;; Gathering coverage data.
 ;;;
 
-(define (hashq-proc proc n)
-  ;; Return the hash of PROC's objcode.
-  (if (rtl-program? proc)
-      (hashq (rtl-program-code proc) n)
-      (hashq (program-objcode proc) n)))
-
-(define (assq-proc proc alist)
-  ;; Instead of really looking for PROC in ALIST, look for the objcode of PROC.
-  ;; IOW the alist is indexed by procedures, not objcodes, but those procedures
-  ;; are taken as an arbitrary representative of all the procedures (closures)
-  ;; sharing that objcode.  This can significantly reduce memory consumption.
-  (if (rtl-program? proc)
-      (let ((code (rtl-program-code proc)))
-        (find (lambda (pair)
-                (let ((proc (car pair)))
-                  (and (rtl-program? proc)
-                       (eqv? code (rtl-program-code proc)))))
-              alist))
-      (let ((code (program-objcode proc)))
-        (find (lambda (pair)
-                (let ((proc (car pair)))
-                  (and (program? proc)
-                       (eq? code (program-objcode proc)))))
-              alist))))
-
 (define (with-code-coverage vm thunk)
   "Run THUNK, a zero-argument procedure, using VM; instrument VM to collect 
code
 coverage data.  Return code coverage data and the values returned by THUNK."
 
-  (define procedure->ip-counts
-    ;; Mapping from procedures to hash tables; said hash tables map instruction
-    ;; pointers to the number of times they were executed.
-    (make-hash-table 500))
+  (define ip-counts
+    ;; A table mapping instruction pointers to the number of times they were
+    ;; executed.
+    (make-hash-table 5000))
 
   (define (collect! frame)
-    ;; Update PROCEDURE->IP-COUNTS with info from FRAME.
-    (let* ((proc       (frame-procedure frame))
-           (ip         (frame-instruction-pointer frame))
-           (proc-entry (hashx-create-handle! hashq-proc assq-proc
-                                             procedure->ip-counts proc #f)))
-      (let loop ()
-        (define ip-counts (cdr proc-entry))
-        (if ip-counts
-            (let ((ip-entry (hashv-create-handle! ip-counts ip 0)))
-              (set-cdr! ip-entry (+ (cdr ip-entry) 1)))
-            (begin
-              (set-cdr! proc-entry (make-hash-table))
-              (loop))))))
+    ;; Update IP-COUNTS with info from FRAME.
+    (let* ((ip (frame-instruction-pointer frame))
+           (ip-entry (hashv-create-handle! ip-counts ip 0)))
+      (set-cdr! ip-entry (+ (cdr ip-entry) 1))))
 
   ;; FIXME: It's unclear what the dynamic-wind is for, given that if the
   ;; VM is different from the current one, continuations will not be
@@ -111,7 +81,48 @@ coverage data.  Return code coverage data and the values 
returned by THUNK."
                             (set-vm-trace-level! vm level)
                             (remove-hook! hook collect!)))))
     (lambda args
-      (apply values (make-coverage-data procedure->ip-counts) args))))
+      (apply values (make-coverage-data ip-counts) args))))
+
+
+
+
+;;;
+;;; Source chunks.
+;;;
+
+(define-record-type <source-chunk>
+  (make-source-chunk base length sources)
+  source-chunk?
+  (base source-chunk-base)
+  (length source-chunk-length)
+  (sources source-chunk-sources))
+
+(set-record-type-printer!
+ <source-chunk>
+ (lambda (obj port)
+   (format port "<source-chunk #x~x-#x~x>"
+           (source-chunk-base obj)
+           (+ (source-chunk-base obj) (source-chunk-length obj)))))
+
+(define (compute-source-chunk ctx)
+  "Build a sorted vector of source information for a given debugging
+context (ELF image).  The return value is a @code{<source-chunk>}, which also
+records the address range to which the source information applies."
+  (make-source-chunk
+   (debug-context-base ctx)
+   (debug-context-length ctx)
+   ;; The source locations are sorted already, but collected in reverse order.
+   (list->vector (reverse! (fold-source-locations cons '() ctx)))))
+
+(define (all-source-information)
+  "Build and return a vector of source information corresponding to all
+loaded code.  The vector will be sorted by ascending address order."
+  (sort! (list->vector (fold-all-debug-contexts
+                        (lambda (ctx seed)
+                          (cons (compute-source-chunk ctx) seed))
+                        '()))
+         (lambda (x y)
+           (< (source-chunk-base x) (source-chunk-base y)))))
 
 
 ;;;
@@ -119,124 +130,137 @@ coverage data.  Return code coverage data and the 
values returned by THUNK."
 ;;;
 
 (define-record-type <coverage-data>
-  (%make-coverage-data procedure->ip-counts
-                       procedure->sources
+  (%make-coverage-data ip-counts
+                       sources
                        file->procedures
                        file->line-counts)
   coverage-data?
 
-  ;; Mapping from procedures to hash tables; said hash tables map instruction
-  ;; pointers to the number of times they were executed.
-  (procedure->ip-counts data-procedure->ip-counts)
+  ;; Mapping from instruction pointers to the number of times they were
+  ;; executed, as a sorted vector of IP-count pairs.
+  (ip-counts data-ip-counts)
 
-  ;; Mapping from procedures to the result of `program-sources'.
-  (procedure->sources   data-procedure->sources)
+  ;; Complete source census at the time the coverage analysis was run, as a
+  ;; sorted vector of <source-chunk> values.
+  (sources data-sources)
 
   ;; Mapping from source file names to lists of procedures defined in the file.
+  ;; FIXME.
   (file->procedures     data-file->procedures)
 
   ;; Mapping from file names to hash tables, which in turn map from line 
numbers
   ;; to execution counts.
   (file->line-counts    data-file->line-counts))
 
+(set-record-type-printer!
+ <coverage-data>
+ (lambda (obj port)
+   (format port "<coverage-data ~x>" (object-address obj))))
 
-(define (make-coverage-data procedure->ip-counts)
+(define (make-coverage-data ip-counts)
   ;; Return a `coverage-data' object based on the coverage data available in
-  ;; PROCEDURE->IP-COUNTS.  Precompute the other hash tables that make up
-  ;; `coverage-data' objects.
-  (let* ((procedure->sources (make-hash-table 500))
+  ;; IP-COUNTS.  Precompute the other hash tables that make up `coverage-data'
+  ;; objects.
+  (let* ((all-sources (all-source-information))
+         (all-counts (sort! (list->vector (hash-fold acons '() ip-counts))
+                            (lambda (x y)
+                              (< (car x) (car y)))))
          (file->procedures   (make-hash-table 100))
          (file->line-counts  (make-hash-table 100))
-         (data               (%make-coverage-data procedure->ip-counts
-                                                  procedure->sources
+         (data               (%make-coverage-data all-counts
+                                                  all-sources
                                                   file->procedures
                                                   file->line-counts)))
-    (define (increment-execution-count! file line count)
+
+    (define (observe-execution-count! file line count)
       ;; Make the execution count of FILE:LINE the maximum of its current value
       ;; and COUNT.  This is so that LINE's execution count is correct when
       ;; several instruction pointers map to LINE.
-      (let ((file-entry (hash-create-handle! file->line-counts file #f)))
-        (if (not (cdr file-entry))
-            (set-cdr! file-entry (make-hash-table 500)))
-        (let ((line-entry (hashv-create-handle! (cdr file-entry) line 0)))
-          (set-cdr! line-entry (max (cdr line-entry) count)))))
-
-    ;; Update execution counts for procs that were executed.
-    (hash-for-each (lambda (proc ip-counts)
-                     (let* ((sources (program-sources* data proc))
-                            (file    (and (pair? sources)
-                                          (source:file (car sources)))))
-                       (and file
-                            (begin
-                              ;; Add a zero count for all IPs in SOURCES and in
-                              ;; the sources of procedures closed over by PROC.
-                              (for-each
-                               (lambda (source)
-                                 (let ((file (source:file source))
-                                       (line (source:line source)))
-                                   (increment-execution-count! file line 0)))
-                               (append-map (cut program-sources* data <>)
-                                           (closed-over-procedures proc)))
-
-                              ;; Add the actual execution count collected.
-                              (hash-for-each
-                               (lambda (ip count)
-                                 (let ((line (closest-source-line sources ip)))
-                                   (increment-execution-count! file line 
count)))
-                               ip-counts)))))
-                   procedure->ip-counts)
-
-    ;; Set the execution count to zero for procedures loaded and not executed.
-    ;; FIXME: Traversing thousands of procedures here is inefficient.
-    (for-each (lambda (proc)
-                (and (not (hashq-ref procedure->sources proc))
-                     (for-each (lambda (proc)
-                                 (let* ((sources (program-sources* data proc))
-                                        (file    (and (pair? sources)
-                                                      (source:file (car 
sources)))))
-                                   (and file
-                                        (for-each
-                                         (lambda (ip)
-                                           (let ((line (closest-source-line 
sources ip)))
-                                             (increment-execution-count! file 
line 0)))
-                                         (map source:addr sources)))))
-                               (closed-over-procedures proc))))
-              (append-map module-procedures (loaded-modules)))
+      (when file
+        (let ((file-entry (hash-create-handle! file->line-counts file #f)))
+          (if (not (cdr file-entry))
+              (set-cdr! file-entry (make-hash-table 500)))
+          (let ((line-entry (hashv-create-handle! (cdr file-entry) line 0)))
+            (set-cdr! line-entry (max (cdr line-entry) count))))))
+
+    ;; First, visit every known source location and mark it as instrumented but
+    ;; unvisited.
+    ;;
+    ;; FIXME: This is not always necessary.  It's important to have the ability
+    ;; to know when a source location is not reached, but sometimes all we need
+    ;; to know is that a particular site *was* reached.  In that case we
+    ;; wouldn't need to load up all the DWARF sections.  As it is, though, we
+    ;; use the complete source census as part of the later phase.
+    (let visit-chunk ((chunk-idx 0))
+      (when (< chunk-idx (vector-length all-sources))
+        (match (vector-ref all-sources chunk-idx)
+          (($ <source-chunk> base chunk-length chunk-sources)
+           (let visit-source ((source-idx 0))
+             (when (< source-idx (vector-length chunk-sources))
+               (let ((s (vector-ref chunk-sources source-idx)))
+                 (observe-execution-count! (source-file s) (source-line s) 0)
+                 (visit-source (1+ source-idx)))))))
+        (visit-chunk (1+ chunk-idx))))
+
+    ;; Then, visit the measured execution counts, walking the complete source
+    ;; census at the same time.  This allows us to map observed addresses to
+    ;; source locations.  Record observed execution counts.
+    (let visit-chunk ((chunk-idx 0) (count-idx 0))
+      (when (< chunk-idx (vector-length all-sources))
+        (match (vector-ref all-sources chunk-idx)
+          (($ <source-chunk> base chunk-length chunk-sources)
+           (let visit-count ((count-idx count-idx) (source-idx 0) (source #f))
+             (when (< count-idx (vector-length all-counts))
+               (match (vector-ref all-counts count-idx)
+                 ((ip . count)
+                  (cond
+                   ((< ip base)
+                    ;; Address before chunk base; no corresponding source.
+                    (visit-count (1+ count-idx) source-idx source))
+                   ((< ip (+ base chunk-length))
+                    ;; Address in chunk; count it.
+                    (let visit-source ((source-idx source-idx) (source source))
+                      (define (finish)
+                        (when source
+                          (observe-execution-count! (source-file source)
+                                                    (source-line source)
+                                                    count))
+                        (visit-count (1+ count-idx) source-idx source))
+                      (cond
+                       ((< source-idx (vector-length chunk-sources))
+                        (let ((source* (vector-ref chunk-sources source-idx)))
+                          (if (<= (source-pre-pc source*) ip)
+                              (visit-source (1+ source-idx) source*)
+                              (finish))))
+                       (else
+                        (finish)))))
+                   (else
+                    ;; Address past chunk; fetch the next chunk.
+                    (visit-chunk (1+ chunk-idx) count-idx)))))))))))
 
     data))
 
 (define (procedure-execution-count data proc)
-  "Return the number of times PROC's code was executed, according to DATA, or 
#f
-if PROC was not executed.  When PROC is a closure, the number of times its code
-was executed is returned, not the number of times this code associated with 
this
-particular closure was executed."
-  (let ((sources (program-sources* data proc)))
-    (and (pair? sources)
-         (and=> (hashx-ref hashq-proc assq-proc
-                           (data-procedure->ip-counts data) proc)
-                (lambda (ip-counts)
-                  ;; FIXME: broken with lambda*
-                  (let ((entry-ip (source:addr (car sources))))
-                    (hashv-ref ip-counts entry-ip 0)))))))
-
-(define (program-sources* data proc)
-  ;; A memoizing version of `program-sources'.
-  (or (hashq-ref (data-procedure->sources data) proc)
-      (and (or (program? proc) (rtl-program? proc))
-           (let ((sources (program-sources proc))
-                 (p->s    (data-procedure->sources data))
-                 (f->p    (data-file->procedures data)))
-             (if (pair? sources)
-                 (let* ((file  (source:file (car sources)))
-                        (entry (hash-create-handle! f->p file '())))
-                   (hashq-set! p->s proc sources)
-                   (set-cdr! entry (cons proc (cdr entry)))
-                   sources)
-                 sources)))))
-
-(define (file-procedures data file)
-  ;; Return the list of globally bound procedures defined in FILE.
-  (hash-ref (data-file->procedures data) file '()))
+  "Return the number of times PROC's code was executed, according to DATA.  
When
+PROC is a closure, the number of times its code was executed is returned, not
+the number of times this code associated with this particular closure was
+executed."
+  (define (binary-search v key val)
+    (let lp ((start 0) (end (vector-length v)))
+      (and (not (eqv? start end))
+           (let* ((idx (floor/ (+ start end) 2))
+                  (elt (vector-ref v idx))
+                  (val* (key elt)))
+             (cond
+              ((< val val*)
+               (lp start idx))
+              ((< val* val)
+               (lp (1+ idx) end))
+              (else elt))))))
+  (and (rtl-program? proc)
+       (match (binary-search (data-ip-counts data) car (rtl-program-code proc))
+         (#f 0)
+         ((ip . code) code))))
 
 (define (instrumented/executed-lines data file)
   "Return the number of instrumented and the number of executed source lines in
@@ -273,66 +297,6 @@ was loaded at the time DATA was collected."
 
 
 ;;;
-;;; Helpers.
-;;;
-
-(define (loaded-modules)
-  ;; Return the list of all the modules currently loaded.
-  (define seen (make-hash-table))
-
-  (let loop ((modules (module-submodules (resolve-module '() #f)))
-             (result  '()))
-    (hash-fold (lambda (name module result)
-                 (if (hashq-ref seen module)
-                     result
-                     (begin
-                       (hashq-set! seen module #t)
-                       (loop (module-submodules module)
-                             (cons module result)))))
-               result
-               modules)))
-
-(define (module-procedures module)
-  ;; Return the list of procedures bound globally in MODULE.
-  (hash-fold (lambda (binding var result)
-               (if (variable-bound? var)
-                   (let ((value (variable-ref var)))
-                     (if (procedure? value)
-                         (cons value result)
-                         result))
-                   result))
-             '()
-             (module-obarray module)))
-
-(define (closest-source-line sources ip)
-  ;; Given SOURCES, as returned by `program-sources' for a given procedure,
-  ;; return the source line of code that is the closest to IP.  This is similar
-  ;; to what `program-source' does.
-  (let loop ((sources sources)
-             (line    (and (pair? sources) (source:line (car sources)))))
-    (if (null? sources)
-        line
-        (let ((source (car sources)))
-          (if (> (source:addr source) ip)
-              line
-              (loop (cdr sources) (source:line source)))))))
-
-(define (closed-over-procedures proc)
-  ;; Return the list of procedures PROC closes over, PROC included.
-  (let loop ((proc   proc)
-             (result '()))
-    (if (and (or (program? proc) (rtl-program? proc)) (not (memq proc result)))
-        (fold loop (cons proc result)
-              ;; FIXME: Include statically nested procedures for RTL
-              ;; programs.
-              (append (if (program? proc)
-                          (vector->list (or (program-objects proc) #()))
-                          '())
-                      (program-free-variables proc)))
-        result)))
-
-
-;;;
 ;;; LCOV output.
 ;;;
 
@@ -342,6 +306,10 @@ was loaded at the time DATA was collected."
 The report will include all the modules loaded at the time coverage data was
 gathered, even if their code was not executed."
 
+  ;; FIXME: Re-enable this code, but using for-each-elf-symbol on each source
+  ;; chunk.  Use that to build a map of file -> proc-addr + line + name.  Then
+  ;; use something like procedure-execution-count to get the execution count.
+  #;
   (define (dump-function proc)
     ;; Dump source location and basic coverage data for PROC.
     (and (or (program? proc) (rtl-program? proc))
@@ -358,11 +326,11 @@ gathered, even if their code was not executed."
   ;; Output per-file coverage data.
   (format port "TN:~%")
   (for-each (lambda (file)
-              (let ((procs (file-procedures data file))
-                    (path  (search-path %load-path file)))
+              (let ((path (search-path %load-path file)))
                 (if (string? path)
                     (begin
                       (format port "SF:~A~%" path)
+                      #;
                       (for-each dump-function procs)
                       (for-each (lambda (line+count)
                                   (let ((line  (car line+count))
diff --git a/module/system/vm/debug.scm b/module/system/vm/debug.scm
index e5eb9be..a3aede7 100644
--- a/module/system/vm/debug.scm
+++ b/module/system/vm/debug.scm
@@ -31,9 +31,11 @@
   #:use-module (system foreign)
   #:use-module (rnrs bytevectors)
   #:use-module (ice-9 match)
+  #:use-module ((srfi srfi-1) #:select (fold))
   #:use-module (srfi srfi-9)
   #:export (debug-context-image
             debug-context-base
+            debug-context-length
             debug-context-text-base
 
             program-debug-info-name
@@ -55,6 +57,7 @@
             arity-is-case-lambda?
 
             debug-context-from-image
+            fold-all-debug-contexts
             for-each-elf-symbol
             find-debug-context
             find-program-debug-info
@@ -74,7 +77,8 @@
             source-line-for-user
             source-column
             find-source-for-addr
-            find-program-sources))
+            find-program-sources
+            fold-source-locations))
 
 ;;; A compiled procedure comes from a specific loaded ELF image.  A
 ;;; debug context identifies that image.
@@ -93,6 +97,11 @@
 @var{context}."
   (elf-bytes (debug-context-elf context)))
 
+(define (debug-context-length context)
+  "Return the size of the mapped ELF image corresponding to
address@hidden, in bytes."
+  (bytevector-length (debug-context-image context)))
+
 (define (for-each-elf-symbol context proc)
   "Call @var{proc} on each symbol in the symbol table of @var{context}."
   (let ((elf (debug-context-elf context)))
@@ -153,6 +162,15 @@ offset from the beginning of the ELF image in 32-bit 
units."
                          (error "ELF object has no text section")))))
     (make-debug-context elf base text-base)))
 
+(define (fold-all-debug-contexts proc seed)
+  "Fold @var{proc} over debug contexts corresponding to all images that
+are mapped at the time this procedure is called.  Any images mapped
+during the fold are omitted."
+  (fold (lambda (image seed)
+          (proc (debug-context-from-image image) seed))
+        seed
+        (all-mapped-elf-images)))
+
 (define (find-debug-context addr)
   "Find and return the debugging context corresponding to the ELF image
 containing the address @var{addr}.  @var{addr} is an integer.  If no ELF
@@ -543,3 +561,34 @@ section of the ELF image.  Returns an ELF symbol, or 
@code{#f}."
                        (reverse sources))))))
             (else '())))))
    (else '())))
+
+(define* (fold-source-locations proc seed context)
+  "Fold @var{proc} over all source locations in @var{context}.
address@hidden will be called with two arguments: the source object and the
+seed."
+  (cond
+   ((and context
+         (false-if-exception
+          (elf->dwarf-context (debug-context-elf context))))
+    =>
+    (lambda (dwarf-ctx)
+      (let ((base (debug-context-base context)))
+        (fold
+         (lambda (die seed)
+           (cond
+            ((die-line-prog die)
+             =>
+             (lambda (prog)
+               (let lp ((seed seed))
+                 (call-with-values
+                     (lambda () (line-prog-advance prog))
+                   (lambda (pc* file line col)
+                     (if pc*
+                         (lp
+                          (proc (make-source/dwarf (+ pc* base) file line col)
+                                seed))
+                         seed))))))
+            (else seed)))
+         seed
+         (read-die-roots dwarf-ctx)))))
+   (else seed)))
diff --git a/module/system/vm/frame.scm b/module/system/vm/frame.scm
index ea2faaf..8aba837 100644
--- a/module/system/vm/frame.scm
+++ b/module/system/vm/frame.scm
@@ -26,7 +26,7 @@
   #:export (frame-bindings
             frame-lookup-binding
             frame-binding-ref frame-binding-set!
-            frame-next-source frame-call-representation
+            frame-call-representation
             frame-environment
             frame-object-binding frame-object-name))
 
@@ -71,15 +71,6 @@
 ;;; Pretty printing
 ;;;
 
-(define (frame-next-source frame)
-  (let ((proc (frame-procedure frame)))
-    (if (or (program? proc) (rtl-program? proc))
-        (program-source proc
-                        (frame-instruction-pointer frame)
-                        (program-sources-pre-retire proc))
-        '())))
-
-
 ;; Basically there are two cases to deal with here:
 ;;
 ;;   1. We've already parsed the arguments, and bound them to local
diff --git a/module/system/vm/objcode.scm b/module/system/vm/objcode.scm
index e2a93d7..4a0e992 100644
--- a/module/system/vm/objcode.scm
+++ b/module/system/vm/objcode.scm
@@ -23,7 +23,7 @@
             bytecode->objcode objcode->bytecode
             load-thunk-from-file load-thunk-from-memory
             word-size byte-order
-            find-mapped-elf-image))
+            find-mapped-elf-image all-mapped-elf-images))
 
 (load-extension (string-append "libguile-" (effective-version))
                 "scm_init_objcodes")
diff --git a/module/system/vm/program.scm b/module/system/vm/program.scm
index 2c8cd75..ecac6a7 100644
--- a/module/system/vm/program.scm
+++ b/module/system/vm/program.scm
@@ -120,6 +120,15 @@
           ;; fixed length
           (instruction-length inst))))))
 
+(define (source-for-addr addr)
+  (and=> (find-source-for-addr addr)
+         (lambda (source)
+           ;; FIXME: absolute or relative address?
+           (cons* 0
+                  (source-file source)
+                  (source-line source)
+                  (source-column source)))))
+
 (define (program-sources proc)
   (cond
    ((rtl-program? proc)
diff --git a/module/system/vm/trap-state.scm b/module/system/vm/trap-state.scm
index 82d4e0e..e334c01 100644
--- a/module/system/vm/trap-state.scm
+++ b/module/system/vm/trap-state.scm
@@ -1,6 +1,6 @@
 ;;; trap-state.scm: a set of traps
 
-;; Copyright (C)  2010 Free Software Foundation, Inc.
+;; Copyright (C)  2010, 2013 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
@@ -275,13 +275,13 @@
             (and (<= (frame-address f) fp)
                  (predicate f))))))
   
-  (let* ((source (frame-next-source frame))
+  (let* ((source (frame-source frame))
          (idx (next-ephemeral-index! trap-state))
          (trap (trap-matching-instructions
                 (wrap-predicate-according-to-into
                  (if instruction?
                      (lambda (f) #t)
-                     (lambda (f) (not (equal? (frame-next-source f) source)))))
+                     (lambda (f) (not (equal? (frame-source f) source)))))
                 (ephemeral-handler-for-index trap-state idx handler))))
     (add-trap-wrapper!
      trap-state


hooks/post-receive
-- 
GNU Guile



reply via email to

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