+
+;;; This is the main mechanism for allocating memory in the lisp heap.
+;;;
+;;; The allocated space is stored in RESULT-TN with the lowtag LOWTAG
+;;; applied. The amount of space to be allocated is SIZE bytes (which
+;;; must be a multiple of the lisp object size).
+;;;
+;;; On other platforms (Non-PPC), if STACK-P is given, then allocation
+;;; occurs on the control stack (for dynamic-extent). In this case,
+;;; you MUST also specify NODE, so that the appropriate compiler
+;;; policy can be used, and TEMP-TN, which is needed for work-space.
+;;; TEMP-TN MUST be a non-descriptor reg. FIXME: This is not yet
+;;; implemented on PPC. We should implement this and replace the
+;;; inline stack-based allocation that presently occurs in the
+;;; VOPs. The stack-p argument is ignored on PPC.
+;;;
+;;; If generational GC is enabled, you MUST supply a value for TEMP-TN
+;;; because a temp register is needed to do inline allocation.
+;;; TEMP-TN, in this case, can be any register, since it holds a
+;;; double-word aligned address (essentially a fixnum).
+(defmacro allocation (result-tn size lowtag &key stack-p node temp-tn flag-tn)
+ ;; We assume we're in a pseudo-atomic so the pseudo-atomic bit is
+ ;; set. If the lowtag also has a 1 bit in the same position, we're all
+ ;; set. Otherwise, we need to zap out the lowtag from alloc-tn, and
+ ;; then or in the lowtag.
+ ;; Normal allocation to the heap.
+ (declare (ignore stack-p node)
+ #!-gencgc
+ (ignore temp-tn flag-tn))
+ #!-gencgc
+ (let ((alloc-size (gensym)))
+ `(let ((,alloc-size ,size))
+ (if (logbitp (1- n-lowtag-bits) ,lowtag)
+ (progn
+ (inst ori ,result-tn alloc-tn ,lowtag))
+ (progn
+ (inst clrrwi ,result-tn alloc-tn n-lowtag-bits)
+ (inst ori ,result-tn ,result-tn ,lowtag)))
+ (if (numberp ,alloc-size)
+ (inst addi alloc-tn alloc-tn ,alloc-size)
+ (inst add alloc-tn alloc-tn ,alloc-size))))
+ #!+gencgc
+ (let ((fix-addr (gensym))
+ (inline-alloc (gensym)))
+ `(let ((,fix-addr (gen-label))
+ (,inline-alloc (gen-label)))
+ ;; Make temp-tn be the size
+ (cond ((numberp ,size)
+ (inst lr ,temp-tn ,size))
+ (t
+ (move ,temp-tn ,size)))
+
+ (inst lr ,flag-tn (make-fixup "boxed_region" :foreign))
+ (inst lwz ,result-tn ,flag-tn 0)
+
+ ;; we can optimize this to only use one fixup here, once we get
+ ;; it working
+ ;; (inst lr ,flag-tn (make-fixup "boxed_region" :foreign 4))
+ ;; (inst lwz ,flag-tn ,flag-tn 0)
+ (inst lwz ,flag-tn ,flag-tn 4)
+
+ (without-scheduling ()
+ ;; CAUTION: The C code depends on the exact order of
+ ;; instructions here. In particular, three instructions before
+ ;; the TW instruction must be an ADD or ADDI instruction, so it
+ ;; can figure out the size of the desired allocation.
+ ;; Now make result-tn point at the end of the object, to
+ ;; figure out if we overflowed the current region.
+ (inst add ,result-tn ,result-tn ,temp-tn)
+ ;; result-tn points to the new end of the region. Did we go past
+ ;; the actual end of the region? If so, we need a full alloc.
+ ;; The C code depends on this exact form of instruction. If
+ ;; either changes, you have to change the other appropriately!
+ (inst cmpw ,result-tn ,flag-tn)
+
+ (inst bng ,inline-alloc)
+ (inst tw :lge ,result-tn ,flag-tn))
+ (inst b ,fix-addr)
+
+ (emit-label ,inline-alloc)
+ (inst lr ,flag-tn (make-fixup "boxed_region" :foreign))
+ (inst stw ,result-tn ,flag-tn 0)
+
+ (emit-label ,fix-addr)
+ ;; At this point, result-tn points at the end of the object.
+ ;; Adjust to point to the beginning.
+ (inst sub ,result-tn ,result-tn ,temp-tn)
+ ;; Set the lowtag appropriately
+ (inst ori ,result-tn ,result-tn ,lowtag))))
+
+(defmacro with-fixed-allocation ((result-tn flag-tn temp-tn type-code size
+ &key (lowtag other-pointer-lowtag))
+ &body body)