Skip to content

Commit 16d0c38

Browse files
committed
x86: support for protecting register values from the GC
1 parent ef751d1 commit 16d0c38

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

compiler/codegen-generic.pco

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
(emit-comment cg "~S" (comment-form form))))
3535

3636
(define (register-bitset regs)
37-
(reduce (register-bit (car regs)) (cdr regs)
37+
(reduce 0 regs
3838
(lambda (bits reg) (logior bits (register-bit reg)))))
3939

4040
;; Assembly utility functions

compiler/codegen-x86.pco

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,16 @@
244244

245245
;;; Heap allocation
246246

247-
(define (emit-alloc cg size size-align post-align allocreg spare-regs)
247+
(define (heap-exhausted-bitset spare-regs protect-regs)
248+
(let* ((prot-bits (register-bitset protect-regs)))
249+
;; Protected registers are distinct from live registers for the
250+
;; purposes of heap_exhausted, so we include them in the spare
251+
;; register set.
252+
(logior (logior (register-bitset spare-regs) prot-bits)
253+
(ash prot-bits general-register-count))))
254+
255+
(define (emit-alloc cg size size-align post-align allocreg spare-regs
256+
protect-regs)
248257
(let* ((again-label (gen-label))
249258
(exhausted-label (gen-label)))
250259
(flush-labels-and-jumps cg)
@@ -260,19 +269,20 @@
260269
(codegen-push-out-of-line cg
261270
(lambda ()
262271
(emit-raw-label cg exhausted-label)
263-
(emit-mov cg (register-bitset (cons allocreg spare-regs)) %closure)
272+
(emit-mov cg (heap-exhausted-bitset (cons allocreg spare-regs)
273+
protect-regs) %closure)
264274
(emit cg "call heap_exhausted")
265275
(emit-restore-%closure cg)
266276
(emit-jump cg again-label)))))
267277

268278
(define gc-label (make-label-for 'gc direct-function-label-prefix))
269279

270280
(define (codegen-helpers cg)
271-
(labels ((for-live-registers (regs op)
281+
(labels ((for-registers (regs bit-offset negated-cond op)
272282
(dolist (reg regs)
273283
(let* ((l (gen-label)))
274-
(emit-test cg (register-bit reg) %closure)
275-
(emit-branch cg "nz" l)
284+
(emit-test cg (ash (register-bit reg) bit-offset) %closure)
285+
(emit-branch cg negated-cond l)
276286
(funcall op cg reg)
277287
(emit-raw-label cg l)))))
278288
(emit cg ".text")
@@ -281,18 +291,34 @@
281291
;; Push live registers onto the stack, guided by the bitset in
282292
;; %closure. This preserves their values, and also means that
283293
;; they get treated as part of the root set by the GC.
284-
(for-live-registers general-registers (function emit-push))
285-
(emit-push cg %closure)
294+
(for-registers general-registers 0 "nz" (function emit-push))
295+
296+
;; Push protected registers onto the stack. These are preserved,
297+
;; but not seen or touched by the GC.
298+
(for-registers general-registers general-register-count "z"
299+
(function emit-push))
286300

287-
;; The stack-bottom argument skips the live reg bitset, so that it
288-
;; doesn't get exposed to the GC.
289-
(emit-lea cg (indexed-operand %sp 1) %closure)
301+
;; Preserve the register bitset
290302
(emit-push cg %closure)
303+
304+
;; Work out the stack-bottom argument, skipping the live reg
305+
;; bitset and any protected register values
306+
(emit-lea cg (indexed-operand %sp 1) %a)
307+
(for-registers general-registers general-register-count "z"
308+
(lambda (cg reg) (emit-add cg value-size %a)))
309+
(emit-push cg %a)
291310
(emit cg "call ~A" gc-label)
292311

293-
;; Restore live registers
312+
;; Restore register bitset
294313
(emit-pop cg %closure)
295-
(for-live-registers (reverse general-registers) (function emit-pop))
314+
315+
(let* ((rev-gen-regs (reverse general-registers)))
316+
;; Restore protected registers
317+
(for-registers rev-gen-regs general-register-count "z"
318+
(function emit-pop))
319+
320+
;; Restore live registers
321+
(for-registers rev-gen-regs 0 "nz" (function emit-pop)))
296322

297323
(emit cg "ret")))
298324

@@ -301,7 +327,7 @@
301327
(define-operator (raw-alloc (size reg-imm)) ((temp-regs alloc))
302328
(emit-alloc cg (emit-scale-number cg value-scale size) value-scale
303329
(compiler-constant-value (attr-ref attrs 'tag-bits))
304-
alloc spare-regs)
330+
alloc spare-regs (if (number? size) () (list size)))
305331
(emit-mov cg alloc result)
306332
result)
307333

@@ -312,7 +338,7 @@
312338
;; enclosed by a lambda that does the initialization.
313339
(define-operator (alloc-closure) ()
314340
(emit-alloc cg (* value-size (1+ (attr-ref attrs 'length)))
315-
value-scale closure-tag-bits result spare-regs)
341+
value-scale closure-tag-bits result spare-regs ())
316342
(emit-mov cg (attr-ref attrs 'label) (mem-operand result))
317343
(emit-add cg closure-tag result)
318344
result)
@@ -393,7 +419,7 @@
393419
;;; Conses
394420

395421
(define-operator (cons (a reg-imm) (d reg-imm)) ((temp-regs alloc))
396-
(emit-alloc cg (* 2 value-size) value-scale pair-tag-bits alloc spare-regs)
422+
(emit-alloc cg (* 2 value-size) value-scale pair-tag-bits alloc spare-regs ())
397423
(emit-mov cg a (mem-operand alloc))
398424
(emit-mov cg d (indexed-operand alloc 1))
399425
(emit-lea cg (offset-operand alloc pair-tag) result)
@@ -413,7 +439,7 @@
413439
;;; Boxes
414440

415441
(define-operator (raw-make-box (val reg-imm)) ((temp-regs alloc))
416-
(emit-alloc cg value-size value-scale box-tag-bits alloc spare-regs)
442+
(emit-alloc cg value-size value-scale box-tag-bits alloc spare-regs ())
417443
(emit-mov cg val (mem-operand alloc))
418444
(emit-lea cg (offset-operand alloc box-tag) result)
419445
result)
@@ -435,7 +461,8 @@
435461

436462
(define-operator (raw-make-symbol (str reg-imm) (id reg-imm))
437463
((temp-regs alloc))
438-
(emit-alloc cg (* 2 value-size) value-scale symbol-tag-bits alloc spare-regs)
464+
(emit-alloc cg (* 2 value-size) value-scale symbol-tag-bits alloc spare-regs
465+
())
439466
(emit-mov cg str (mem-operand alloc))
440467
(emit-mov cg id (indexed-operand alloc 1))
441468
(emit-lea cg (offset-operand alloc symbol-tag) result)
@@ -547,7 +574,7 @@
547574
(emit-mov cg len %c)
548575
(emit-scale-number cg scale len)
549576
(emit-add cg value-size len)
550-
(emit-alloc cg len scale tag-bits alloc (list* %di spare-regs))
577+
(emit-alloc cg len scale tag-bits alloc (list* %di spare-regs) (list len))
551578
(emit-mov cg alloc %di)
552579
(emit-mov cg %c (mem-operand alloc))
553580
(emit-add cg value-size %di)

0 commit comments

Comments
 (0)