2017-01-14 2 views
1

Я студент компьютерных наук, в настоящее время принимает Compilation курса, у нас есть проект во время курса, чтобы построить компилятор в IC языка, который является подмножеством языка Java. Я в финальной части, где мне нужно сгенерировать MIPS сборка без выделения регистров из ИК-дерева.
Я пытаюсь понять, как экземпляры объектов представлены в MIPS сборка. Я знаю, что мне нужно создать таблицу виртуальных функций для каждого экземпляра объекта (который содержит адреса функций, релевантных для экземпляра).
Мой вопрос:
Нужно ли делать аналогичную таблицу для полей класса, потому что поля также наследуются. И как бы вы предложили это сделать?
Кроме того, я был бы очень признателен, если бы кто-нибудь мог привести пример того, как будет выглядеть код сборки для MIPS
для экземпляров объектов, которые наследуют классы и поля.
Например что бы MIPS код выглядеть для:объектно-ориентированное наследование в MIPS Ассамблее

class A{ 
    int x; 
    void f(){} 
} 

class B extends A{ 
    int y; 
    void g(){} 

    void main(){ 
     A newObj = new B(); 
     newObj.f(); 
     newObj.x++; 
    } 
} 
+1

Поля не могут быть виртуальными, поэтому нет необходимости в таблице. Если вы хотите узнать, как выглядит asm, используйте существующий компилятор. – Jester

+2

Обратите внимание, что VMT не требуется * один раз для каждого экземпляра * - * Один раз для каждого класса *, и всех экземпляров, содержащих указатель, достаточно. – tofro

ответ

2

Я обращаюсь только эта часть вопроса:

Кроме того, я был бы очень признателен, если кто-нибудь может привести пример как реально выглядит код сборки MIPS

Я переписал ваш пример на C++ таким образом, что компилятор C++ с несколькими коммутаторами не будет оптимизировать полностью исключить его и сохранить поля и вызовы (если вы задаетесь вопросом, почему используется volatile, а также некоторые другие вещи, просто чтобы предотвратить компилятор для сборки сборки, например return value = 5, return ... Компиляторы на C++, как правило, немного раздражают друг друга с оптимизацией, когда вы хотите просто увидеть некоторый «примерный» код).

class A { 
    public: 
    volatile int x; 
    virtual void f(){ 
     ++x; 
    } 
}; 

class B : public A { 
    public: 
    volatile int y; 
    B(int i) { 
     y = i; 
     x = i-1; 
    } 
    virtual void f(){ 
     x += 2; 
    } 
    void g() { 
     f(); 
     x += 3; 
     ++y; 
    } 
}; 

int footest(int in) { 
    B* obj = new B(in); 
    A* obj_A_alias = obj; 
    obj_A_alias->f();  // calling B::f(), because f is virtual 
    obj->g(); 
    obj->f(); 
    obj->A::f();   // forcing A::f() call (on B instance) 
    int result = obj->x + obj->y; 
    delete obj; 
    return result; 
} 

Теперь, если вы поставите это в http://godbolt.org/ и настроить компилятор MIPS GCC 5.4 с вариантами -O3 -std=c++11 -fno-loop-optimize -fno-inline, вы получите этот результат:

$LFB0 = . 
A::f(): 
$LVL0 = . 
     lw  $2,4($4) 
     addiu $2,$2,1 
     sw  $2,4($4) 
     j  $31 
     nop 

$LFB7 = . 
B::f(): 
$LVL1 = . 
     lw  $2,4($4) 
     addiu $2,$2,2 
     sw  $2,4($4) 
     j  $31 
     nop 

$LFB3 = . 
A::A(): 
$LVL2 = . 
$LBB2 = . 
     lui  $2,%hi(vtable for A+8) 
     addiu $2,$2,%lo(vtable for A+8) 
     j  $31 
     sw  $2,0($4) 

$LBE2 = . 
     A::A() = A::A() 
$LFB5 = . 
B::B(int): 
$LVL3 = . 
     addiu $sp,$sp,-40 
     sw  $17,32($sp) 
     move $17,$5 
     sw  $31,36($sp) 
     sw  $16,28($sp) 
$LBB3 = . 
     jal  A::A() 
     move $16,$4 

$LVL4 = . 
     addiu $2,$17,-1 
$LBE3 = . 
     lw  $31,36($sp) 
$LBB4 = . 
     sw  $17,8($16) 
     sw  $2,4($16) 
     lui  $2,%hi(vtable for B+8) 
$LBE4 = . 
     lw  $17,32($sp) 
$LVL5 = . 
$LBB5 = . 
     addiu $2,$2,%lo(vtable for B+8) 
     sw  $2,0($16) 
$LBE5 = . 
     lw  $16,28($sp) 
$LVL6 = . 
     j  $31 
     addiu $sp,$sp,40 

     B::B(int) = B::B(int) 
$LFB8 = . 
B::g(): 
$LVL7 = . 
     lw  $2,0($4) 
     addiu $sp,$sp,-32 
     sw  $16,24($sp) 
     sw  $31,28($sp) 
     lw  $25,0($2) 
     jalr $25 
     move $16,$4 

$LVL8 = . 
     lw  $2,4($16) 
     lw  $31,28($sp) 
     addiu $2,$2,3 
     sw  $2,4($16) 
     lw  $2,8($16) 
     addiu $2,$2,1 
     sw  $2,8($16) 
     lw  $16,24($sp) 
$LVL9 = . 
     j  $31 
     addiu $sp,$sp,32 

$LFB9 = . 
footest(int): 
$LVL10 = . 
     lui  $28,%hi(__gnu_local_gp) 
     addiu $sp,$sp,-32 
     addiu $28,$28,%lo(__gnu_local_gp) 
     sw  $16,24($sp) 
     move $16,$4 
$LVL11 = . 
     sw  $31,28($sp) 
     lw  $25,%call16(operator new(unsigned int))($28) 
1:  jalr  $25 
     li  $4,12     # 0xc 

$LVL12 = . 
     move $5,$16 
     move $16,$2 
$LVL13 = . 
     jal  B::B(int) 
     move $4,$2 

$LVL14 = . 
$LVL15 = . 
     jal  B::f() 
     move $4,$16 

$LVL16 = . 
     jal  B::g() 
     move $4,$16 

$LVL17 = . 
     lw  $2,0($16) 
     lw  $25,0($2) 
     jalr $25 
     move $4,$16 

$LVL18 = . 
     jal  A::f() 
     move $4,$16 

$LVL19 = . 
     move $4,$16 
     lw  $28,16($sp) 
     lw  $2,4($16) 
     lw  $16,8($16) 
$LVL20 = . 
     lw  $25,%call16(operator delete(void*))($28) 
$LVL21 = . 
1:  jalr  $25 
     addu $16,$2,$16 

$LVL22 = . 
     move $2,$16 
     lw  $31,28($sp) 
     lw  $16,24($sp) 
$LVL23 = . 
     j  $31 
     addiu $sp,$sp,32 

typeinfo name for A: 
     .ascii "1A\000" 
typeinfo for A: 
     .word vtable for __cxxabiv1::__class_type_info+8 
     .word typeinfo name for A 
typeinfo name for B: 
     .ascii "1B\000" 
typeinfo for B: 
     .word vtable for __cxxabiv1::__si_class_type_info+8 
     .word typeinfo name for B 
     .word typeinfo for A 
vtable for A: 
     .word 0 
     .word typeinfo for A 
     .word A::f() 
vtable for B: 
     .word 0 
     .word typeinfo for B 
     .word B::f() 

Try it на фактическом месте, так что вы получите также цветные подсказки, какая часть кода принадлежит той части источника (а также компиляторы MIPS64, если это ваша целевая платформа).


EDIT: Кроме того, вы должны, вероятно, попробовать -O0 вариант также, что выход будет очень вероятно, гораздо больше связаны с тем, что вы можете разумно достигнуть с одним студентом только проект.


Я не достаточно хорошо в MIPS, чтобы объяснить вам, что происходит там, и у меня есть время для этого, но если вы производите компилятор, вы должны понимать это лучше, чем у меня.

C++ источник демонстрирует, как виртуальный вызов делается ($LVL17), не виртуальный родительский вызов ($LVL18), не виртуальный самостоятельный вызов ($LVL16), и доступ к значениям полей ($LVL19).

Теперь имейте в виду, что это профессионально оптимизированный инструмент, поэтому, если вы закончите с менее оптимальным решением, все должно быть хорошо. Также имейте в виду, что компиляция Java и C++ немного отличается, в Java конечный результат не является «статичным», как C++, поэтому, возможно, у вас недостаточно информации для оптимизации так агрессивно, как C++, вызовы виртуальных функций просто жестко запрограммированы с целевым адресом или полями тоже ...

В конце концов, если это Java, вы не можете ожидать, что он будет оптимальным, поскольку для управляемого языка исполнения он является прекрасным и вместе с высококачественный JIT-компилятор, базовая скорость кода может быть на одном уровне с C++, но как только вы попадаете в неэффективные структуры данных Java, C++ «swoooshs» вдоль и за горизонтом.

Смежные вопросы