File: VTable.h

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (191 lines) | stat: -rw-r--r-- 7,347 bytes parent folder | download
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#pragma once
#include "Core/TObject.h"
#include "Core/Map.h"
#include "Core/GcBitset.h"
#include "Code/Listing.h"
#include "VTableSlot.h"
#include "VTableCpp.h"
#include "VTableStorm.h"
#include "VTableUpdater.h"
#include "Function.h"
#include "OverridePart.h"

namespace storm {
	STORM_PKG(core.lang);

	class Type;

	/**
	 * The VTable implementation in Storm is split into three files. This one (VTable.h) contains
	 * the logical 'one and only' VTable implementation for a type. However, in Storm a VTable is
	 * split into two parts: the C++ VTable and the Storm VTable.
	 *
	 * The C++ VTable is managed by VTableCpp, and is binary compatible with C++. Storm produces its
	 * own derivatives to be able to extend classes declared in C++, but this has some
	 * limitations. For example, we can not dynamically add slots in the VTable without having to
	 * walk the heap and examine all living objects to see if we need to replace their VTables
	 * whenever the VTable shall be expanded.
	 *
	 * Instead, we store the dynamic part in the Storm VTable, which is managed by VTableStorm. For
	 * types declared in Storm, we store a pointer to the Storm VTable at the unused offset -1 in
	 * the C++ VTable. This allows us to change the Storm VTable for all living objects by simply
	 * altering one pointer. However, this indirection has a small penalty which we might want to
	 * get rid of eventually.
	 *
	 * If a vtable is set in this vtable, it is automatically updated in all vtables of the child
	 * class, as told by 'owner'. The vtable is also responsible for keeping vtable dispatch up to
	 * date if vtable slots are moved. We assume we will be notified when a child has been removed,
	 * and that we will be re-created whenever we gain a new parent.
	 *
	 * Note: As mentioned in the documentation for 'core.lang.Type', we assume that we do not need
	 * to eagerly load functions in child classes since they are not needed until that class is
	 * instantiated, in which case we will be notified. If we would eagerly load subclasses in this
	 * manner, we would create dependencies that are hard to realize.
	 *
	 * TODO: It might be possible to only store a bitmask in VTableCpp and VTableStorm that
	 * indicates if we have a new function set at this level or not.
	 */
	class VTable : public ObjectOn<Compiler> {
		STORM_CLASS;
		friend class VTableUpdater;
	public:
		// Create a VTable for a type. Use 'createXxx()' to supply the C++ vtable we shall be
		// derived from. Needs to know which type we're associated with as we need to traverse the
		// inheritance hierarchy for certain operations.
		STORM_CTOR VTable(Type *owner);

		// Create vtable for a class representing a pure C++ type. In this mode, it is not possible
		// to replace functions in the VTable.
		void createCpp(const void *cppVTable);

		// Create a vtable for a class derived from 'parent'. If done more than once, the current
		// VTable is cleared and then re-initialized.
		void STORM_FN createStorm(VTable *parent);

		// Insert a function to be managed by this VTable. 'fn' will be allocated in a suitable slot
		// and will be set to use a lookup if needed.
		void STORM_FN insert(Function *fn);

		// Remove a function from this VTable. Will ensure that any parent functions that no longer
		// require vtable lookup.
		void STORM_FN remove(Function *fn);

		// Notify that a child class has been removed. We assume it is not possible to reach 'type'
		// by traversing the inheritance hierarchy.
		void STORM_FN removeChild(Type *type);

		// Late initialization.
		void lateInit();

		// Set the vtable of an object.
		void insert(RootObject *obj);

		// Generate code for setting the vtable.
		void STORM_FN insert(code::Listing *to, code::Var obj);

		// Get the vtable pointer. Marks it as used.
		const void **pointer();

		// Make this vtable replace the other one (i.e. update refs).
		void replace(VTable *old, ReplaceTasks *tasks);

		// Get the "topmost" functions for each entry in the vtable. Unused slots are left out
		// (since they would be null).
		Array<Function *> *allSlots();

		// Dump the vtable contents to stdout.
		void dbg_dump() 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 {
			if (cpp)
				return cpp->sameAs(vtable);
			else
				return false;
		}

	private:
		// Owning type.
		Type *owner;

		// The derived C++ VTable (might be write-protected).
		VTableCpp *cpp;

		// The derived Storm VTable (if we created one).
		VTableStorm *storm;

		// First slot we have access to in the Storm vtable. This equals the size of our parent's
		// vtable.
		Nat stormFirst;

		// Associate an updater with each function.
		typedef Map<Function *, VTableUpdater *> UpdateMap;
		Map<Function *, VTableUpdater *> *updaters;

		// RefSource referring to the VTable.
		code::RefSource *source;

		// Called on super-classes whenever a parent slot has been vacated.
		void remove(VTableSlot slot);

		// Called when one of our parent classes have grown their vtable and we need to follow.
		void parentGrown(Nat pos, Nat count);

		// Called when we need to update a slot.
		void slotMoved(VTableSlot slot, const void *newAddr);

		// Update slots in all children.
		void parentSlotMoved(VTableSlot slot, const void *newAddr);

		// Find the current vtable slot for 'fn' (if any) in this vtable or in any parent vtables.
		VTableSlot findSlot(Function *fn, Bool setLookup);

		// Find a slot matching 'fn' assuming we're a super class to where 'fn' belongs. If
		// 'setLookup' is true, then use vtable lookup for the most specific match found.
		VTableSlot findSuperSlot(OverridePart *fn, Bool setLookup);

		// Enable lookup for 'slot' in any parent classes.
		void updateSuper(VTableSlot slot);

		// Find (and update) any children overriding 'fn'. Returns true if any child is found.
		Bool updateChildren(Function *fn, VTableSlot slot);

		// Helper to the above function.
		Bool updateChildren(OverridePart *fn, VTableSlot slot);

		// See if some child is using slot 'slot' to override the function in that slot.
		Bool hasOverride(VTableSlot slot);

		// For all slots not already found in the two sets: try to find an overriding function for
		// them. If none is found, disable vtable lookup on the function for that slot.
		void disableLookup(GcBitset *cppFound, GcBitset *stormFound);

		// Set 'slot' to refer to a specific function.
		void set(VTableSlot slot, Function *fn);
		void set(VTableSlot slot, const void *fn);

		// Get the function associated with 'slot'. We allow reading out of bounds.
		MAYBE(Function *) get(VTableSlot slot);

		// Clear 'slot'.
		void clear(VTableSlot slot);

		// Create a slot for a Storm function. Returns the created index.
		VTableSlot allocSlot();

		// Fill in functions for slots into the two arrays.
		void allSlots(Array<Function *> *cppFns, Array<Function *> *stormFns);

		// Use lookup for 'fn'.
		static void useLookup(Function *fn, VTableSlot slot);

		// Update lookup for 'fn' to use 'slot'. Does nothing if no lookup is already used.
		static void updateLookup(Function *fn, VTableSlot slot);

		// Decide how much to grow each time 'storm' needs to grow.
		static const Nat stormGrow = 5;
	};


}