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 102 103 104
|
#include "stdafx.h"
#include "Code/Binary.h"
#include "Code/Listing.h"
using namespace code;
static Int destroyed = 0;
class BigType {
public:
BigType(Int v) : v(v) {}
~BigType() {
destroyed += v;
}
Int v;
BigType CODECALL redirectTo() {
return BigType(v + 20);
}
};
static void freeBig(BigType *me) {
me->~BigType();
}
static void copyBig(BigType *to, BigType *from) {
new (to) BigType(*from);
}
static BigType redirectTo(BigType v) {
return BigType(v.v + 10);
}
static bool throwError = false;
static const void *redirectFn() {
if (throwError)
throw Error();
return address(&redirectTo);
}
BEGIN_TEST(RedirectTest, Code) {
Engine &e = gEngine();
Arena *arena = code::arena(e);
Ref copyBig = arena->external(S("copyBig"), address(&::copyBig));
Ref freeBig = arena->external(S("freeBig"), address(&::freeBig));
Ref redirectFn = arena->external(S("redirectFn"), address(&::redirectFn));
TypeDesc *bigDesc = new (e) ComplexDesc(Size::sInt, copyBig, freeBig);
Array<TypeDesc *> *params = new (e) Array<TypeDesc *>();
params->push(bigDesc);
Listing *l = arena->redirect(false, bigDesc, params, redirectFn, Operand());
Binary *b = new (e) Binary(arena, l);
typedef BigType (*Fn)(BigType);
Fn fn = (Fn)b->address();
throwError = true;
destroyed = 0;
CHECK_ERROR((*fn)(BigType(10)), Error);
CHECK(destroyed >= 10 && destroyed <= 20);
throwError = false;
CHECK_EQ((*fn)(BigType(10)).v, 20);
} END_TEST
static const void *redirectFnMember() {
if (throwError)
throw Error();
return address(&BigType::redirectTo);
}
BEGIN_TEST(RedirectMemberTest, Code) {
Engine &e = gEngine();
Arena *arena = code::arena(e);
Ref copyBig = arena->external(S("copyBig"), address(&::copyBig));
Ref freeBig = arena->external(S("freeBig"), address(&::freeBig));
Ref redirectFn = arena->external(S("redirectFnMember"), address(&::redirectFnMember));
TypeDesc *bigDesc = new (e) ComplexDesc(Size::sInt, copyBig, freeBig);
Array<TypeDesc *> *params = new (e) Array<TypeDesc *>();
params->push(ptrDesc(e));
Listing *l = arena->redirect(false, bigDesc, params, redirectFn, Operand());
Binary *b = new (e) Binary(arena, l);
typedef BigType (CODECALL BigType::*Fn)();
Fn fn = asMemberPtr<Fn>(b->address());
BigType val(10);
throwError = true;
CHECK_ERROR((val.*fn)(), Error);
throwError = false;
CHECK_EQ((val.*fn)().v, 30);
} END_TEST
|