- implement emitter functions for LKP_R, META, CLSS, LO, LO_R, LP, LP_R, SO, SO_R, SP, SP_R

- add emit code for throwing exceptions on null pointers
This commit is contained in:
Magnus Norddahl 2018-08-31 06:57:30 +02:00
parent 999b3833ff
commit ccd2f58fb4

View file

@ -34,7 +34,6 @@
#define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS) #define ASSERTKS(x) assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS)
// [pbeta] TODO: VM aborts // [pbeta] TODO: VM aborts
#define NULL_POINTER_CHECK(a,o,x)
#define BINARY_OP_INT(op,out,r,l) \ #define BINARY_OP_INT(op,out,r,l) \
{ \ { \
auto tmp = cc.newInt32(); \ auto tmp = cc.newInt32(); \
@ -145,10 +144,10 @@ private:
EMIT_OP(LK_R); EMIT_OP(LK_R);
EMIT_OP(LKF_R); EMIT_OP(LKF_R);
// EMIT_OP(LKS_R); // EMIT_OP(LKS_R);
// EMIT_OP(LKP_R); EMIT_OP(LKP_R);
// EMIT_OP(LFP); // EMIT_OP(LFP);
// EMIT_OP(META); EMIT_OP(META);
// EMIT_OP(CLSS); EMIT_OP(CLSS);
EMIT_OP(LB); EMIT_OP(LB);
EMIT_OP(LB_R); EMIT_OP(LB_R);
EMIT_OP(LH); EMIT_OP(LH);
@ -165,10 +164,10 @@ private:
EMIT_OP(LDP_R); EMIT_OP(LDP_R);
// EMIT_OP(LS); // EMIT_OP(LS);
// EMIT_OP(LS_R); // EMIT_OP(LS_R);
// EMIT_OP(LO); EMIT_OP(LO);
// EMIT_OP(LO_R); EMIT_OP(LO_R);
// EMIT_OP(LP); EMIT_OP(LP);
// EMIT_OP(LP_R); EMIT_OP(LP_R);
EMIT_OP(LV2); EMIT_OP(LV2);
EMIT_OP(LV2_R); EMIT_OP(LV2_R);
EMIT_OP(LV3); EMIT_OP(LV3);
@ -188,10 +187,10 @@ private:
EMIT_OP(SDP_R); EMIT_OP(SDP_R);
//EMIT_OP(SS); //EMIT_OP(SS);
//EMIT_OP(SS_R); //EMIT_OP(SS_R);
//EMIT_OP(SO); EMIT_OP(SO);
//EMIT_OP(SO_R); EMIT_OP(SO_R);
//EMIT_OP(SP); EMIT_OP(SP);
//EMIT_OP(SP_R); EMIT_OP(SP_R);
EMIT_OP(SV2); EMIT_OP(SV2);
EMIT_OP(SV2_R); EMIT_OP(SV2_R);
EMIT_OP(SV3); EMIT_OP(SV3);
@ -386,122 +385,146 @@ private:
void EmitLK_R() void EmitLK_R()
{ {
cc.mov(regD[a], asmjit::x86::ptr(ToMemAddress(konstd), regD[B], 2, C * 4)); cc.mov(regD[a], asmjit::x86::ptr(ToMemAddress(konstd), regD[B], 2, C * sizeof(int32_t)));
} }
void EmitLKF_R() void EmitLKF_R()
{ {
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, ToMemAddress(konstf + BC)); cc.mov(tmp, ToMemAddress(konstf + BC));
cc.movsd(regF[a], asmjit::x86::qword_ptr(tmp, regD[B], 3, C * 8)); cc.movsd(regF[a], asmjit::x86::qword_ptr(tmp, regD[B], 3, C * sizeof(double)));
} }
/*void EmitLKS_R() // load string constant indexed //void EmitLKS_R() { } // load string constant indexed
void EmitLKP_R()
{ {
//cc.mov(regS[a], konsts[regD[B] + C]); cc.mov(regA[a], asmjit::x86::ptr(ToMemAddress(konsta), regD[B], 2, C * sizeof(void*)));
} }
void EmitLKP_R() // load pointer constant indexed /*void EmitLFP() // load frame pointer
{
//cc.mov(b, regD[B] + C);
//cc.mov(regA[a], konsta[b].v);
}
void EmitLFP() // load frame pointer
{
}
void EmitMETA() // load a class's meta data address
{
}
void EmitCLSS() // load a class's descriptor address
{ {
}*/ }*/
void EmitMETA()
{
typedef void*(*FuncPtr)(void*);
auto label = cc.newLabel();
cc.test(regA[B], regA[B]);
cc.jne(label);
EmitThrowException(X_READ_NIL);
cc.bind(label);
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *o) -> void*
{
return static_cast<DObject*>(o)->GetClass();
}))), asmjit::FuncSignature1<void*, void*>());
call->setRet(0, regA[a]);
call->setArg(0, regA[B]);
}
void EmitCLSS()
{
typedef void*(*FuncPtr)(void*);
auto label = cc.newLabel();
cc.test(regA[B], regA[B]);
cc.jne(label);
EmitThrowException(X_READ_NIL);
cc.bind(label);
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *o) -> void*
{
return static_cast<DObject*>(o)->GetClass()->Meta;
}))), asmjit::FuncSignature1<void*, void*>());
call->setRet(0, regA[a]);
call->setArg(0, regA[B]);
}
// Load from memory. rA = *(rB + rkC) // Load from memory. rA = *(rB + rkC)
void EmitLB() void EmitLB()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movsx(regD[a], asmjit::x86::byte_ptr(PB, KC)); cc.movsx(regD[a], asmjit::x86::byte_ptr(PB, KC));
} }
void EmitLB_R() void EmitLB_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movsx(regD[a], asmjit::x86::byte_ptr(PB, RC)); cc.movsx(regD[a], asmjit::x86::byte_ptr(PB, RC));
} }
void EmitLH() void EmitLH()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movsx(regD[a], asmjit::x86::word_ptr(PB, KC)); cc.movsx(regD[a], asmjit::x86::word_ptr(PB, KC));
} }
void EmitLH_R() void EmitLH_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movsx(regD[a], asmjit::x86::word_ptr(PB, RC)); cc.movsx(regD[a], asmjit::x86::word_ptr(PB, RC));
} }
void EmitLW() void EmitLW()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regD[a], asmjit::x86::dword_ptr(PB, KC)); cc.mov(regD[a], asmjit::x86::dword_ptr(PB, KC));
} }
void EmitLW_R() void EmitLW_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regD[a], asmjit::x86::dword_ptr(PB, RC)); cc.mov(regD[a], asmjit::x86::dword_ptr(PB, RC));
} }
void EmitLBU() void EmitLBU()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regD[a], asmjit::x86::byte_ptr(PB, KC)); cc.mov(regD[a], asmjit::x86::byte_ptr(PB, KC));
} }
void EmitLBU_R() void EmitLBU_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regD[a], asmjit::x86::byte_ptr(PB, RC)); cc.mov(regD[a], asmjit::x86::byte_ptr(PB, RC));
} }
void EmitLHU() void EmitLHU()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regD[a], asmjit::x86::word_ptr(PB, KC)); cc.mov(regD[a], asmjit::x86::word_ptr(PB, KC));
} }
void EmitLHU_R() void EmitLHU_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regD[a], asmjit::x86::word_ptr(PB, RC)); cc.mov(regD[a], asmjit::x86::word_ptr(PB, RC));
} }
void EmitLSP() void EmitLSP()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movss(regF[a], asmjit::x86::dword_ptr(PB, KC)); cc.movss(regF[a], asmjit::x86::dword_ptr(PB, KC));
} }
void EmitLSP_R() void EmitLSP_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movss(regF[a], asmjit::x86::dword_ptr(PB, RC)); cc.movss(regF[a], asmjit::x86::dword_ptr(PB, RC));
} }
void EmitLDP() void EmitLDP()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movsd(regF[a], asmjit::x86::qword_ptr(PB, KC)); cc.movsd(regF[a], asmjit::x86::qword_ptr(PB, KC));
} }
void EmitLDP_R() void EmitLDP_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
cc.movsd(regF[a], asmjit::x86::qword_ptr(PB, RC)); cc.movsd(regF[a], asmjit::x86::qword_ptr(PB, RC));
} }
@ -511,27 +534,57 @@ private:
void EmitLS_R() void EmitLS_R()
{ {
} }*/
void EmitLO() // load object void EmitLO()
{ {
EmitNullPointerThrow(B, X_READ_NIL);
auto ptr = cc.newIntPtr();
cc.mov(ptr, asmjit::x86::ptr(PB, KC));
typedef void*(*FuncPtr)(void*);
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *ptr) -> void*
{
DObject *p = static_cast<DObject *>(ptr);
return GC::ReadBarrier(p);
}))), asmjit::FuncSignature1<void*, void*>());
call->setRet(0, regA[a]);
call->setArg(0, ptr);
} }
void EmitLO_R() void EmitLO_R()
{ {
EmitNullPointerThrow(B, X_READ_NIL);
auto ptr = cc.newIntPtr();
cc.mov(ptr, asmjit::x86::ptr(PB, RC));
typedef void*(*FuncPtr)(void*);
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>([](void *ptr) -> void*
{
DObject *p = static_cast<DObject *>(ptr);
return GC::ReadBarrier(p);
}))), asmjit::FuncSignature1<void*, void*>());
call->setRet(0, regA[a]);
call->setArg(0, ptr);
} }
void EmitLP() // load pointer void EmitLP()
{ {
EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regA[a], asmjit::x86::ptr(PB, KC));
} }
void EmitLP_R() void EmitLP_R()
{ {
}*/ EmitNullPointerThrow(B, X_READ_NIL);
cc.mov(regA[a], asmjit::x86::ptr(PB, RC));
}
void EmitLV2() void EmitLV2()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, KC); cc.add(tmp, KC);
@ -541,7 +594,7 @@ private:
void EmitLV2_R() void EmitLV2_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, RC); cc.add(tmp, RC);
@ -551,7 +604,7 @@ private:
void EmitLV3() void EmitLV3()
{ {
NULL_POINTER_CHECK(PB, KC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, KC); cc.add(tmp, KC);
@ -562,7 +615,7 @@ private:
void EmitLV3_R() void EmitLV3_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, RC); cc.add(tmp, RC);
@ -581,7 +634,7 @@ private:
void EmitLBIT() // rA = !!(*rB & C) -- *rB is a byte void EmitLBIT() // rA = !!(*rB & C) -- *rB is a byte
{ {
NULL_POINTER_CHECK(PB, 0, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
auto tmp = cc.newInt8(); auto tmp = cc.newInt8();
cc.mov(regD[a], PB); cc.mov(regD[a], PB);
cc.and_(regD[a], C); cc.and_(regD[a], C);
@ -594,74 +647,98 @@ private:
void EmitSB() void EmitSB()
{ {
NULL_POINTER_CHECK(PA, KC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.mov(asmjit::x86::byte_ptr(PA, KC), regD[B].r8Lo()); cc.mov(asmjit::x86::byte_ptr(PA, KC), regD[B].r8Lo());
} }
void EmitSB_R() void EmitSB_R()
{ {
NULL_POINTER_CHECK(PA, RC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.mov(asmjit::x86::byte_ptr(PA, RC), regD[B].r8Lo()); cc.mov(asmjit::x86::byte_ptr(PA, RC), regD[B].r8Lo());
} }
void EmitSH() void EmitSH()
{ {
NULL_POINTER_CHECK(PA, KC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.mov(asmjit::x86::word_ptr(PA, KC), regD[B].r16()); cc.mov(asmjit::x86::word_ptr(PA, KC), regD[B].r16());
} }
void EmitSH_R() void EmitSH_R()
{ {
NULL_POINTER_CHECK(PA, RC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.mov(asmjit::x86::word_ptr(PA, RC), regD[B].r16()); cc.mov(asmjit::x86::word_ptr(PA, RC), regD[B].r16());
} }
void EmitSW() void EmitSW()
{ {
NULL_POINTER_CHECK(PA, KC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.mov(asmjit::x86::dword_ptr(PA, KC), regD[B]); cc.mov(asmjit::x86::dword_ptr(PA, KC), regD[B]);
} }
void EmitSW_R() void EmitSW_R()
{ {
NULL_POINTER_CHECK(PA, RC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.mov(asmjit::x86::dword_ptr(PA, RC), regD[B]); cc.mov(asmjit::x86::dword_ptr(PA, RC), regD[B]);
} }
void EmitSSP() void EmitSSP()
{ {
NULL_POINTER_CHECK(PB, KC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.movss(asmjit::x86::dword_ptr(PA, KC), regF[B]); cc.movss(asmjit::x86::dword_ptr(PA, KC), regF[B]);
} }
void EmitSSP_R() void EmitSSP_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.movss(asmjit::x86::dword_ptr(PA, RC), regF[B]); cc.movss(asmjit::x86::dword_ptr(PA, RC), regF[B]);
} }
void EmitSDP() void EmitSDP()
{ {
NULL_POINTER_CHECK(PB, KC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.movsd(asmjit::x86::qword_ptr(PA, KC), regF[B]); cc.movsd(asmjit::x86::qword_ptr(PA, KC), regF[B]);
} }
void EmitSDP_R() void EmitSDP_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_WRITE_NIL); EmitNullPointerThrow(A, X_WRITE_NIL);
cc.movsd(asmjit::x86::qword_ptr(PA, RC), regF[B]); cc.movsd(asmjit::x86::qword_ptr(PA, RC), regF[B]);
} }
//void EmitSS() {} // store string //void EmitSS() {} // store string
//void EmitSS_R() {} //void EmitSS_R() {}
//void EmitSO() {} // store object pointer with write barrier (only needed for non thinkers and non types)
//void EmitSO_R() {} void EmitSO()
//void EmitSP() {} // store pointer {
//void EmitSP_R() {} cc.mov(asmjit::x86::ptr(PA, KC), regA[B]);
typedef void(*FuncPtr)(DObject*);
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(GC::WriteBarrier))), asmjit::FuncSignature1<void, void*>());
call->setArg(0, regA[B]);
}
void EmitSO_R()
{
cc.mov(asmjit::x86::ptr(PA, RC), regA[B]);
typedef void(*FuncPtr)(DObject*);
auto call = cc.call(ToMemAddress(reinterpret_cast<const void*>(static_cast<FuncPtr>(GC::WriteBarrier))), asmjit::FuncSignature1<void, void*>());
call->setArg(0, regA[B]);
}
void EmitSP()
{
cc.mov(asmjit::x86::ptr(PA, KC), regA[B]);
}
void EmitSP_R()
{
cc.mov(asmjit::x86::ptr(PA, RC), regA[B]);
}
void EmitSV2() void EmitSV2()
{ {
NULL_POINTER_CHECK(PB, KC, X_WRITE_NIL); EmitNullPointerThrow(B, X_WRITE_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, KC); cc.add(tmp, KC);
@ -671,7 +748,7 @@ private:
void EmitSV2_R() void EmitSV2_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_WRITE_NIL); EmitNullPointerThrow(B, X_WRITE_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, RC); cc.add(tmp, RC);
@ -681,7 +758,7 @@ private:
void EmitSV3() void EmitSV3()
{ {
NULL_POINTER_CHECK(PB, KC, X_WRITE_NIL); EmitNullPointerThrow(B, X_WRITE_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, KC); cc.add(tmp, KC);
@ -692,7 +769,7 @@ private:
void EmitSV3_R() void EmitSV3_R()
{ {
NULL_POINTER_CHECK(PB, RC, X_WRITE_NIL); EmitNullPointerThrow(B, X_WRITE_NIL);
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
cc.mov(tmp, PB); cc.mov(tmp, PB);
cc.add(tmp, RC); cc.add(tmp, RC);
@ -2488,6 +2565,15 @@ private:
call->setArg(0, b); call->setArg(0, b);
} }
void EmitNullPointerThrow(int index, EVMAbortException reason)
{
auto label = cc.newLabel();
cc.test(regA[index], regA[index]);
cc.jne(label);
EmitThrowException(reason);
cc.bind(label);
}
void EmitThrowException(EVMAbortException reason) void EmitThrowException(EVMAbortException reason)
{ {
using namespace asmjit; using namespace asmjit;