$30 off During Our Annual Pro Sale. View Details »

Kompilator Ruby – C

Kompilator Ruby – C

Slides from a presentation delivered on 2.2.2011 at the Warsaw Ruby Users Group meetup.

http://wrug.eu/2011/01/31/2011-02-spotkanie-lutowe/

Jan Stępień

February 02, 2011
Tweet

More Decks by Jan Stępień

Other Decks in Programming

Transcript

  1. Kompilator Ruby – C
    Jan Stępień Julian Zubek
    2 lutego 2011

    View Slide

  2. Ruby jest wolny
    Źródło: http://shootout.alioth.debian.org

    View Slide

  3. Ruby jest wolny
    Przetłumaczmy Ruby na C!

    View Slide

  4. Cele projektu
    Ruby −→ binarny plik wykonywalny
    Uzyskać krótszy czas wykonania

    View Slide

  5. Wspierany podzbiór Ruby
    Obiektowość: klasy, obiekty, metody, pola
    Dynamiczne nadpisywanie metod
    Uproszczone bloki
    Ułamek biblioteki standardowej

    View Slide

  6. Schemat działania
    Wczytanie kodu
    Parsowanie
    Translacja
    Generowanie kodu C
    Kompilacja
    Linkowanie
    Kod Ruby
    AST Ruby
    AST C
    Kod C
    Plik obiektowy

    View Slide

  7. Schemat działania
    Wczytanie kodu
    Parsowanie
    Translacja
    Generowanie kodu C
    Kompilacja
    Linkowanie
    ruby parser
    GCC

    View Slide

  8. Narzędzia
    Translator napisany w Ruby
    Biblioteka standardowa w C
    Parser: ruby parser
    Garbage collector: BDWGC
    Struktury danych: GLib

    View Slide

  9. Proste wyrażenia
    b = 0
    a = if b
    a = 1
    b = 2
    end
    Object *b;
    b = (Fixnum_new (0));
    Object *a;
    Object *var1;
    if (boolean_value (b)) {
    a = (Fixnum_new (1));
    b = (Fixnum_new (2));
    var1 = b;
    }
    a = var1;

    View Slide

  10. Obiekty
    typedef struct {
    uint32_t type;
    } Object;
    typedef struct {
    Object parent;
    int val;
    } Fixnum;

    View Slide

  11. Tłumaczenie klas
    class A
    def set(a)
    @a = a
    end
    def get
    @a
    end
    end
    typedef struct {
    Object meta;
    Object *a;
    } A;
    Object * A_set_Fixnum(Object *self,
    Object *a) {
    (((A *) self)->a) = a;
    return ((A *) self)->a;
    }
    Object * A_get(Object *self) {
    return ((A *) self)->a;
    }

    View Slide

  12. Pola przy dziedziczeniu
    typedef struct {
    uint32 type;
    } Object;
    typedef struct {
    Object parent;
    Object* leg_count;
    } Animal;
    typedef struct {
    Object parent;
    Object* leg_count;
    Object* horns_length;
    } Cow;

    View Slide

  13. Metody
    Tłumaczenie dopiero w momencie wywołania
    Każda metoda to funkcja w C
    Jeśli znamy typy przekazanych argumentów to
    tworzymy osobną funkcję

    View Slide

  14. Metody
    dict_elem classes_dictionary[] = {
    {-1, &Object_method_find, &vs_Object},
    {0, NULL, &vs_M_Object},
    {0, NULL, &vs_Class},
    {0, &Fixnum_method_find, &vs_Fixnum},
    {0, &Float_method_find, &vs_Float},
    /* ... */
    }

    View Slide

  15. Metody
    Znamy wszystkie nazwy metod
    Perfekcyjny hash bez kolizji
    Cache metod
    Nadpisanie metody to po prostu zmiana
    wskaźnika na funkcję

    View Slide

  16. Bloki
    Każdy blok to funkcja C
    Stos bloków pozwala na zagnieżdżanie

    View Slide

  17. Bloki
    2.upto 5 do |ocena|
    puts "Wypiszmy " + ocena.to_s
    end

    View Slide

  18. Bloki
    typedef Object* (*block_t)(Object*, ...);
    static Object* block1(Object* self,Object* ocena) {
    Object* _var2[1]= {ocena};
    Object* _var1;
    _var1=(call_method((ocena->type),"to__s",classes_dictionary,_var2));
    Object* _var3;
    _var3=(String__PLUS_((String_new("Wypiszmy: ")),_var1));
    Object* _var4;
    _var4=(Object_puts(self,_var3));
    return _var4;
    };
    int main() {
    /* ... */
    push_block((((block_t)block1)));
    Object* _var5;
    _var5=(Fixnum_upto((Fixnum_new(2)),(Fixnum_new(5))));
    pop_block();
    return 0;
    }

    View Slide

  19. Odśmiecanie pamięci
    Boehm-Demers-Weiser GC
    malloc → GC malloc
    free →

    View Slide

  20. Optymalizacja arytmetyki
    puts((4 + 5.4) / 2)
    Object* _var1;
    _var1 = Fixnum__PLUS_(Fixnum_new(4),
    Float_new(5.4)));
    Object* _var2;
    _var2 = Float__DIV_(_var1, Fixnum_new(2));
    Object_puts(self, _var2);
    Object_puts(self, Float_new((4 + 5.4) / 2));

    View Slide

  21. Biblioteka standardowa
    class Fixnum
    defined_in_stdlib
    def /(arg)
    defined_as :Fixnum__DIV_
    Fixnum.returned_if Fixnum
    Float.returned_if Float
    end
    def to_s
    defined_as :Fixnum_to__s
    returns String
    end
    # I tak dalej...
    end

    View Slide

  22. Zgodność z Ruby 1.9
    97% pokrycia kodu testami
    Cel: odpalić RubySpec

    View Slide

  23. Przenośność

    View Slide

  24. Wyniki
    Test Poprawa
    ackermann.rb 3,91
    arrays.rb 4,46
    arithmetic.rb 5,20
    heapsort.rb 1,30
    matrix.rb 0,67
    quicksort.rb 0,96
    strings.rb 0,33
    Ruby 1.9.2, GNU/Linux 2.6.35, i686, Intel Core 2 Duo T6570 @ 2,10GHz, 2GB RAM

    View Slide

  25. matrix.rb – mnożenie macierzy
    main
    0 (0.0%)
    of 86 (100.0%)
    M_Object_mmult_Fixnum_Fixnum_Array_Array
    9 (10.5%)
    of 82 (95.3%)
    82
    _init
    7 (8.1%)
    4
    call_method
    17 (19.8%)
    of 56 (65.1%)
    56
    Array__INDEX_
    11 (12.8%)
    3
    Fixnum_new
    3 (3.5%)
    of 11 (12.8%)
    11
    1
    Fixnum__MUL_
    5 (5.8%)
    of 12 (14.0%)
    12
    8
    __strcmp_ssse3
    7 (8.1%)
    7
    1
    Fixnum__PLUS_
    1 (1.2%)
    of 6 (7.0%)
    6
    Array_method_find
    2 (2.3%)
    2
    Fixnum_method_find
    2 (2.3%)
    2
    xmalloc_atomic
    3 (3.5%)
    of 19 (22.1%)
    Garbage
    collector
    18.6%
    16
    7
    8
    4 1

    View Slide

  26. quicksort.rb – rekurencja i tablice
    main
    0 (0.0%)
    of 266 (100.0%)
    M_Object_qsort_Array
    21 (7.9%)
    of 262 (98.5%)
    262
    Fixnum_new
    10 (3.8%)
    of 126 (47.4%)
    boolean_value
    8 (3.0%)
    1
    3226
    53
    call_method
    20 (7.5%)
    of 80 (30.1%)
    80
    Array_length
    1 (0.4%)
    of 74 (27.8%)
    52
    Array_push
    2 (0.8%)
    of 36 (13.5%)
    27
    Array__INDEX_
    10 (3.8%)
    7
    7
    xmalloc_atomic
    4 (1.5%)
    of 116 (43.6%)
    115
    Garbage
    54.8%
    collector
    112
    22 9
    3
    Float__LT_
    6 (2.3%)
    of 8 (3.0%)
    8
    Array_method_find
    6 (2.3%)
    of 7 (2.6%)
    7
    72

    View Slide

  27. strings.rb – bardzo długie stringi
    String__PLUS_
    0 (0.0%)
    of 1232 (98.2%)
    *__GI_strncpy
    801 (63.8%)
    801
    String_new
    0 (0.0%)
    of 400 (31.9%)
    393
    __strlen_sse2
    38 (3.0%)
    38
    xmalloc_atomic
    0 (0.0%)
    of 304 (24.2%)
    295
    g_string_append_len
    0 (0.0%)
    of 99 (7.9%)
    99
    GC_malloc_atomic
    0 (0.0%)
    of 304 (24.2%)
    GC_generic_malloc
    0 (0.0%)
    of 298 (23.7%)
    294
    304
    290
    main
    1 (0.1%)
    of 261 (20.8%)
    242
    Garbage
    23.7%
    collector
    __memcpy_ssse3
    99 (7.9%)
    g_slice_alloc
    (inline)
    0 (0.0%)
    of 99 (7.9%)
    g_string_append_len
    (inline)
    0 (0.0%)
    of 99 (7.9%)
    99
    99
    99
    99
    198

    View Slide

  28. Dalszy rozwój
    Brakujące elementy Ruby: lambdy, moduły,
    wątki, wyjątki, biblioteka standardowa...
    Optymalizacja przetwarzanego kodu
    Wykorzystanie rozwiązań z YARV
    Optymalizacja wyszukiwania metod
    Dalsza praca nad statycznym
    rozpoznawaniem typów
    RubySpec, self-hosting

    View Slide

  29. Open source już wkrótce
    (jak tylko nie będziemy się mieli czego wstydzić)

    View Slide

  30. [email protected]
    github.com/jstepien
    twitter.com/janstepien
    Dziękuję

    View Slide

  31. Źródła zdjęć
    http://flickr.com/photos/10943651@N00/3044525754
    http://flickr.com/photos/thomasgraham/2360853639
    Prezentację utworzono przy pomocy pakietu L
    A
    TEX.

    View Slide