File: CodeTable.h

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; 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 (115 lines) | stat: -rw-r--r-- 3,061 bytes parent folder | download | duplicates (3)
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
#pragma once
#include "Utils/Lock.h"
#include <vector>

namespace storm {

	/**
	 * A table that stores a set of pointers to Gc-allocated machine code. This implementation
	 * allows quick (O(log n) in most cases) lookup from a pointer within one of the code
	 * blocks. When registering a code block, using 'track', a handle is returned. This is so the Gc
	 * can update the table whenever the block has been moved, even though the CodeTable is
	 * allocated as a global.
	 *
	 * The internals of the table are protected by locks unless otherwise stated.
	 *
	 * This could be used to implement exception handling in the various code backends, but is not
	 * used otherwise.
	 */
	class CodeTable : NoCopy {
	public:
		// Create.
		CodeTable();

		// Destroy.
		~CodeTable();

		// A handle. This will always be pointer-sized so that it fits inside 'GcCodeRef::pointer'.
		typedef void *Handle;

		// Start tracking a new piece of machine code. Assumed to be allocated in a GC pool somewhere.
		Handle add(void *code);

		// Update the location of a previous handle. This function is *not* protected by locks as it
		// is expected to be called from inside the Gc scanning logic. All calls from outside Gc
		// scanning needs to be properly locked. 'code' is expected to be non-null.
		static void update(Handle handle, void *code);

		// Remove a code segment from the tracking mechanisms. Make sure so that 'update' for that
		// handle is not called again, as it may be reused shortly after.
		void remove(Handle handle);

		// Find a code segment from a pointer that is somewhere inside of it. Returns 'null' if
		// nothing was found.
		void *find(const void *addr);

	private:
		// An element in the table. These will never move, so a handle is simply a pointer to one of these.
		struct Elem {
			// Code allocation.
			void *code;

			// Owner.
			CodeTable *owner;
		};

		// Allocator.
		class Allocator {
		public:
			// Create.
			Allocator();

			// Destroy.
			~Allocator();

			// Allocate an object.
			Elem *alloc();

			// Deallocate an object.
			void free(Elem *e);

			// Fill 'out' with all elements that are allocated in some order.
			void alive(vector<Elem *> &out);

		private:
			enum {
				chunkSize = 10240
			};

			// Allocated chunks.
			vector<Elem *> chunks;

			// First element in the free list.
			Elem *first;

			// Allocate a new chunk.
			void allocChunk();
		};

		// Predicate for sorting.
		struct CodeCompare {
			inline bool operator() (const Elem *a, const Elem *b) const {
				return a->code < b->code;
			}
		};

		// Lock protecting the table.
		util::Lock lock;

		// Allocator for elements.
		Allocator mem;

		// Table of all active functions. Sorted when 'sorted' is true.
		typedef vector<Elem *>::iterator Iter;
		vector<Elem *> table;

		// Are the entries in the table sorted? (0 or 1, updated using atomics).
		size_t sorted;

		// Does the code in 'elem' contain 'ptr'?
		static bool contains(Elem *elem, const void *ptr);
	};

	// Get a global instance of the code table.
	CodeTable &codeTable();
}