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
|
#include "stdafx.h"
#include "FnState.h"
#include "Code/Block.h"
#include "Code/Exception.h"
namespace code {
Nat encodeFnState(Nat block, Nat activation) {
if (block != Block().key() && block > 0xFFFE)
throw new (runtime::someEngine()) InvalidValue(S("The X86 backend does not support more than 65535 blocks."));
if (activation > 0xFFFF)
throw new (runtime::someEngine()) InvalidValue(S("The X86 backend does not support more than 65536 activations."));
if (block == Block().key())
block = 0xFFFF;
return (block << 16) | activation;
}
void decodeFnState(Nat original, Nat &block, Nat &activation) {
block = (original >> 16) & 0xFFFF;
activation = original & 0xFFFF;
if (block == 0xFFFF)
block = Block().key();
}
/**
* Description of the data at the end of each function.
*/
struct FnData {
// Number of entries in the block table.
size_t blockCount;
};
/**
* Description of a single entry in the block table.
*/
struct FnBlock {
// At which offset do we start?
Nat offset;
// Which block?
Nat block;
};
// Get the block data from a function.
static const FnBlock *getBlocks(const FnData *data) {
const FnBlock *end = (const FnBlock *)data;
return end - data->blockCount;
}
// Compare object.
struct BlockCompare {
bool operator()(Nat offset, const FnBlock &block) const {
return offset < block.offset;
}
};
Nat findFunctionState(const void *function, size_t offset) {
size_t size = runtime::codeSize(function);
return findFunctionStateFromEnd((const byte *)function + size, offset);
}
Nat findFunctionStateFromEnd(const void *end, size_t offset) {
const FnData *data = (const FnData *)end - 1;
const FnBlock *blocks = getBlocks(data);
Nat invalid = Block().key();
// The entries are sorted by their 'offset' member. We can perform a binary search!
// Note: if there are multiple elements that are equal, we need to pick the last one.
const FnBlock *found = std::upper_bound(blocks, blocks + data->blockCount, Nat(offset), BlockCompare());
if (found == blocks) {
// Before any block, nothing to do!
return invalid;
}
found--;
return found->block;
}
}
|