mirror of
https://github.com/corda/corda.git
synced 2025-01-31 16:35:43 +00:00
progress on JIT compiler sketch
This commit is contained in:
parent
55b956916f
commit
5b5a4fe8d7
125
src/buffer.h
125
src/buffer.h
@ -1,125 +0,0 @@
|
|||||||
#ifndef BUFFER_H
|
|
||||||
#define BUFFER_H
|
|
||||||
|
|
||||||
#include "system.h"
|
|
||||||
|
|
||||||
namespace vm {
|
|
||||||
|
|
||||||
class Buffer {
|
|
||||||
public:
|
|
||||||
Buffer(System* s, unsigned minimumCapacity):
|
|
||||||
s(s),
|
|
||||||
data(0),
|
|
||||||
position(0),
|
|
||||||
capacity(0),
|
|
||||||
minimumCapacity(minimumCapacity)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~Buffer() {
|
|
||||||
if (data) {
|
|
||||||
s->free(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ensure(unsigned space) {
|
|
||||||
if (position + space > capacity) {
|
|
||||||
unsigned newCapacity = max
|
|
||||||
(position + space, max(minimumCapacity, capacity * 2));
|
|
||||||
uint8_t* newData = static_cast<uint8_t*>(s->allocate(newCapacity));
|
|
||||||
if (data) {
|
|
||||||
memcpy(newData, data, position);
|
|
||||||
s->free(data);
|
|
||||||
}
|
|
||||||
data = newData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(uint8_t v) {
|
|
||||||
ensure(1);
|
|
||||||
data[position++] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append2(uint16_t v) {
|
|
||||||
ensure(2);
|
|
||||||
memcpy(data + position, &v, 2);
|
|
||||||
position += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void append4(uint32_t v) {
|
|
||||||
ensure(4);
|
|
||||||
memcpy(data + position, &v, 4);
|
|
||||||
position += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
void appendAddress(uintptr_t v) {
|
|
||||||
append4(v);
|
|
||||||
if (BytesPerWord == 8) {
|
|
||||||
// we have to use the preprocessor here to avoid a warning on
|
|
||||||
// 32-bit systems
|
|
||||||
#ifdef __x86_64__
|
|
||||||
append4(v >> 32);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(void* p, unsigned size) {
|
|
||||||
ensure(size);
|
|
||||||
memcpy(data + position, p, size);
|
|
||||||
position += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set2(unsigned offset, uint32_t v) {
|
|
||||||
assert(s, offset + 2 <= position);
|
|
||||||
memcpy(data + offset, &v, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set4(unsigned offset, uint32_t v) {
|
|
||||||
assert(s, offset + 4 <= position);
|
|
||||||
memcpy(data + offset, &v, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t& get(unsigned offset) {
|
|
||||||
assert(s, offset + 1 <= position);
|
|
||||||
return data[offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t& get2(unsigned offset) {
|
|
||||||
assert(s, offset + 2 <= position);
|
|
||||||
return *reinterpret_cast<uint16_t*>(data + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t& get4(unsigned offset) {
|
|
||||||
assert(s, offset + 4 <= position);
|
|
||||||
return *reinterpret_cast<uint32_t*>(data + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t& getAddress(unsigned offset) {
|
|
||||||
assert(s, offset + 4 <= position);
|
|
||||||
return *reinterpret_cast<uintptr_t*>(data + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void get(unsigned offset, void* p, unsigned size) {
|
|
||||||
assert(s, offset + size <= position);
|
|
||||||
memcpy(p, data + offset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned length() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copyTo(void* b) {
|
|
||||||
if (data) {
|
|
||||||
memcpy(b, data, position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System* s;
|
|
||||||
uint8_t* data;
|
|
||||||
unsigned position;
|
|
||||||
unsigned capacity;
|
|
||||||
unsigned minimumCapacity;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace vm
|
|
||||||
|
|
||||||
#endif//BUFFER_H
|
|
716
src/compiler.cpp
716
src/compiler.cpp
@ -1,315 +1,793 @@
|
|||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
using namespace vm;
|
using namespace vm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class IpMapping {
|
||||||
|
public:
|
||||||
|
IpMapping(unsigned ip, unsigned offset): ip(ip), offset(offset) { }
|
||||||
|
|
||||||
|
const unsigned ip;
|
||||||
|
const unsigned offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
Context(System* s, void* indirectCaller):
|
||||||
|
s(s),
|
||||||
|
code(s, 1024),
|
||||||
|
virtualStack(s, BytesPerWord * 32),
|
||||||
|
operands(s, 8 * 1024),
|
||||||
|
ipTable(s, sizeof(IpMapping) * 512),
|
||||||
|
constantPool(s, BytesPerWord * 32),
|
||||||
|
registerPool(s, BytesPerWord * 8),
|
||||||
|
promises(s, 1024),
|
||||||
|
indirectCaller(reinterpret_cast<intptr_t>(indirectCaller))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
promises.dispose();
|
||||||
|
constantPool.dispose();
|
||||||
|
registerPool.dispose();
|
||||||
|
ipTable.dispose();
|
||||||
|
operands.dispose();
|
||||||
|
virtualStack.dispose();
|
||||||
|
code.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
System* s;
|
||||||
|
Vector code;
|
||||||
|
Vector<MyOperand*> virtualStack;
|
||||||
|
Vector operands;
|
||||||
|
Vector<IpMapping> ipTable;
|
||||||
|
Vector<MyOperand*> constantPool;
|
||||||
|
Vector<MyOperand*> registerPool;
|
||||||
|
Vector promises;
|
||||||
|
intptr_t indirectCaller;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void NO_RETURN
|
||||||
|
abort(Context* c)
|
||||||
|
{
|
||||||
|
abort(c->s);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
inline void
|
||||||
|
assert(Context* c, bool v)
|
||||||
|
{
|
||||||
|
assert(c->s, v);
|
||||||
|
}
|
||||||
|
#endif // not NDEBUG
|
||||||
|
|
||||||
|
inline void
|
||||||
|
expect(Context* c, bool v)
|
||||||
|
{
|
||||||
|
expect(c->system, v);
|
||||||
|
}
|
||||||
|
|
||||||
class MyPromise: public Promise {
|
class MyPromise: public Promise {
|
||||||
public:
|
public:
|
||||||
MyPromise(int value): resolved(false), value_(value) { }
|
enum PromiseType {
|
||||||
|
PoolPromiseType,
|
||||||
|
CodePromiseType,
|
||||||
|
IpPromiseType
|
||||||
|
};
|
||||||
|
|
||||||
|
MyPromise(intptr_t value): resolved(false), value_(value) { }
|
||||||
|
|
||||||
virtual unsigned value(System* s) {
|
virtual unsigned value(System* s) {
|
||||||
assert(s, resolved);
|
assert(s, resolved);
|
||||||
return value_;
|
return value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual PromiseType type() = 0;
|
||||||
|
|
||||||
bool resolved;
|
bool resolved;
|
||||||
int value_;
|
intptr_t value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PoolPromise: public MyPromise {
|
||||||
|
public:
|
||||||
|
PoolPromise(intptr_t value): MyPromise(value) { }
|
||||||
|
|
||||||
|
virtual PromiseType type() {
|
||||||
|
return PoolPromiseType;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CodePromise: public MyPromise {
|
||||||
|
public:
|
||||||
|
PoolPromise(intptr_t value): MyPromise(value) { }
|
||||||
|
|
||||||
|
virtual PromiseType type() {
|
||||||
|
return CodePromiseType;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IpPromise: public MyPromise {
|
||||||
|
public:
|
||||||
|
PoolPromise(intptr_t value): MyPromise(value) { }
|
||||||
|
|
||||||
|
virtual PromiseType type() {
|
||||||
|
return IpPromiseType;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MyOperand: public Operand {
|
||||||
|
public:
|
||||||
|
enum OperandType {
|
||||||
|
ImmediateOperandType,
|
||||||
|
RegisterOperandType,
|
||||||
|
MemoryOperandType
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~MyOperand() { }
|
||||||
|
|
||||||
|
virtual OperandType type() = 0;
|
||||||
|
|
||||||
|
virtual unsigned footprint() {
|
||||||
|
return BytesPerWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned size() = 0;
|
||||||
|
|
||||||
|
virtual void push(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void mov(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void cmp(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void jl(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void jg(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void jle(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void jge(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void je(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void jne(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void jmp(Context* c) { abort(c); }
|
||||||
|
|
||||||
|
virtual void add(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void sub(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void mul(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void div(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void rem(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void shl(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void shr(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void ushr(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void and_(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void or_(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void xor_(Context* c, MyOperand*) { abort(c); }
|
||||||
|
|
||||||
|
virtual void neg(Context* c) { abort(c); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ImmediateOperand: public MyOperand {
|
||||||
|
public:
|
||||||
|
ImmediateOperand(intptr_t value):
|
||||||
|
value(value)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual OperandType type() {
|
||||||
|
return ImmediateOperandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned size() {
|
||||||
|
return sizeof(ImmediateOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void push(Context* c) {
|
||||||
|
if (isInt8(value)) {
|
||||||
|
c->code.append(0x6a);
|
||||||
|
c->code.append(value);
|
||||||
|
} else if (isInt32(value)) {
|
||||||
|
c->code.append(0x68);
|
||||||
|
c->code.append4(value);
|
||||||
|
} else {
|
||||||
|
RegisterOperand* tmp = temporary(c);
|
||||||
|
mov(c, tmp);
|
||||||
|
tmp->push(c);
|
||||||
|
release(c, tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mov(Context* c, MyOperand* dst) {
|
||||||
|
switch (dst->type()) {
|
||||||
|
case RegisterOperandType:
|
||||||
|
rex(c);
|
||||||
|
c->code.append(0xb8 | registerValue(c, dst));
|
||||||
|
c->code.appendAddress(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MemoryOperandType:
|
||||||
|
rex(c);
|
||||||
|
encode(c, 0xc7, 0, 0x40, 0x80, rax,
|
||||||
|
asRegister(memoryBase(c, dst)),
|
||||||
|
memoryDisplacement(c, dst));
|
||||||
|
c->code.append4(v);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: abort(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intptr_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AbsoluteOperand: public MyOperand {
|
||||||
|
public:
|
||||||
|
AbsoluteOperand(Promise* value):
|
||||||
|
value(value)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual OperandType type() {
|
||||||
|
return AbsoluteOperandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned size() {
|
||||||
|
return sizeof(AbsoluteOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise* value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RegisterOperand: public MyOperand {
|
||||||
|
public:
|
||||||
|
RegisterOperand(Register value):
|
||||||
|
value(value)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual OperandType type() {
|
||||||
|
return RegisterOperandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned size() {
|
||||||
|
return sizeof(RegisterOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void push(Context* c) {
|
||||||
|
c->code.append(0x50 | value);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mov(Context* c, MyOperand* dst) {
|
||||||
|
switch (dst->type()) {
|
||||||
|
case RegisterOperandType:
|
||||||
|
if (value != registerValue(c, dst)) {
|
||||||
|
rex(c);
|
||||||
|
c->code.append(0x89);
|
||||||
|
c->code.append(0xc0 | (value << 3) | registerValue(c, dst));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MemoryOperandType:
|
||||||
|
rex(c);
|
||||||
|
encode(c, 0x89, 0, 0x40, 0x80, src,
|
||||||
|
asRegister(memoryBase(c, dst)),
|
||||||
|
memoryDisplacement(c, dst));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: abort(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Register value;
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterOperand*
|
||||||
|
temporary(Context* c)
|
||||||
|
{
|
||||||
|
return c->registerPool.pop<RegisterOperand*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
release(Context* c, RegisterOperand* v)
|
||||||
|
{
|
||||||
|
return c->registerPool.push(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
encode(Context* c, uint8_t instruction, uint8_t zeroPrefix,
|
||||||
|
uint8_t bytePrefix, uint8_t wordPrefix,
|
||||||
|
Register a, Register b, int32_t offset)
|
||||||
|
{
|
||||||
|
c->code.append(instruction);
|
||||||
|
|
||||||
|
uint8_t prefix;
|
||||||
|
if (offset == 0 and b != rbp) {
|
||||||
|
prefix = zeroPrefix;
|
||||||
|
} else if (isByte(offset)) {
|
||||||
|
prefix = bytePrefix;
|
||||||
|
} else {
|
||||||
|
prefix = wordPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->code.append(prefix | (a << 3) | b);
|
||||||
|
|
||||||
|
if (b == rsp) {
|
||||||
|
c->code.append(0x24);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset == 0 and b != rbp) {
|
||||||
|
// do nothing
|
||||||
|
} else if (isInt8(offset)) {
|
||||||
|
c->code.append(offset);
|
||||||
|
} else {
|
||||||
|
c->code.append4(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Register
|
||||||
|
asRegister(Context* c, MyOperand* v)
|
||||||
|
{
|
||||||
|
if (v->type() == RegisterOperandType) {
|
||||||
|
return registerValue(v);
|
||||||
|
} else {
|
||||||
|
assert(c, v->type() == MemoryOperandType);
|
||||||
|
|
||||||
|
RegisterOperand* tmp = temporary(c);
|
||||||
|
v->mov(c, tmp);
|
||||||
|
Register r = tmp->value;
|
||||||
|
release(c, tmp);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemoryOperand: public MyOperand {
|
||||||
|
public:
|
||||||
|
MemoryOperand(MyOperand* base, int displacement, MyOperand* index,
|
||||||
|
unsigned scale):
|
||||||
|
base(base),
|
||||||
|
displacement(displacement),
|
||||||
|
index(index),
|
||||||
|
scale(scale)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual OperandType type() {
|
||||||
|
return MemoryOperandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned size() {
|
||||||
|
return sizeof(MemoryOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isStackReference() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void push(Context* c) {
|
||||||
|
assert(c, index == 0);
|
||||||
|
assert(c, scale == 0);
|
||||||
|
|
||||||
|
encode(c, 0xff, 0x30, 0x70, 0xb0, rax, asRegister(c, base), displacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mov(Context* c, MyOperand* dst) {
|
||||||
|
switch (dst->type()) {
|
||||||
|
case RegisterOperandType:
|
||||||
|
rex(c);
|
||||||
|
encode(c, 0x8b, 0, 0x40, 0x80, registerValue(c, dst),
|
||||||
|
base, displacement);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MemoryOperandType: {
|
||||||
|
RegisterOperand* tmp = temporary(c);
|
||||||
|
mov(c, tmp);
|
||||||
|
tmp->mov(c, dst);
|
||||||
|
release(c, tmp);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: abort(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyOperand* base;
|
||||||
|
int displacement;
|
||||||
|
MyOperand* index;
|
||||||
|
unsigned scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StackOperand: public MemoryOperand {
|
||||||
|
public:
|
||||||
|
StackOperand(MyOperand* base, int displacement):
|
||||||
|
MemoryOperand(base, displacement, 0, 1)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual unsigned size() {
|
||||||
|
return sizeof(StackOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isStackReference() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SelectionOperand: public MyOperand {
|
||||||
|
public:
|
||||||
|
SelectionOperand(Compiler::SelectionType type, MyOperand* base):
|
||||||
|
type(type), base(base)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual OperandType type() {
|
||||||
|
return SelectionOperandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned footprint() {
|
||||||
|
if (type == Compiler::S8Selection) {
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual unsigned size() {
|
||||||
|
return sizeof(SelectionOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
Compiler::SelectionType type;
|
||||||
|
MyOperand* base;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImmediateOperand*
|
||||||
|
immediate(Context* c, intptr_t v)
|
||||||
|
{
|
||||||
|
return c->operands.push(ImmediateOperand(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
AbsoluteOperand*
|
||||||
|
absolute(Context* c, intptr_t v)
|
||||||
|
{
|
||||||
|
return c->operands.push(AbsoluteOperand(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterOperand*
|
||||||
|
register_(Context* c, Register v)
|
||||||
|
{
|
||||||
|
return c->operands.push(RegisterOperand(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryOperand*
|
||||||
|
memory(Context* c, MyOperand* base, int displacement,
|
||||||
|
MyOperand* index, unsigned scale)
|
||||||
|
{
|
||||||
|
return c->operands.push(MemoryOperand(base, displacement, index, scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
StackOperand*
|
||||||
|
stack(Context* c, int displacement)
|
||||||
|
{
|
||||||
|
return c->operands.push(StackOperand(register_(c, rbp), displacement));
|
||||||
|
}
|
||||||
|
|
||||||
|
MyOperand*
|
||||||
|
selection(Context* c, Compiler::SelectionType type, MyOperand* base)
|
||||||
|
{
|
||||||
|
if ((type == S4Selection and BytesPerWord == 4)
|
||||||
|
or (type == S8Selection and BytesPerWord == 8))
|
||||||
|
{
|
||||||
|
return base;
|
||||||
|
} else {
|
||||||
|
return c->operands.push(SelectionOperand(type, base));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isStackReference(Context* c, MyOperand* v)
|
||||||
|
{
|
||||||
|
return v->type() == MemoryOperandType
|
||||||
|
and static_cast<MemoryOperand*>(v)->isStackReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
flushStack(Context* c)
|
||||||
|
{
|
||||||
|
Stack newVirtualStack;
|
||||||
|
for (unsigned i = 0; i < c->virtualStack.length();) {
|
||||||
|
MyOperand* v = c->virtualStack.peek<MyOperand*>(i);
|
||||||
|
|
||||||
|
if (not isStackReference(c, v)) {
|
||||||
|
v->push(c);
|
||||||
|
|
||||||
|
if (v->footprint() / BytesPerWord == 2) {
|
||||||
|
newVirtualStack.push(stack(c, c->stackIndex + 4));
|
||||||
|
} else {
|
||||||
|
newVirtualStack.push(stack(c, c->stackIndex));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newVirtualStack.push(v, v->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
i += v->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
c->virtualStack.swap(&newVirtualStack);
|
||||||
|
}
|
||||||
|
|
||||||
class MyCompiler: public Compiler {
|
class MyCompiler: public Compiler {
|
||||||
public:
|
public:
|
||||||
MyCompiler(System* s, void* indirectCaller):
|
MyCompiler(System* s, void* indirectCaller):
|
||||||
s(s), indirectCaller(reinterpret_cast<intptr_t>(indirectCaller))
|
c(s, indirectCaller)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Promise* poolOffset() {
|
virtual Promise* poolOffset() {
|
||||||
return promises.push(PoolPromise(constantPool.length() / BytesPerWord));
|
return c.promises.push(PoolPromise(constantPool.length() / BytesPerWord));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Promise* codeOffset() {
|
virtual Promise* codeOffset() {
|
||||||
return promises.push(CodePromise(code.length()));
|
return c.promises.push(CodePromise(code.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* poolAppend(Operand* v) {
|
virtual Operand* poolAppend(Operand* v) {
|
||||||
Operand* r = operands.push
|
Operand* r = absolute(&c, poolOffset());
|
||||||
(PoolEntry(constantPool.length() / BytesPerWord));
|
constantPool.push(static_cast<MyOperand*>(v));
|
||||||
constantPool.push(v);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* constant(intptr_t v) {
|
virtual Operand* constant(intptr_t v) {
|
||||||
return operands.push(Constant(v));
|
return immediate(&c, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void push(Operand* v) {
|
virtual void push(Operand* v) {
|
||||||
stack_.push(v);
|
c.virtualStack.push(static_cast<MyOperand*>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void push2(Operand* v) {
|
virtual void push2(Operand* v) {
|
||||||
stack_.push(v);
|
push(v);
|
||||||
stack_.push(0);
|
if (BytesPerWord == 8) push(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* stack(unsigned index) {
|
virtual Operand* stack(unsigned index) {
|
||||||
return stack_.peek(stack.size() - index - 1);
|
return c.virtualStack.peek(stack.size() - index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* stack2(unsigned index) {
|
virtual Operand* stack2(unsigned index) {
|
||||||
return stack_.peek(stack.size() - index - 1);
|
return c.virtualStack.peek(stack.size() - index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* pop() {
|
virtual Operand* pop() {
|
||||||
return stack_.pop();
|
return pop(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* pop2() {
|
virtual Operand* pop2() {
|
||||||
stack_.pop();
|
if (BytesPerWord == 8) pop();
|
||||||
return stack_.pop();
|
return pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void pop(Operand* dst) {
|
virtual void pop(Operand* dst) {
|
||||||
mov(stack_.pop(), dst);
|
pop(c)->mov(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void pop2(Operand* dst) {
|
virtual void pop2(Operand* dst) {
|
||||||
stack_.pop();
|
if (BytesPerWord == 8) pop();
|
||||||
mov(stack_.pop(), dst);
|
pop(dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* stack() {
|
virtual Operand* stack() {
|
||||||
flushStack();
|
flushStack(&c);
|
||||||
return operands.push(Register(rsp));
|
return register_(&c, rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* base() {
|
virtual Operand* base() {
|
||||||
return operands.push(Register(rbp));
|
return register_(&c, rbp);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* thread() {
|
virtual Operand* thread() {
|
||||||
return operands.push(Register(rbx));
|
return register_(&c, rbx);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* indirectTarget() {
|
virtual Operand* indirectTarget() {
|
||||||
return operands.push(Register(rax));
|
return register_(&c, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* temporary() {
|
virtual Operand* temporary() {
|
||||||
return registerPool.pop();
|
return ::temporary(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void release(Operand* v) {
|
virtual void release(Operand* v) {
|
||||||
return registerPool.push(v);
|
assert(&c, static_cast<MyOperand>(v)->type() == RegisterOperandType);
|
||||||
|
return ::release(&c, static_cast<RegisterOperand*>(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* label() {
|
virtual Operand* label() {
|
||||||
return operands.push(Label());
|
return absolute(&c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void mark(Operand* label) {
|
virtual void mark(Operand* label) {
|
||||||
setLabelValue(s, label, codeOffset());
|
setAbsoluteValue(&c, static_cast<MyOperand*>(label), codeOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* call(Operand* v) {
|
virtual Operand* call(Operand* v) {
|
||||||
flushStack();
|
flushStack(&c);
|
||||||
static_cast<MyOperand*>(v)->call(a);
|
static_cast<MyOperand*>(v)->call(&c);
|
||||||
return operands.push(Register(rax));
|
return register_(&c, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* alignedCall(Operand* v) {
|
virtual Operand* alignedCall(Operand* v) {
|
||||||
flushStack();
|
flushStack(&c);
|
||||||
static_cast<MyOperand*>(v)->alignedCall(a);
|
static_cast<MyOperand*>(v)->alignedCall(&c);
|
||||||
return operands.push(Register(rax));
|
return register_(&c, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* indirectCall
|
virtual Operand* indirectCall
|
||||||
(Operand* address, unsigned argumentCount, ...)
|
(Operand* address, unsigned argumentCount, ...)
|
||||||
{
|
{
|
||||||
va_list a; va_start(a, argumentCount);
|
va_list a; va_start(a, argumentCount);
|
||||||
pushArguments(argumentCount, a);
|
pushArguments(&c, argumentCount, a);
|
||||||
va_end(a);
|
va_end(a);
|
||||||
|
|
||||||
mov(address, operands.push(Register(rax)));
|
static_cast<MyOperand*>(address)->mov(&c, register_(rax));
|
||||||
constant(indirectCaller)->call(a);
|
immediate(&c, indirectCaller)->call(&c);
|
||||||
|
|
||||||
popArguments(argumentCount);
|
popArguments(&c, argumentCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* indirectCallNoReturn
|
virtual Operand* indirectCallNoReturn
|
||||||
(Operand* address, unsigned argumentCount, ...)
|
(Operand* address, unsigned argumentCount, ...)
|
||||||
{
|
{
|
||||||
va_list a; va_start(a, argumentCount);
|
va_list a; va_start(a, argumentCount);
|
||||||
pushArguments(argumentCount, a);
|
pushArguments(&c, argumentCount, a);
|
||||||
va_end(a);
|
va_end(a);
|
||||||
|
|
||||||
mov(address, operands.push(Register(rax)));
|
static_cast<MyOperand*>(address)->mov(&c, register_(rax));
|
||||||
constant(indirectCaller)->call(a);
|
immediate(&c, indirectCaller)->call(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* directCall
|
virtual Operand* directCall
|
||||||
(Operand* address, unsigned argumentCount, ...)
|
(Operand* address, unsigned argumentCount, ...)
|
||||||
{
|
{
|
||||||
va_list a; va_start(a, argumentCount);
|
va_list a; va_start(a, argumentCount);
|
||||||
pushArguments(argumentCount, a);
|
pushArguments(&c, argumentCount, a);
|
||||||
va_end(a);
|
va_end(a);
|
||||||
|
|
||||||
static_cast<MyOperand*>(address)->call(a);
|
static_cast<MyOperand*>(address)->call(&c);
|
||||||
|
|
||||||
popArguments(argumentCount);
|
popArguments(&c, argumentCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void return_(Operand* v) {
|
virtual void return_(Operand* v) {
|
||||||
mov(v, operands.push(Register(rax)));
|
static_cast<MyOperand*>(v)->mov(&c, register_(rax));
|
||||||
a->ret();
|
ret(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void ret() {
|
virtual void ret() {
|
||||||
a->ret();
|
ret(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void mov(Operand* src, Operand* dst) {
|
virtual void mov(Operand* src, Operand* dst) {
|
||||||
static_cast<MyOperand>(src)->mov(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(src)->mov(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void cmp(Operand* subtrahend, Operand* minuend) {
|
virtual void cmp(Operand* subtrahend, Operand* minuend) {
|
||||||
static_cast<MyOperand>(subtrahend)->mov
|
static_cast<MyOperand*>(subtrahend)->mov
|
||||||
(a, static_cast<MyOperand>(minuend));
|
(&c, static_cast<MyOperand*>(minuend));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void jl(Operand* v) {
|
virtual void jl(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->jl(a);
|
static_cast<MyOperand*>(v)->jl(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void jg(Operand* v) {
|
virtual void jg(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->jg(a);
|
static_cast<MyOperand*>(v)->jg(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void jle(Operand* v) {
|
virtual void jle(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->jle(a);
|
static_cast<MyOperand*>(v)->jle(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void jge(Operand* v) {
|
virtual void jge(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->jge(a);
|
static_cast<MyOperand*>(v)->jge(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void je(Operand* v) {
|
virtual void je(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->je(a);
|
static_cast<MyOperand*>(v)->je(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void jne(Operand* v) {
|
virtual void jne(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->jne(a);
|
static_cast<MyOperand*>(v)->jne(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void jmp(Operand* v) {
|
virtual void jmp(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->jmp(a);
|
static_cast<MyOperand*>(v)->jmp(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void add(Operand* v, Operand* dst) {
|
virtual void add(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->add(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->add(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void sub(Operand* v, Operand* dst) {
|
virtual void sub(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->sub(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->sub(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void mul(Operand* v, Operand* dst) {
|
virtual void mul(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->mul(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->mul(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void div(Operand* v, Operand* dst) {
|
virtual void div(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->div(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->div(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void rem(Operand* v, Operand* dst) {
|
virtual void rem(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->rem(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->rem(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void shl(Operand* v, Operand* dst) {
|
virtual void shl(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->shl(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->shl(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void shr(Operand* v, Operand* dst) {
|
virtual void shr(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->shr(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->shr(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void ushr(Operand* v, Operand* dst) {
|
virtual void ushr(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->ushr(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->ushr(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void and_(Operand* v, Operand* dst) {
|
virtual void and_(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->and_(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->and_(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void or_(Operand* v, Operand* dst) {
|
virtual void or_(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->or_(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->or_(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void xor_(Operand* v, Operand* dst) {
|
virtual void xor_(Operand* v, Operand* dst) {
|
||||||
static_cast<MyOperand>(v)->xor_(a, static_cast<MyOperand>(dst));
|
static_cast<MyOperand*>(v)->xor_(&c, static_cast<MyOperand*>(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void neg(Operand* v) {
|
virtual void neg(Operand* v) {
|
||||||
static_cast<MyOperand>(v)->neg(a);
|
static_cast<MyOperand*>(v)->neg(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* memory(Operand* base) {
|
virtual Operand* memory(Operand* base, int displacement,
|
||||||
return operands.push(Memory(base, 0, 0, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Operand* memory(Operand* base, unsigned displacement) {
|
|
||||||
return operands.push(Memory(base, displacement, 0, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Operand* memory(Operand* base, unsigned displacement,
|
|
||||||
Operand* index, unsigned scale)
|
Operand* index, unsigned scale)
|
||||||
{
|
{
|
||||||
return operands.push(Memory(base, displacement, index, scale));
|
return memory(&c, base, displacement, index, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* select1(Operand* v) {
|
virtual Operand* select(SelectionType type, Operand* v) {
|
||||||
return operands.push(Selection(S1Selection, v));
|
return selection(&c, type, v);
|
||||||
}
|
|
||||||
|
|
||||||
virtual Operand* select2(Operand* v) {
|
|
||||||
return operands.push(Selection(S2Selection, v));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Operand* select2z(Operand* v) {
|
|
||||||
return operands.push(Selection(Z2Selection, v));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Operand* select4(Operand* v) {
|
|
||||||
return operands.push(Selection(S4Selection, v));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Operand* select8(Operand* v) {
|
|
||||||
return operands.push(Selection(S8Selection, v));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void prologue() {
|
virtual void prologue() {
|
||||||
a->push(rbp);
|
register_(&c, rbp)->push(&c);
|
||||||
a->mov(rsp, rbp);
|
register_(&c, rsp)->mov(&c, register_(&c, rbp));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void epilogue() {
|
virtual void epilogue() {
|
||||||
a->mov(rbp, rsp);
|
register_(&c, rbp)->mov(&c, register_(&c, rsp));
|
||||||
a->pop(rbp);
|
register_(&c, rbp)->pop(&c);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void startLogicalIp(unsigned v) {
|
virtual void startLogicalIp(unsigned ip) {
|
||||||
ipTable.append(IpMapping(v, code.length()));
|
c.ipTable.push(IpMapping(ip, code.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* logicalIp(unsigned v) {
|
virtual Operand* logicalIp(unsigned ip) {
|
||||||
return operands.push(Label(promises.push(IpPromise(v))));
|
return absolute(&c, promises.push(IpPromise(ip)));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual unsigned logicalIpToOffset(unsigned ip) {
|
virtual unsigned logicalIpToOffset(unsigned ip) {
|
||||||
unsigned bottom = 0;
|
unsigned bottom = 0;
|
||||||
unsigned top = ipTable.size();
|
unsigned top = c.ipTable.size();
|
||||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||||
unsigned middle = bottom + (span / 2);
|
unsigned middle = bottom + (span / 2);
|
||||||
IpMapping* mapping = ipTable.get(middle);
|
IpMapping* mapping = c.ipTable.get(middle);
|
||||||
|
|
||||||
if (ip == mapping->ip) {
|
if (ip == mapping->ip) {
|
||||||
return mapping->offset;
|
return mapping->offset;
|
||||||
@ -324,34 +802,24 @@ class MyCompiler: public Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual unsigned size() {
|
virtual unsigned size() {
|
||||||
return code.length();
|
return c.code.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void writeTo(void* out) {
|
virtual void writeTo(void* out) {
|
||||||
// todo
|
// todo
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateCall(void* returnAddress, void* newTarget);
|
virtual void updateCall(void* returnAddress, void* newTarget) {
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
promises.dispose();
|
c.dispose();
|
||||||
constantPool.dispose();
|
|
||||||
registerPool.dispose();
|
|
||||||
ipTable.dispose();
|
|
||||||
operands.dispose();
|
|
||||||
code.dispose();
|
|
||||||
|
|
||||||
s->free(this);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
Context c;
|
||||||
Stack code;
|
|
||||||
Stack operands;
|
|
||||||
Stack ipTable;
|
|
||||||
Stack constantPool;
|
|
||||||
Stack registerPool;
|
|
||||||
Stack promises;
|
|
||||||
intptr_t indirectCaller;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -11,11 +11,19 @@ class Promise {
|
|||||||
public:
|
public:
|
||||||
virtual ~Promise() { }
|
virtual ~Promise() { }
|
||||||
|
|
||||||
virtual unsigned value() = 0;
|
virtual unsigned value(System* s) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Compiler {
|
class Compiler {
|
||||||
public:
|
public:
|
||||||
|
enum SelectionType {
|
||||||
|
S1Selection,
|
||||||
|
S2Selection,
|
||||||
|
Z2Selection,
|
||||||
|
S4Selection,
|
||||||
|
S8Selection
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~Compiler() { }
|
virtual ~Compiler() { }
|
||||||
|
|
||||||
virtual Promise* poolOffset() = 0;
|
virtual Promise* poolOffset() = 0;
|
||||||
@ -78,16 +86,10 @@ class Compiler {
|
|||||||
virtual void xor_(Operand* v, Operand* dst) = 0;
|
virtual void xor_(Operand* v, Operand* dst) = 0;
|
||||||
virtual void neg(Operand*) = 0;
|
virtual void neg(Operand*) = 0;
|
||||||
|
|
||||||
virtual Operand* memory(Operand* base) = 0;
|
virtual Operand* memory(Operand* base, int displacement = 0,
|
||||||
virtual Operand* memory(Operand* base, unsigned displacement) = 0;
|
Operand* index = 0, unsigned scale = 1) = 0;
|
||||||
virtual Operand* memory(Operand* base, unsigned displacement,
|
|
||||||
Operand* index, unsigned scale) = 0;
|
|
||||||
|
|
||||||
virtual Operand* select1(Operand*) = 0;
|
virtual Operand* select(SelectionType, Operand*) = 0;
|
||||||
virtual Operand* select2(Operand*) = 0;
|
|
||||||
virtual Operand* select2z(Operand*) = 0;
|
|
||||||
virtual Operand* select4(Operand*) = 0;
|
|
||||||
virtual Operand* select8(Operand*) = 0;
|
|
||||||
|
|
||||||
virtual void prologue() = 0;
|
virtual void prologue() = 0;
|
||||||
virtual void epilogue() = 0;
|
virtual void epilogue() = 0;
|
||||||
|
103
src/vector.h
Normal file
103
src/vector.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#ifndef VECTOR_H
|
||||||
|
#define VECTOR_H
|
||||||
|
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
namespace vm {
|
||||||
|
|
||||||
|
template <class T = uint8_t>
|
||||||
|
class Vector {
|
||||||
|
public:
|
||||||
|
Vector(System* s, unsigned minimumCapacity):
|
||||||
|
s(s),
|
||||||
|
data(0),
|
||||||
|
position(0),
|
||||||
|
capacity(0),
|
||||||
|
minimumCapacity(minimumCapacity)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~Vector() {
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
if (data) {
|
||||||
|
s->free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensure(unsigned space) {
|
||||||
|
if (position + space > capacity) {
|
||||||
|
unsigned newCapacity = max
|
||||||
|
(position + space, max(minimumCapacity, capacity * 2));
|
||||||
|
uint8_t* newData = static_cast<uint8_t*>(s->allocate(newCapacity));
|
||||||
|
if (data) {
|
||||||
|
memcpy(newData, data, position);
|
||||||
|
s->free(data);
|
||||||
|
}
|
||||||
|
data = newData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void get(unsigned offset, void* dst, unsigned size) {
|
||||||
|
assert(s, offset >= 0);
|
||||||
|
assert(s, offset + size <= position);
|
||||||
|
mempcy(dst, data + offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(unsigned offset, const void* src, unsigned size) {
|
||||||
|
assert(s, offset >= 0);
|
||||||
|
assert(s, offset + size <= position);
|
||||||
|
mempcy(data + offset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop(void* dst, unsigned size) {
|
||||||
|
get(position - size, dst, size);
|
||||||
|
position -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* append(const void* p, unsigned size) {
|
||||||
|
ensure(size);
|
||||||
|
void* r = data + position;
|
||||||
|
memcpy(r, p, size);
|
||||||
|
position += size;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(uint8_t v) {
|
||||||
|
append(&v, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append2(uint16_t v) {
|
||||||
|
append(&v, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append4(uint32_t v) {
|
||||||
|
append(&v, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void appendAddress(uintptr_t v) {
|
||||||
|
append(&v, BytesPerWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class C = T>
|
||||||
|
C* push(const C& v) {
|
||||||
|
return static_cast<C*>(append(&v, sizeof(C)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class C = T>
|
||||||
|
C pop() {
|
||||||
|
C r; pop(&r, sizeof(C));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
System* s;
|
||||||
|
uint8_t* data;
|
||||||
|
unsigned position;
|
||||||
|
unsigned capacity;
|
||||||
|
unsigned minimumCapacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vm
|
||||||
|
|
||||||
|
#endif//VECTOR_H
|
Loading…
x
Reference in New Issue
Block a user