source: branches/generic-class-file/abcl/src/org/armedbear/lisp/jvm-class-file.lisp @ 12776

Last change on this file since 12776 was 12776, checked in by ehuelsmann, 13 years ago

More pool functions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.8 KB
Line 
1;;; jvm-class-file.lisp
2;;;
3;;; Copyright (C) 2010 Erik Huelsmann
4;;; $Id: jvm-class-file.lisp 12776 2010-07-03 20:35:42Z ehuelsmann $
5;;;
6;;; This program is free software; you can redistribute it and/or
7;;; modify it under the terms of the GNU General Public License
8;;; as published by the Free Software Foundation; either version 2
9;;; of the License, or (at your option) any later version.
10;;;
11;;; This program is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19;;;
20;;; As a special exception, the copyright holders of this library give you
21;;; permission to link this library with independent modules to produce an
22;;; executable, regardless of the license terms of these independent
23;;; modules, and to copy and distribute the resulting executable under
24;;; terms of your choice, provided that you also meet, for each linked
25;;; independent module, the terms and conditions of the license of that
26;;; module.  An independent module is a module which is not derived from
27;;; or based on this library.  If you modify this library, you may extend
28;;; this exception to your version of the library, but you are not
29;;; obligated to do so.  If you do not wish to do so, delete this
30;;; exception statement from your version.
31
32(in-package "JVM")
33
34#|
35
36The general design of the class-file writer is to have generic
37- human readable - representations of the class being generated
38during the construction and manipulation phases.
39
40After completing the creation/manipulation of the class, all its
41components will be finalized. This process translates readable
42(e.g. string) representations to indices to be stored on disc.
43
44The only thing to be done after finalization is sending the
45output to a stream ("writing").
46
47
48Finalization happens highest-level first. As an example, take a
49method with exception handlers. The exception handlers are stored
50as attributes in the class file structure. They are children of the
51method's Code attribute. In this example, the body of the Code
52attribute (the higher level) gets finalized before the attributes.
53The reason to do so is that the exceptions need to refer to labels
54(offsets) in the Code segment.
55
56
57|#
58
59
60(defun map-primitive-type (type)
61  (case type
62    (:int        "I")
63    (:long       "J")
64    (:float      "F")
65    (:double     "D")
66    (:boolean    "Z")
67    (:char       "C")
68    (:byte       "B")
69    (:short      "S")
70    ((nil :void) "V")))
71
72
73#|
74
75The `class-name' facility helps to abstract from "this instruction takes
76a reference" and "this instruction takes a class name". We simply pass
77the class name around and the instructions themselves know which
78representation to use.
79
80|#
81
82(defstruct (class-name (:conc-name class-)
83                       (:constructor %make-class-name))
84  name-internal
85  ref
86  array-ref)
87
88(defun make-class-name (name)
89  (setf name (substitute #\/ #\. name))
90  (%make-class-name :name-internal name
91                    :ref (concatenate 'string "L" name ";")
92                    :array-ref (concatenate 'string "[L" name ";")))
93
94(defmacro define-class-name (symbol java-dotted-name &optional documentation)
95  `(defconstant ,symbol (make-class-name ,java-dotted-name)
96     ,documentation))
97
98(define-class-name +!java-object+ "java.lang.Object")
99(define-class-name +!java-string+ "java.lang.String")
100(define-class-name +!lisp-object+ "org.armedbear.lisp.LispObject")
101(define-class-name +!lisp-simple-string+ "org.armedbear.lisp.SimpleString")
102(define-class-name +!lisp+ "org.armedbear.lisp.Lisp")
103(define-class-name +!lisp-nil+ "org.armedbear.lisp.Nil")
104(define-class-name +!lisp-class+ "org.armedbear.lisp.LispClass")
105(define-class-name +!lisp-symbol+ "org.armedbear.lisp.Symbol")
106(define-class-name +!lisp-thread+ "org.armedbear.lisp.LispThread")
107(define-class-name +!lisp-closure-binding+ "org.armedbear.lisp.ClosureBinding")
108(define-class-name +!lisp-integer+ "org.armedbear.lisp.Integer")
109(define-class-name +!lisp-fixnum+ "org.armedbear.lisp.Fixnum")
110(define-class-name +!lisp-bignum+ "org.armedbear.lisp.Bignum")
111(define-class-name +!lisp-single-float+ "org.armedbear.lisp.SingleFloat")
112(define-class-name +!lisp-double-float+ "org.armedbear.lisp.DoubleFloat")
113(define-class-name +!lisp-cons+ "org.armedbear.lisp.Cons")
114(define-class-name +!lisp-load+ "org.armedbear.lisp.Load")
115(define-class-name +!lisp-character+ "org.armedbear.lisp.Character")
116(define-class-name +!lisp-simple-vector+ "org.armedbear.lisp.SimpleVector")
117(define-class-name +!lisp-abstract-string+ "org.armedbear.lisp.AbstractString")
118(define-class-name +!lisp-abstract-vector+ "org.armedbear.lisp.AbstractVector")
119(define-class-name +!lisp-abstract-bit-vector+
120    "org.armedbear.lisp.AbstractBitVector")
121(define-class-name +!lisp-environment+ "org.armedbear.lisp.Environment")
122(define-class-name +!lisp-special-binding+ "org.armedbear.lisp.SpecialBinding")
123(define-class-name +!lisp-special-binding-mark+
124    "org.armedbear.lisp.SpecialBindingMark")
125(define-class-name +!lisp-throw+ "org.armedbear.lisp.Throw")
126(define-class-name +!lisp-return+ "org.armedbear.lisp.Return")
127(define-class-name +!lisp-go+ "org.armedbear.lisp.Go")
128(define-class-name +!lisp-primitive+ "org.armedbear.lisp.Primitive")
129(define-class-name +!lisp-compiled-closure+
130    "org.armedbear.lisp.CompiledClosure")
131(define-class-name +!lisp-eql-hash-table+ "org.armedbear.lisp.EqlHashTable")
132(define-class-name +!lisp-package+ "org.armedbear.lisp.Package")
133(define-class-name +!lisp-readtable+ "org.armedbear.lisp.Readtable")
134(define-class-name +!lisp-stream+ "org.armedbear.lisp.Stream")
135(define-class-name +!lisp-closure+ "org.armedbear.lisp.Closure")
136(define-class-name +!lisp-closure-parameter+
137    "org.armedbear.lisp.Closure$Parameter")
138(define-class-name +!fasl-loader+ "org.armedbear.lisp.FaslClassLoader")
139
140#|
141
142Lisp-side descriptor representation:
143
144 - list: a list starting with a method return value, followed by
145     the argument types
146 - keyword: the primitive type associated with that keyword
147 - class-name structure instance: the class-ref value
148
149The latter two can be converted to a Java representation using
150the `internal-field-ref' function, the former is to be fed to
151`descriptor'.
152
153|#
154
155(defun internal-field-type (field-type)
156  (if (keywordp field-type)
157      (map-primitive-type field-type)
158      (class-name-internal field-type)))
159
160(defun internal-field-ref (field-type)
161  (if (keywordp field-type)
162      (map-primitive-type field-type)
163      (class-ref field-type)))
164
165(defun descriptor (return-type &rest argument-types)
166  (format nil "(~{~A~}~A)" (mapcar #'internal-field-ref argument-types)
167          (internal-field-type return-type)))
168
169
170(defstruct pool
171  ;; `count' contains a reference to the last-used slot (0 being empty)
172  ;; "A constant pool entry is considered valid if it has
173  ;; an index greater than 0 (zero) and less than pool-count"
174  (count 0)
175  entries-list
176  ;; the entries hash stores raw values, except in case of string and
177  ;; utf8, because both are string values
178  (entries (make-hash-table :test #'equal :size 2048 :rehash-size 2.0)))
179
180(defstruct constant
181  tag
182  index)
183
184(defparameter +constant-type-map+
185  '((:class          7 1)
186    (:field-ref      9 1)
187    (:method-ref    10 1)
188    ;; (:interface-method-ref 11)
189    (:string         8 1)
190    (:integer        3 1)
191    (:float          4 1)
192    (:long           5 2)
193    (:double         6 2)
194    (:name-and-type 12 1)
195    (:utf8           1 1)))
196
197(defstruct (constant-class (:constructor make-constant-class (index name-index))
198                           (:include constant
199                                     (tag 7)))
200  name-index)
201
202(defstruct (constant-member-ref (:include constant))
203  class
204  name/type)
205
206(defstruct (constant-string (:constructor
207                             make-constant-string (index value-index))
208                            (:include constant
209                                      (tag 8)))
210  value-index) ;;; #### is this the value or the value index???
211
212(defstruct (constant-float/int (:constructor
213                                %make-constant-float/int (tag index value))
214                               (:include constant))
215  value)
216
217(declaim (inline make-constant-float make-constant-int))
218(defun make-constant-float (index value)
219  (%make-constant-float/int 4 index value))
220
221(defun make-constant-int (index value)
222  (%make-constant-float/int 3 index value))
223
224(defstruct (constant-double/long (:constructor
225                                  %make-constant-double/long (tag index value))
226                                 (:include constant))
227  value)
228
229(declaim (inline make-constant-double make-constant-float))
230(defun make-constant-double (index value)
231  (%make-constant-double/long 6 index value))
232
233(defun make-constant-long (index value)
234  (%make-constant-double/long 5 index value))
235
236(defstruct (constant-name/type (:include constant
237                                         (tag 12)))
238  name-index
239  descriptor-index)
240
241(defstruct (constant-utf8 (:constructor make-constant-utf8 (index value))
242                          (:include constant
243                                    (tag 11)))
244  value)
245
246
247(defun pool-add-class (pool class)
248  ;; ### do we make class a string or class-name structure?
249  (let ((entry (gethash class (pool-entries pool))))
250    (unless entry
251      (setf entry
252            (make-constant-class (incf (pool-count pool))
253                                 (pool-add-utf8 pool
254                                                (class-name-internal class)))
255            (gethash class (pool-entries pool)) entry)
256      (push entry (pool-entries-list pool)))
257    (constant-index entry)))
258
259(defun pool-add-member-ref (pool class name type)
260  (let ((entry (gethash (acons name type class) (pool-entries pool))))
261    (unless entry
262      (setf entry (make-constant-member-ref (incf (pool-count pool))
263                                            (pool-add-class pool class)
264                                            (pool-add-name/type pool name type))
265            (gethash (acons name type class) (pool-entries pool)) entry)
266      (push entry (pool-entries-list pool)))
267    (constant-index entry)))
268
269(defun pool-add-string (pool string)
270  (let ((entry (gethash (cons 8 string) ;; 8 == string-tag
271                        (pool-entries pool))))
272    (unless entry
273      (setf entry (make-constant-string (incf (pool-count pool))
274                                        (pool-add-utf8 pool string))
275            (gethash (cons 8 string) (pool-entries pool)) entry)
276      (push entry (pool-entries-list pool)))
277    (constant-index entry)))
278
279(defun pool-add-int (pool int)
280  (let ((entry (gethash (cons 3 int) (pool-entries pool))))
281    (unless entry
282      (setf entry (make-constant-int (incf (pool-count pool)) int)
283            (gethash (cons 3 int) (pool-entries pool)) entry)
284      (push entry (pool-entries-list pool)))
285    (constant-index entry)))
286
287(defun pool-add-float (pool float)
288  (let ((entry (gethash (cons 4 float) (pool-entries pool))))
289    (unless entry
290      (setf entry (make-constant-float (incf (pool-count pool)) float)
291            (gethash (cons 4 float) (pool-entries pool)) entry)
292      (push entry (pool-entries-list pool)))
293    (constant-index entry)))
294
295(defun pool-add-long (pool long)
296  (let ((entry (gethash (cons 5 long) (pool-entries pool))))
297    (unless entry
298      (setf entry (make-constant-long (incf (pool-count pool)) long)
299            (gethash (cons 5 long) (pool-entries pool)) entry)
300      (push entry (pool-entries-list pool))
301      (incf (pool-count pool))) ;; double index increase; long takes 2 slots
302    (constant-index entry)))
303
304(defun pool-add-double (pool double)
305  (let ((entry (gethash (cons 6 double) (pool-entries pool))))
306    (unless entry
307      (setf entry (make-constant-double (incf (pool-count pool)) double)
308            (gethash (cons 6 double) (pool-entries pool)) entry)
309      (push entry (pool-entries-list pool))
310      (incf (pool-count pool))) ;; double index increase; 'double' takes 2 slots
311    (constant-index entry)))
312
313(defun pool-add-name/type (pool name type)
314  (let ((entry (gethash (cons name type) (pool-entries pool)))
315        (internal-type (if (listp type)
316                           (apply #'descriptor type)
317                           (internal-field-ref type))))
318    (unless entry
319      (setf entry (make-constant-name/type (incf (pool-count pool))
320                                           (pool-add-utf8 pool name)
321                                           (pool-add-utf8 pool internal-type))
322            (gethash (cons name type) (pool-entries pool)) entry)
323      (push entry (pool-entries-list pool)))
324    (constant-index entry)))
325
326(defun pool-add-utf8 (pool utf8-as-string)
327  (let ((entry (gethash (cons 11 utf8-as-string) ;; 11 == utf8
328                        (pool-entries pool))))
329    (unless entry
330      (setf entry (make-constant-utf8 (incf (pool-count pool)) utf8-as-string)
331            (gethash (cons 11 utf8-as-string) (pool-entries pool)) entry)
332      (push entry (pool-entries-list pool)))
333    (constant-index entry)))
334
335(defstruct (class-file (:constructor %make-class-file))
336  constants
337  access-flags
338  class
339  superclass
340  ;; interfaces
341  fields
342  methods
343  attributes
344  )
345
346(defun class-add-field (class field)
347  (push field (class-file-fields class)))
348
349(defun class-field (class name)
350  (find name (class-file-fields class)
351        :test #'string= :key #'field-name))
352
353(defun class-add-method (class method)
354  (push method (class-file-methods class)))
355
356(defun class-methods-by-name (class name)
357  (remove (map-method-name name) (class-file-methods class)
358          :test-not #'string= :key #'method-name))
359
360(defun class-method (class descriptor)
361  (find descriptor (class-file-methods class)
362        :test #'string= :key #'method-name))
363
364
365(defun finalize-class-file (class)
366
367  ;; constant pool contains constants finalized on addition;
368  ;; no need for additional finalization
369
370  (setf (class-file-access-flags class)
371        (map-flags (class-file-access-flags class)))
372  ;; (finalize-class-name )
373  ;;  (finalize-interfaces)
374  (dolist (field (class-file-fields class))
375    (finalize-field field class))
376  (dolist (method (class-file-methods class))
377    (finalize-method method class))
378  ;; top-level attributes (no parent attributes to refer to)
379  (finalize-attributes (class-file-attributes class) nil class)
380
381)
382
383(defun !write-class-file (class stream)
384  ;; all components need to finalize themselves:
385  ;;  the constant pool needs to be complete before we start
386  ;;  writing our output.
387
388  ;; header
389  (write-u4 #xCAFEBABE stream)
390  (write-u2 3 stream)
391  (write-u2 45 stream)
392
393   ;; constants pool
394  (write-constants (class-file-constants class) stream)
395  ;; flags
396  (write-u2  (class-file-access-flags class) stream)
397  ;; class name
398  (write-u2 (class-file-class class) stream)
399  ;; superclass
400  (write-u2 (class-file-superclass class) stream)
401
402  ;; interfaces
403  (write-u2 0 stream)
404
405  ;; fields
406  (write-u2 (length (class-file-fields class)) stream)
407  (dolist (field (class-file-fields class))
408    (!write-field field stream))
409
410  ;; methods
411  (write-u2 (length (class-file-methods class)) stream)
412  (dolist (method (class-file-methods class))
413    (!write-method method stream))
414
415  ;; attributes
416  (write-attributes (class-file-attributes class) stream))
417
418(defun write-constants (constants stream)
419  (write-u2 (pool-count constants) stream)
420  (dolist (entry (reverse (pool-entries-list constants)))
421    (let ((tag (constant-tag entry)))
422    (write-u1 tag stream)
423    (case tag
424      (1 ; UTF8
425       (write-utf8 (constant-utf8-value entry) stream))
426      ((3 4) ; int
427       (write-u4 (constant-float/int-value entry) stream))
428      ((5 6) ; long double
429       (write-u4 (second entry) stream)
430       (write-u4 (third entry) stream))
431      ((9 10 11 12) ; fieldref methodref InterfaceMethodref nameAndType
432       (write-u2 (second entry) stream)
433       (write-u2 (third entry) stream))
434      ((7 8) ; class string
435       (write-u2 (constant-class-name-index entry) stream))
436      (t
437       (error "write-constant-pool-entry unhandled tag ~D~%" tag))))))
438
439#|
440
441ABCL doesn't use interfaces, so don't implement it here at this time
442
443(defstruct interface)
444
445|#
446
447
448(defparameter +access-flags-map+
449  '((:public       #x0001)
450    (:private      #x0002)
451    (:protected    #x0004)
452    (:static       #x0008)
453    (:final        #x0010)
454    (:volatile     #x0040)
455    (:synchronized #x0020)
456    (:transient    #x0080)
457    (:native       #x0100)
458    (:abstract     #x0400)
459    (:strict       #x0800)))
460
461(defun map-flags (flags)
462  (reduce #'(lambda (x y)
463              (logior (or (when (member (car x) flags)
464                            (second x))
465                          0) y)
466              (logior (or )))
467          :initial-value 0))
468
469(defstruct (field (:constructor %make-field))
470  access-flags
471  name
472  descriptor
473  attributes
474  )
475
476(defun make-field (name type &key (flags '(:public)))
477  (%make-field :access-flags flags
478               :name name
479               :descriptor type))
480
481(defun add-field-attribute (field attribute)
482  (push attribute (field-attributes field)))
483
484
485(defun finalize-field (field class)
486  (let ((pool (class-file-constants class)))
487    (setf (field-access-flags field)
488          (map-flags (field-access-flags field))
489          (field-descriptor field)
490          (pool-add-utf8 pool (internal-field-type (field-descriptor field)))
491          (field-name field)
492          (pool-add-utf8 pool (field-name field))))
493  (finalize-attributes (field-attributes field) nil class))
494
495(defun !write-field (field stream)
496  (write-u2 (field-access-flags field) stream)
497  (write-u2 (field-name field) stream)
498  (write-u2 (field-descriptor field) stream)
499  (write-attributes (field-attributes field) stream))
500
501
502(defstruct (method (:constructor %!make-method))
503  access-flags
504  name
505  descriptor
506  attributes
507  arg-count ;; not in the class file,
508            ;; but required for setting up CODE attribute
509  )
510
511
512(defun map-method-name (name)
513  (cond
514    ((eq name :class-constructor)
515     "<clinit>")
516    ((eq name :constructor)
517     "<init>")
518    (t name)))
519
520(defun !make-method-descriptor (name return &rest args)
521  (apply #'concatenate (append (list 'string (map-method-name name) "(")
522                               (mapcar #'map-primitive-type args)
523                               (list ")" return))))
524
525(defun !make-method (name return args &key (flags '(:public)))
526  (setf name (map-method-name name))
527  (%make-method :descriptor (apply #'make-method-descriptor
528                                   name return args)
529                :access-flags flags
530                :name name
531                :arg-count (if (member :static flags)
532                               (length args)
533                               (1+ (length args))))) ;; implicit 'this'
534
535(defun method-add-attribute (method attribute)
536  (push attribute (method-attributes method)))
537
538(defun method-attribute (method name)
539  (find name (method-attributes method)
540        :test #'string= :key #'attribute-name))
541
542
543(defun finalize-method (method class)
544  (let ((pool (class-file-constants class)))
545    (setf (method-access-flags method)
546          (map-flags (method-access-flags method))
547          (method-descriptor method)
548          (pool-add-utf8 pool (apply #'descriptor (method-descriptor method)))
549          (method-name method)
550          (pool-add-utf8 pool (map-method-name (method-name method)))))
551  (finalize-attributes (method-attributes method) nil class))
552
553
554(defun !write-method (method stream)
555  (write-u2 (method-access-flags method) stream)
556  (write-u2 (method-name method) stream)
557  (write-u2 (method-descriptor method) stream)
558  (write-attributes (method-attributes method) stream))
559
560(defstruct attribute
561  name
562
563  ;; not in the class file:
564  finalizer  ;; function of 3 arguments: the attribute, parent and class-file
565  writer     ;; function of 2 arguments: the attribute and the output stream
566  )
567
568(defun finalize-attributes (attributes att class)
569  (dolist (attribute attributes)
570    ;; assure header: make sure 'name' is in the pool
571    (setf (attribute-name attribute)
572          (pool-add-string (class-file-constants class)
573                           (attribute-name attribute)))
574    ;; we're saving "root" attributes: attributes which have no parent
575    (funcall (attribute-finalizer attribute) attribute att class)))
576
577(defun write-attributes (attributes stream)
578  (write-u2 (length attributes) stream)
579  (dolist (attribute attributes)
580    (write-u2 (attribute-name attribute) stream)
581    ;; set up a bulk catcher for (UNSIGNED-BYTE 8)
582    ;; since we need to know the attribute length (excluding the header)
583    (let ((local-stream (sys::%make-byte-array-output-stream)))
584      (funcall (attribute-writer attribute) attribute local-stream)
585      (let ((array (sys::%get-output-stream-array local-stream)))
586        (write-u2 (length array) stream)
587        (write-sequence array stream)))))
588
589
590
591(defstruct (code-attribute (:conc-name code-)
592                           (:include attribute
593                                     (name "Code")
594                                     (finalizer #'!finalize-code)
595                                     (writer #'!write-code))
596                           (:constructor %make-code-attribute))
597  max-stack
598  max-locals
599  code
600  attributes
601  ;; labels contains offsets into the code array after it's finalized
602  (labels (make-hash-table :test #'eq))
603
604  ;; fields not in the class file start here
605  current-local ;; used for handling nested WITH-CODE-TO-METHOD blocks
606  )
607
608
609(defun code-label-offset (code label)
610  (gethash label (code-labels code)))
611
612(defun (setf code-label-offset) (offset code label)
613  (setf (gethash label (code-labels code)) offset))
614
615(defun !finalize-code (code class)
616  (let ((c (coerce (resolve-instructions (code-code code)) 'vector)))
617    (setf (code-max-stack code) (analyze-stack c)
618          (code-code code) (code-bytes c)))
619  (finalize-attributes (code-attributes code) code class))
620
621(defun !write-code (code stream)
622  (write-u2 (code-max-stack code) stream)
623  (write-u2 (code-max-locals code) stream)
624  (let ((code-array (code-code code)))
625    (write-u4 (length code-array) stream)
626    (dotimes (i (length code-array))
627      (write-u1 (svref code-array i) stream)))
628  (write-attributes (code-attributes code) stream))
629
630(defun make-code-attribute (method)
631  (%make-code-attribute :max-locals (method-arg-count method)))
632
633(defun code-add-attribute (code attribute)
634  (push attribute (code-attributes code)))
635
636(defun code-attribute (code name)
637  (find name (code-attributes code)
638        :test #'string= :key #'attribute-name))
639
640
641
642(defvar *current-code-attribute*)
643
644(defun save-code-specials (code)
645  (setf (code-code code) *code*
646        (code-max-locals code) *registers-allocated*
647        (code-exception-handlers code) *handlers*
648        (code-current-local code) *register*))
649
650(defun restore-code-specials (code)
651  (setf *code* (code-code code)
652        *registers-allocated* (code-max-locals code)
653        *register* (code-current-local code)))
654
655(defmacro with-code-to-method ((method &key safe-nesting) &body body)
656  (let ((m (gensym))
657        (c (gensym)))
658    `(progn
659       ,@(when safe-nesting
660           `((when *current-code-attribute*
661               (save-code-specials *current-code-attribute*))))
662       (let* ((,m ,method)
663              (,c (method-attribute ,m "Code"))
664              (*code* (code-code ,c))
665              (*registers-allocated* (code-max-locals ,c))
666              (*register* (code-current-local ,c))
667              (*current-code-attribute* ,c))
668         ,@body
669         (setf (code-code ,c) *code*
670               (code-exception-handlers ,c) *handlers*
671               (code-max-locals ,c) *registers-allocated*))
672       ,@(when safe-nesting
673           `((when *current-code-attribute*
674               (restore-code-specials *current-code-attribute*)))))))
675
676(defstruct (exceptions-attribute (:constructor make-exceptions)
677                                 (:conc-name exceptions-)
678                                 (:include attribute
679                                           (name "Exceptions")
680                                           (finalizer #'finalize-exceptions)
681                                           (writer #'write-exceptions)))
682  exceptions)
683
684(defun finalize-exceptions (exceptions code class)
685  (dolist (exception (exceptions-exceptions exceptions))
686    ;; no need to finalize `catch-type': it's already the index required
687    (setf (exception-start-pc exception)
688          (code-label-offset code (exception-start-pc exception))
689          (exception-end-pc exception)
690          (code-label-offset code (exception-end-pc exception))
691          (exception-handler-pc exception)
692          (code-label-offset code (exception-handler-pc exception))
693          (exception-catch-type exception)
694          (pool-add-string (class-file-constants class)
695                           (exception-catch-type exception))))
696  ;;(finalize-attributes (exceptions-attributes exception) exceptions class)
697  )
698
699
700(defun write-exceptions (exceptions stream)
701  ; number of entries
702  (write-u2 (length (exceptions-exceptions exceptions)) stream)
703  (dolist (exception (exceptions-exceptions exceptions))
704    (write-u2 (exception-start-pc exception) stream)
705    (write-u2 (exception-end-pc exception) stream)
706    (write-u2 (exception-handler-pc exception) stream)
707    (write-u2 (exception-catch-type exception) stream)))
708
709(defun code-add-exception (code start end handler type)
710  (when (null (code-attribute code "Exceptions"))
711    (code-add-attribute code (make-exceptions)))
712  (push (make-exception :start-pc start
713                        :end-pc end
714                        :handler-pc handler
715                        :catch-type type)
716        (exceptions-exceptions (code-attribute code "Exceptions"))))
717
718(defstruct exception
719  start-pc    ;; label target
720  end-pc      ;; label target
721  handler-pc  ;; label target
722  catch-type  ;; a string for a specific type, or NIL for all
723  )
724
725(defstruct (source-file-attribute (:conc-name source-)
726                                  (:include attribute
727                                            (name "SourceFile")))
728  filename)
729
730(defstruct (line-numbers-attribute (:include attribute
731                                             (name "LineNumberTable")))
732  line-numbers)
733
734(defstruct line-number
735  start-pc
736  line)
737
738(defstruct (local-variables-attribute (:conc-name local-var-)
739                                      (:include attribute
740                                                (name "LocalVariableTable")))
741  locals)
742
743(defstruct (local-variable (:conc-name local-))
744  start-pc
745  length
746  name
747  descriptor
748  index)
749
750#|
751
752;; this is the minimal sequence we need to support:
753
754;;  create a class file structure
755;;  add methods
756;;  add code to the methods, switching from one method to the other
757;;  finalize the methods, one by one
758;;  write the class file
759
760to support the sequence above, we probably need to
761be able to
762
763- find methods by signature
764- find the method's code attribute
765- add code to the code attribute
766- finalize the code attribute contents (blocking it for further addition)
767-
768
769
770|#
771
Note: See TracBrowser for help on using the repository browser.