~ubuntu-branches/ubuntu/trusty/librep/trusty

« back to all changes in this revision

Viewing changes to lisp/rep/vm/compiler/inline.jl

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2001-11-13 15:06:22 UTC
  • Revision ID: james.westby@ubuntu.com-20011113150622-vgmgmk6srj3kldr3
Tags: upstream-0.15.2
ImportĀ upstreamĀ versionĀ 0.15.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#| inline.jl -- function inlining
 
2
 
 
3
   $Id: inline.jl,v 1.22 2001/08/08 06:00:22 jsh Exp $
 
4
 
 
5
   Copyright (C) 2000 John Harper <john@dcs.warwick.ac.uk>
 
6
 
 
7
   This file is part of librep.
 
8
 
 
9
   librep is free software; you can redistribute it and/or modify it
 
10
   under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation; either version 2, or (at your option)
 
12
   any later version.
 
13
 
 
14
   librep is distributed in the hope that it will be useful, but
 
15
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with librep; see the file COPYING.  If not, write to
 
21
   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
22
|#
 
23
 
 
24
(declare (unsafe-for-call/cc))
 
25
 
 
26
(define-structure rep.vm.compiler.inline
 
27
 
 
28
    (export compile-lambda-inline
 
29
            compile-tail-call)
 
30
 
 
31
    (open rep
 
32
          rep.vm.compiler.utils
 
33
          rep.vm.compiler.basic
 
34
          rep.vm.compiler.modules
 
35
          rep.vm.compiler.lap
 
36
          rep.vm.compiler.bindings)
 
37
 
 
38
  (define inline-depth (make-fluid 0))          ;depth of lambda-inlining
 
39
  (defconst max-inline-depth 8)
 
40
 
 
41
  (defun push-inline-args (lambda-list args #!optional pushed-args-already tester)
 
42
    (let
 
43
        ((arg-count 0))
 
44
      (if (not pushed-args-already)
 
45
          ;; First of all, evaluate each argument onto the stack
 
46
          (while (consp args)
 
47
            (compile-form-1 (car args))
 
48
            (setq args (cdr args)
 
49
                  arg-count (1+ arg-count)))
 
50
        ;; Args already on stack
 
51
        (setq args nil
 
52
              arg-count pushed-args-already))
 
53
      ;; Now the interesting bit. The args are on the stack, in
 
54
      ;; reverse order. So now we have to scan the lambda-list to
 
55
      ;; see what they should be bound to.
 
56
      (let
 
57
          ((state 'required)
 
58
           (args-left arg-count)
 
59
           (bind-stack '()))
 
60
        (mapc tester (get-lambda-vars lambda-list))
 
61
        (while lambda-list
 
62
          (cond
 
63
           ((symbolp lambda-list)
 
64
            (setq bind-stack (cons (cons lambda-list args-left) bind-stack))
 
65
            (setq args-left 0))
 
66
           ((consp lambda-list)
 
67
            (case (car lambda-list)
 
68
              ((#!optional &optional) (setq state 'optional))
 
69
              ((#!rest &rest) (setq state 'rest))
 
70
              ;; XXX implement keyword params
 
71
              ((#!key) (compiler-error "can't inline `#!key' parameters"))
 
72
              (t (case state
 
73
                   ((required)
 
74
                    (if (zerop args-left)
 
75
                        (compiler-error "required arg `%s' missing"
 
76
                                        (car lambda-list))
 
77
                      (setq bind-stack (cons (car lambda-list) bind-stack)
 
78
                            args-left (1- args-left))))
 
79
                   ((optional)
 
80
                    (if (zerop args-left)
 
81
                        (let ((def (cdar lambda-list)))
 
82
                          (if def
 
83
                              (compile-form-1 (car def))
 
84
                            (emit-insn '(push ())))
 
85
                          (increment-stack))
 
86
                      (setq args-left (1- args-left)))
 
87
                    (setq bind-stack (cons (or (caar lambda-list)
 
88
                                               (car lambda-list)) bind-stack)))
 
89
                   ((rest)
 
90
                    (setq bind-stack (cons (cons (car lambda-list) args-left)
 
91
                                           bind-stack)
 
92
                          args-left 0
 
93
                          state '*done*)))))))
 
94
          (setq lambda-list (cdr lambda-list)))
 
95
        (when (> args-left 0)
 
96
          (compiler-warning 'parameters
 
97
           "%d unused %s to lambda expression"
 
98
           args-left (if (= args-left 1) "parameter" "parameters")))
 
99
        (cons args-left bind-stack))))
 
100
 
 
101
  (defun pop-inline-args (bind-stack args-left setter)
 
102
    ;; Bind all variables
 
103
    (while bind-stack
 
104
      (if (consp (car bind-stack))
 
105
          (progn
 
106
            (compile-constant '())
 
107
            (unless (null (cdr (car bind-stack)))
 
108
              (do ((i 0 (1+ i)))
 
109
                  ((= i (cdr (car bind-stack))))
 
110
                (emit-insn '(cons))
 
111
                (decrement-stack)))
 
112
            (setter (car (car bind-stack))))
 
113
        (setter (car bind-stack)))
 
114
      (decrement-stack)
 
115
      (setq bind-stack (cdr bind-stack)))
 
116
    ;; Then pop any args that weren't used.
 
117
    (while (> args-left 0)
 
118
      (emit-insn '(pop))
 
119
      (decrement-stack)
 
120
      (setq args-left (1- args-left))))
 
121
 
 
122
  ;; This compiles an inline lambda, i.e. FUN is something like
 
123
  ;; (lambda (LAMBDA-LIST...) BODY...)
 
124
  ;; If PUSHED-ARGS-ALREADY is true it should be a count of the number
 
125
  ;; of arguments pushed onto the stack (in reverse order). In this case,
 
126
  ;; ARGS is ignored
 
127
  (defun compile-lambda-inline (fun args #!optional pushed-args-already
 
128
                                return-follows name)
 
129
    (setq fun (compiler-macroexpand fun))
 
130
    (when (>= (fluid-set inline-depth (1+ (fluid inline-depth)))
 
131
              max-inline-depth)
 
132
      (fluid-set inline-depth 0)
 
133
      (compiler-error "can't inline more than %d nested functions"
 
134
                      max-inline-depth))
 
135
    (let*
 
136
        ((lambda-list (nth 1 fun))
 
137
         (body (nthcdr 2 fun))
 
138
         (out (push-inline-args
 
139
               lambda-list args pushed-args-already test-variable-bind))
 
140
         (args-left (car out))
 
141
         (bind-stack (cdr out)))
 
142
 
 
143
      (call-with-frame
 
144
       (lambda ()
 
145
         ;; Set up the body for compiling, skip any interactive form or
 
146
         ;; doc string
 
147
         (while (and (consp body)
 
148
                     (or (stringp (car body))
 
149
                         (and (consp (car body))
 
150
                              (eq (car (car body)) 'interactive))))
 
151
           (setq body (cdr body)))
 
152
    
 
153
         ;; Now we have a list of things to bind to, in the same order
 
154
         ;; as the stack of evaluated arguments. The list has items
 
155
         ;; SYMBOL, (SYMBOL . ARGS-TO-BIND), or (SYMBOL . nil)
 
156
         (if bind-stack
 
157
             (progn
 
158
               (emit-insn '(init-bind))
 
159
               (increment-b-stack)
 
160
               (pop-inline-args bind-stack args-left (lambda (x)
 
161
                                                       (note-binding x)
 
162
                                                       (emit-binding x)))
 
163
               (call-with-lambda-record name lambda-list 0
 
164
                (lambda ()
 
165
                  (fix-label (lambda-label (current-lambda)))
 
166
                  (set-lambda-inlined (current-lambda) t)
 
167
                  (compile-body body return-follows)))
 
168
               (emit-insn '(unbind))
 
169
               (decrement-b-stack))
 
170
           ;; Nothing to bind to. Just pop the evaluated args and
 
171
           ;; evaluate the body
 
172
           (while (> args-left 0)
 
173
             (emit-insn '(pop))
 
174
             (decrement-stack)
 
175
             (setq args-left (1- args-left)))
 
176
           (call-with-lambda-record name lambda-list 0
 
177
            (lambda ()
 
178
              (fix-label (lambda-label (current-lambda)))
 
179
              (set-lambda-inlined (current-lambda) t)
 
180
              (compile-body body return-follows))))))
 
181
      (fluid-set inline-depth (1- (fluid inline-depth)))))
 
182
 
 
183
  (define (pop-between top bottom)
 
184
    (or (and (>= top bottom) (>= bottom 0))
 
185
        (break)
 
186
        (error "Invalid stack pointers: %d, %d" top bottom))
 
187
    (when (/= top bottom)
 
188
      (if (= bottom 0)
 
189
          (emit-insn '(pop-all))
 
190
        (do ((sp top (1- sp)))
 
191
            ((= sp bottom))
 
192
          (emit-insn '(pop))))))
 
193
 
 
194
  (define (unbind-between top bottom)
 
195
    (cond ((= bottom -1) (emit-insn '(unbindall-0)))
 
196
          ((= bottom 0)
 
197
           (unless (<= top bottom)
 
198
             (emit-insn '(unbindall))))
 
199
          (t (do ((bp top (1- bp)))
 
200
                 ((<= bp bottom))
 
201
               (emit-insn '(unbind))))))
 
202
 
 
203
  (defun compile-tail-call (lambda-record args)
 
204
    (let* ((out (push-inline-args (lambda-args lambda-record)
 
205
                                  args nil test-variable-ref))
 
206
           (args-left (car out))
 
207
           (bind-stack (cdr out)))
 
208
      (call-with-frame
 
209
       (lambda ()
 
210
         (if (catch 'foo
 
211
               (mapc (lambda (var)
 
212
                       (when (binding-enclosed-p var)
 
213
                         (throw 'foo t)))
 
214
                     (get-lambda-vars (lambda-args lambda-record)))
 
215
               nil)
 
216
             ;; some of the parameter bindings may have been captured,
 
217
             ;; so rebind all of them
 
218
             (progn
 
219
               (unbind-between (fluid current-b-stack)
 
220
                               ;; the 1- is so that the frame of
 
221
                               ;; the function itself is also removed
 
222
                               (1- (lambda-bp lambda-record)))
 
223
               (emit-insn '(init-bind))
 
224
               (pop-inline-args bind-stack args-left emit-binding))
 
225
           ;; none of the bindings are captured, so just modify them
 
226
           (pop-inline-args bind-stack args-left emit-varset)
 
227
           (unbind-between (fluid current-b-stack)
 
228
                           (lambda-bp lambda-record)))
 
229
         ;; force the stack pointer to what it should be
 
230
         (pop-between (fluid current-stack) (lambda-sp lambda-record))
 
231
         (emit-insn `(jmp ,(lambda-label lambda-record))))))))