1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
#include "stdafx.h"
#include "VTableCall.h"
#include "Code/Listing.h"
#include "Core/StrBuf.h"
#include "Engine.h"
namespace storm {
VTableCalls::VTableCalls() {
cpp = new (this) Array<code::RefSource *>();
storm = new (this) Array<code::RefSource *>();
variants = engine().arena()->firstParamId(null);
}
code::RefSource *VTableCalls::get(VTableSlot slot, Value result) {
Engine &e = engine();
Nat id = e.arena()->firstParamId(result.desc(e));
switch (slot.type) {
case VTableSlot::tCpp:
return getCpp(slot.offset, id);
case VTableSlot::tStorm:
return getStorm(slot.offset, id);
default:
assert(false, L"Unknown slot type.");
return null;
}
}
code::RefSource *&VTableCalls::find(Array<code::RefSource *> *in, Nat offset, Nat id) {
Nat arrayId = offset*variants + id;
while (in->count() <= arrayId)
in->push(null);
return in->at(arrayId);
}
code::RefSource *VTableCalls::getCpp(Nat offset, Nat id) {
code::RefSource *&entry = find(cpp, offset, id);
if (entry)
return entry;
using namespace code;
Reg tmpReg = engine().arena()->functionDispatchReg();
Reg firstReg = tmpReg;
Operand firstParam = engine().arena()->firstParamLoc(id);
Listing *l = new (this) Listing();
if (firstParam.type() == opRegister) {
firstReg = firstParam.reg();
} else {
*l << mov(tmpReg, firstParam);
firstReg = tmpReg;
}
*l << mov(tmpReg, ptrRel(firstReg, Offset()));
*l << jmp(ptrRel(tmpReg, Offset::sPtr * offset));
Binary *b = new (this) Binary(engine().arena(), l);
entry = new (this) VTableSource(cppSlot(offset), id, b);
return entry;
}
code::RefSource *VTableCalls::getStorm(Nat offset, Nat id) {
code::RefSource *&entry = find(storm, offset, id);
if (entry)
return entry;
using namespace code;
Reg tmpReg = engine().arena()->functionDispatchReg();
Reg firstReg = tmpReg;
Operand firstParam = engine().arena()->firstParamLoc(id);
Listing *l = new (this) Listing();
if (firstParam.type() == opRegister) {
firstReg = firstParam.reg();
} else {
*l << mov(tmpReg, engine().arena()->firstParamLoc(id));
firstReg = tmpReg;
}
*l << mov(tmpReg, ptrRel(firstReg, Offset()));
*l << mov(tmpReg, ptrRel(tmpReg, -Offset::sPtr * vtable::extraOffset));
*l << jmp(ptrRel(tmpReg, Offset::sPtr * (offset + 2))); // 2 for the 2 size_t members in arrays.
Binary *b = new (this) Binary(engine().arena(), l);
entry = new (this) VTableSource(stormSlot(offset), id, b);
return entry;
}
VTableSource::VTableSource(VTableSlot slot, Nat id, code::Content *c) : RefSource(c), slot(slot), id(id) {}
Str *VTableSource::title() const {
StrBuf *out = new (this) StrBuf();
*out << S("vtable ") << slot << S(",") << id;
return out->toS();
}
}
|