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
|
#pragma once
#include "Core/TObject.h"
#include "Code/Reference.h"
#include "Code/Listing.h"
#include "Gc/VTable.h"
namespace storm {
STORM_PKG(core.lang);
class Function;
/**
* This file manages a C++ VTable. This is done in a way which is compatible with the C++
* compiler implementation, so that we can extend classes in C++ in Storm seamlessly.
*
* Note: as we need to be able to access a negative index of the table, and since we can not have
* internal pointers to objects due to the GC, we actually always point to index -extraOffset in the
* VTable when storing it in this class.
*
* Note: This class assumes that all objects in C++ only use single inheritance.
*/
class VTableCpp : public code::Content {
STORM_CLASS;
public:
// Create a VTable which is a write-protected wrapper around the raw C++ vtable.
static VTableCpp *wrap(Engine &e, const void *vtable);
static VTableCpp *wrap(Engine &e, const void *vtable, nat count);
// Create a VTable which is a copy of the provided C++ vtable or another VTableCpp object.
static VTableCpp *copy(Engine &e, const void *vtable);
static VTableCpp *copy(Engine &e, const void *vtable, nat count);
static VTableCpp *copy(Engine &e, const VTableCpp *src);
// Get number of elements. Note: 'size' returns number of bytes.
nat count() const;
// Get a pointer to the vtable. Marks it as used.
const void **pointer();
// Set this VTable for a class.
void insert(RootObject *obj);
// Generate code to set VTable for a class. 'vtableRef' is a reference to the VTableCpp used.
static void insert(code::Listing *to, code::Var obj, code::Ref vtableRef);
// Get the offset between the vtable allocation and the actual start of the vtable.
static size_t vtableAllocOffset() { return vtable::allocOffset(); }
// Replace the contents in here with a new vtable. Clears all references.
void replace(const void *vtable);
void replace(const void *vtable, nat count);
void replace(const VTableCpp *src);
// Get/set the extra data. Not present if write-protected.
const void *extra() const;
void extra(const void *to);
// Find a function in here. Returns vtable::invalid if none is found.
nat findSlot(const void *fn) const;
// Set a slot. When write protected, this is a no-op.
void set(nat slot, const void *to);
void set(nat slot, Function *fn);
// Get the function associated with a vtable entry.
MAYBE(Function *) get(nat slot) const;
// Clear a vtable entry.
void clear(nat slot);
// Interface from 'Content'.
virtual const void *address() const;
virtual nat size() const;
// Check if this object stores the same vtable as 'vtable' (extracted using 'vtable::from').
// Called from 'runtime::typeOf', so needs to be fairly fast.
inline Bool sameAs(const void *vtable) const {
return vtable == raw
|| (data && (vtable == &data->v[vtable::extraOffset]));
}
private:
// Create.
VTableCpp(const void *src, nat count, bool copy);
// The VTable data. We're storing it as a regular GC array. May be null if we're referring
// to a raw c++ vtable. The 'filled' member of this array is used to indicate that the
// vtable has been assigned to an object at some time.
GcArray<const void *> *data;
// References updating the VTable. The entire table is null if no updaters are added.
GcArray<Function *> *refs;
// Raw write-protected C++ vtable.
const void **raw;
// Size of the vtable in here.
nat tabSize;
// Initialize ourselves.
void init(const void *vtable, nat count, bool copy);
// Get a pointer to the start of the vtable.
const void **table() const;
// Is the table used?
inline bool used() const;
};
}
|