Why does scope(success) have to use exceptions?

Andrej Mitrovic andrej.mitrovich at gmail.com
Wed Jan 16 15:19:09 PST 2013


Sample code:

void callScope(ref int x)
{
    x = 1;
    scope(success) { x = 2; }
    x = 3;
    scope(success) { x = 4; }
}

void callFunc(ref int x)
{
    x = 1;
    x = 3;
    x = 4;
    x = 2;
}

void main()
{
    int x;
    callScope(x);
    assert(x == 2);

    callFunc(x);
    assert(x == 2);
}

I was expecting callScope to be lowered down to the handwritten code
in callFunc in assembly, but instead it uses exceptions. Here's some
simple ASM for callFunc compiled with -c -release -O (no inline):

_D4test8callFuncFKiZv:; Function begin, communal
        mov     dword [eax], 1                          ; 0000 _ C7.
00, 00000001
        mov     ecx, eax                                ; 0006 _ 89. C1
        mov     dword [ecx], 3                          ; 0008 _ C7.
01, 00000003
        mov     dword [ecx], 4                          ; 000E _ C7.
01, 00000004
        mov     dword [ecx], 2                          ; 0014 _ C7.
01, 00000002
        ret                                             ; 001A _ C3
; _D4test8callFuncFKiZv End of function

And this monster code for callScope:

_D4test9callScopeFKiZv:; Function begin, communal
        push    ebp                                     ; 0000 _ 55
        mov     ebp, esp                                ; 0001 _ 8B. EC
        mov     edx, dword [fs:__except_list]           ; 0003 _ 64:
8B. 15, 00000000(segrel)
        push    -1                                      ; 000A _ 6A, FF
        mov     ecx, 1                                  ; 000C _ B9, 00000001
        push    _D4test9callScopeFKiZv+0A6H             ; 0011 _ 68,
000000A6(segrel)
        push    edx                                     ; 0016 _ 52
        mov     dword [fs:__except_list], esp           ; 0017 _ 64:
89. 25, 00000000(segrel)
        sub     esp, 24                                 ; 001E _ 83. EC, 18
        push    ebx                                     ; 0021 _ 53
        push    esi                                     ; 0022 _ 56
        push    edi                                     ; 0023 _ 57
        mov     dword [ebp-18H], eax                    ; 0024 _ 89. 45, E8
        mov     dword [eax], ecx                        ; 0027 _ 89. 08
        mov     byte [ebp-1CH], 0                       ; 0029 _ C6. 45, E4, 00
        mov     dword [ebp-4H], 0                       ; 002D _ C7.
45, FC, 00000000
        mov     dword [ebp-4H], ecx                     ; 0034 _ 89. 4D, FC
        mov     dword [eax], 3                          ; 0037 _ C7.
00, 00000003
        xor     ecx, ecx                                ; 003D _ 31. C9
        mov     dword [eax], 4                          ; 003F _ C7.
00, 00000004
        mov     dword [ebp-4H], ecx                     ; 0045 _ 89. 4D, FC
        jmp     ?_002                                   ; 0048 _ EB, 0C

; Note: Inaccessible code
        mov     byte [ebp-1CH], 1                       ; 004A _ C6. 45, E4, 01
        push    dword [ebp-20H]                         ; 004E _ FF. 75, E0
        call    __d_throwc                              ; 0051 _ E8,
00000000(rel)
?_002:  mov     dword [ebp-4H], -1                      ; 0056 _ C7.
45, FC, FFFFFFFF
; Note: Displacement could be made smaller by sign extension
        lea     ecx, [ebp-0CH]                          ; 005D _ 8D.
8D, FFFFFFF4
        push    -1                                      ; 0063 _ 6A, FF
        push    ecx                                     ; 0065 _ 51
        push    FLAT:?_001                              ; 0066 _ 68,
00000000(segrel)
        call    __d_local_unwind2                       ; 006B _ E8,
00000000(rel)
        add     esp, 12                                 ; 0070 _ 83. C4, 0C
        call    ?_003                                   ; 0073 _ E8, 00000002
        jmp     ?_005                                   ; 0078 _ EB, 18

?_003:  mov     dword [ebp-4H], -1                      ; 007A _ C7.
45, FC, FFFFFFFF
        mov     al, byte [ebp-1CH]                      ; 0081 _ 8A. 45, E4
        xor     al, 01H                                 ; 0084 _ 34, 01
        jz      ?_004                                   ; 0086 _ 74, 09
        mov     edx, dword [ebp-18H]                    ; 0088 _ 8B. 55, E8
        mov     dword [edx], 2                          ; 008B _ C7.
02, 00000002
?_004:  ret                                             ; 0091 _ C3

?_005:
; Note: Displacement could be made smaller by sign extension
        mov     ecx, dword [ebp-0CH]                    ; 0092 _ 8B.
8D, FFFFFFF4
        mov     dword [fs:__except_list], ecx           ; 0098 _ 64:
89. 0D, 00000000(segrel)
        pop     edi                                     ; 009F _ 5F
        pop     esi                                     ; 00A0 _ 5E
        pop     ebx                                     ; 00A1 _ 5B
        mov     esp, ebp                                ; 00A2 _ 8B. E5
        pop     ebp                                     ; 00A4 _ 5D
        ret                                             ; 00A5 _ C3
; _D4test9callScopeFKiZv End of function

I'm trying to understand why. If an exception is thrown between one of
those assignment statements the stack will unwind and any following
assignment statements will not be called, so there shouldn't be a need
to check if an exception is thrown. Why doesn't the compiler simply
rewrite callScope to look like callFunc?


More information about the Digitalmars-d mailing list