Skip to content

condition-continuation gives inaccurate information #981

@mnieper

Description

@mnieper

Consider the following code:

(import (scheme))

(define (f1)
  (with-continuation-mark 'key 'outer
    (f2)))

(define (f2)
  (car
    (list
      (call/cc
        (lambda (c)
          (continuation-marks->list (continuation-next-marks c) 'key))))))

(define (g1 x)
  (with-continuation-mark 'key 'outer
    (g2 x)))

(define kar car)

(define (g2 x)
  (kar
    (list
      (fx+ x x))))

(pretty-print (f1))

(guard (c ((implementation-restriction-violation? c)
           (pretty-print (continuation-marks->list (continuation-next-marks (condition-continuation c)) 'key))))
  (pretty-print (g1 (greatest-fixnum))))

If it is run as a script (so that the optimiser cannot do interprocedural optimisations), it first prints (outer) and then (). The expected console output is (outer) twice.

The reason that it doesn't work as advertised in the manual (condition-continuation "indicates the current continuation at the point where the exception described by the condition occurred") is that the compiler basically turns the call to the error handler for fx+ into a tail call. This is the generated assembly on my machine:

g2:
entry.71:
0:       subi           (imm 1), $trap
5:       beq            lt.68(123)
ej.72:
7:       cmpi           (imm 1), %ac0
11:      bne            lf.67(105)
dcl.73:
13:      mov            %r8, %rcx
16:      or             %r8, %rcx
19:      testib         (imm 7), %rcx
22:      bne            Llib.66(79)
lt.74:
24:      mov            %r8, %rcx
27:      add            %r8, %rcx
30:      bvs            Llib.66(71)
ej.75:
32:      lea            (disp -7 %ap), %xp
36:      addi           (imm 16), %ap
40:      cmp            %ap, $eap
44:      bcs            Lget-room.65(42)
ej.64:
46:      mov            %xp, %r8
49:      mov            %rcx, (disp 7 %r8)
53:      movi           (imm 38), (disp 15 %r8)
61:      movi           (literal 0 (object kar.*top*:kar)), %xp
71:      mov            (disp 5 %xp), %cp
76:      movi           (imm 1), %ac0
83:      jmp            (disp 13 %xp)
Lget-room.65:
88:      movi           (imm 4294967295), %xp
98:      call           %xp
101:     relocation:    (x86_64-call 65 (library-code #(libspec get-room 178)))
101:     bra            ej.64(-57)
Llib.66:
103:     mov            %r8, %rdi
106:     movi           (imm 4294967295), %ts
116:     jmp            %ts
118:     relocation:    (x86_64-jump 65 (library-code #(libspec fx+ 51256)))
lf.67:
118:     movi           (imm 4294967295), %ts
128:     jmp            %ts
130:     relocation:    (x86_64-jump 65 (library-code #(libspec doargerr 176)))
lt.68:
130:     movi           (imm 4294967295), %ts
140:     jmp            %ts
142:     relocation:    (x86_64-jump 65 (library-code #(libspec event-detour 180)))
142:     <end g2>

To fix it, the compiler must not treat calls to library error procedures as tail calls if they do not happen in tail position (but this will blow up the code size). Alternatively, the specification of (condition-continuation) must be weakened, making it less reliable. I haven't tested how much Racket is affected by this inaccuracy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions