ich nur dieser Teil der Frage bin Adressierung:
Außerdem wäre ich sehr dankbar, wenn jemand ein Beispiel geben könnte aussehen würde, wie Assembler-Code realen MIPS
ich habe Ihr Beispiel in C++ neu zu schreiben in einer Weise, dass C++ Compiler mit wenigen Schaltern wird nicht opti Mize es völlig aus und halten Sie die Felder und Anrufe (wenn Sie sich wundern, warum volatile
verwendet wird, und einige andere Dinge, nur um zu verhindern, Compiler zu Assembly wie return value = 5, return
produzieren ... C++ Compiler neigen dazu, ein bisschen genervt gut mit Optimierungen, wenn Sie will nur einen "Beispielcode" sehen.
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;
}
Nun, wenn Sie diese in http://godbolt.org/ und einrichten Compiler MIPS gcc 5.4 mit Optionen -O3 -std=c++11 -fno-loop-optimize -fno-inline
gesetzt wird, werden Sie diese Ausgabe erhalten:
$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 auf dem tatsächlichen Ort, so dass Sie bekommen auch farbige Hinweise, welcher Teil des Codes zu welchem Teil der Quelle gehört (und es gibt auch MIPS64-Compiler, wenn dies Ihre Zielplattform ist).
EDIT: auch Sie sollten wahrscheinlich zu -O0
Option versuchen, wird diese Ausgabe sehr wahrscheinlich viel mehr aufeinander bezogene, was Sie mit einem Schüler-alone-Projekt vernünftig erreichen kann.
Ich bin nicht gut genug, um in MIPS Ihnen zu erklären, was dort vor sich geht, noch habe ich Zeit dafür haben, aber wenn Sie Compiler produzieren, sollten Sie es besser ist als ich verstehen.
Die C++ Quelle demonstriert, wie virtueller Aufruf erfolgt ($LVL17
), nicht virtueller Mutter Anruf ($LVL18
), nicht virtueller Selbstanruf ($LVL16
) und Feldwerte Zugang ($LVL19
).
Denken Sie daran, dies ist ein professionelles optimiertes Tool. Wenn Sie mit einer weniger optimalen Lösung enden, sollte es in Ordnung sein. Bedenken Sie auch, dass sich die Kompilierung von Java und C++ ein wenig unterscheidet, in Java ist das Endergebnis nicht so "statisch" wie C++, also könnte es sein, dass Sie nicht genug Informationen haben, um so aggressiv zu optimieren wie C++ Virtuelle Funktionsaufrufe werden einfach mit der Zieladresse oder auch mit Feldern programmiert ...
Wenn es Java ist, kann man nicht erwarten, dass es optimal ist, für eine verwaltete Runtime-Sprache ist es gut und zusammen mit hoher Qualität JIT-Compiler die grundlegende Code-Geschwindigkeit kann auf Augenhöhe mit C++ sein, aber sobald Sie von ineffizienten Java-Datenstrukturen getroffen werden, C++ "shoooshs" entlang und jenseits von Horizont.
Felder können nicht virtuell sein, daher ist keine Tabelle erforderlich. Wenn Sie wissen möchten, wie der Asm aussieht, verwenden Sie einen vorhandenen Compiler. – Jester
Beachten Sie, dass ein VMT nicht einmal * pro Instanz benötigt wird * - * Einmal pro Klasse * und alle Instanzen, die einen Zeiger dorthin halten, sind ausreichend. – tofro