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 105 106 107 108 109 110 111 112 113 114 115
|
#include "stdafx.h"
#include "Code.h"
#include "Gc.h"
#include "Core/GcCode.h"
#include "CodeTable.h"
#include "DwarfTable.h"
#include "CodeX86.h"
#include "CodeX64.h"
#include "CodeArm64.h"
#if defined(X86)
#define ARCH x86
#elif defined(X64)
#define ARCH x64
#elif defined(ARM64)
#define ARCH arm64
#else
#error "Updating code segments is not implemented for your architecture yet!"
#endif
namespace storm {
namespace gccode {
// The generic cases. These are implemented the same on every platform.
static void doWritePtr(void *code, const GcCode *refs, Nat id) {
const GcCodeRef &ref = refs->refs[id];
size_t ptr = size_t(ref.pointer);
void *write = ((byte *)code) + ref.offset;
// Note: These writes need to be visible as an atomic operation to the instruction
// decoding unit of the CPU. Further atomicity is not required, as the GC arranges for
// that anyway. Offsets might not be aligned as regular pointers on the system.
switch (ref.kind) {
case GcCodeRef::disabled:
case GcCodeRef::ptrStorage:
case GcCodeRef::backEdge:
// Nothing to do...
break;
case GcCodeRef::rawPtr:
unalignedAtomicWrite(*(size_t *)write, ptr);
invalidateSingleICache(write);
break;
case GcCodeRef::relativePtr:
case GcCodeRef::relative:
unalignedAtomicWrite(*(size_t *)write, ptr - (size_t(write) + sizeof(size_t)));
invalidateSingleICache(write);
break;
case GcCodeRef::inside:
unalignedAtomicWrite(*(size_t *)write, ptr + size_t(code));
invalidateSingleICache(write);
break;
case GcCodeRef::relativeHere:
// Write a relative pointer to 'pointer' itself. Should always be the same, but the
// offset is not really exposed conveniently anywhere else.
ptr = size_t(&ref.pointer);
shortUnalignedAtomicWrite(*(nat *)write, nat(ptr - (size_t(write) + sizeof(nat))));
invalidateSingleICache(write);
break;
case GcCodeRef::codeInfo:
if (ref.pointer)
CodeTable::update(ref.pointer, code);
break;
case GcCodeRef::dwarfInfo:
if (ref.pointer)
DwarfChunk::updateFn((FDE *)ref.pointer, code);
break;
default:
// Pass on to the architecture specific parts:
ARCH::writePtr(code, refs, id);
break;
}
}
void updatePtrs(void *code, const GcCode *refs) {
for (Nat i = 0; i < refs->refCount; i++)
doWritePtr(code, refs, i);
}
void writePtr(void *code, Nat id) {
GcCode *refs = Gc::codeRefs(code);
doWritePtr(code, refs, id);
}
Bool needFinalization() {
return ARCH::needFinalization();
}
void finalize(void *code) {
GcCode *refs = Gc::codeRefs(code);
for (size_t i = 0; i < refs->refCount; i++) {
GcCodeRef &ref = refs->refs[i];
if (ref.pointer) {
if (ref.kind == GcCodeRef::codeInfo) {
CodeTable::Handle h = ref.pointer;
atomicWrite(ref.pointer, null);
codeTable().remove(h);
} else if (ref.kind == GcCodeRef::dwarfInfo) {
FDE *ptr = (FDE *)ref.pointer;
atomicWrite(ref.pointer, null);
dwarfTable().free(ptr);
}
}
}
ARCH::finalize(code);
}
}
}
|