File: Binary.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 (219 lines) | stat: -rw-r--r-- 6,754 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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#pragma once
#include "Core/TObject.h"
#include "Core/GcType.h"
#include "Arena.h"
#include "Listing.h"
#include "RefSource.h"
#include "StackFrame.h"

namespace code {
	STORM_PKG(core.asm);

	/**
	 * A Binary represents a Listing that has been translated into machine code, along with any
	 * extra information needed (such as descriptions of exception handlers or similar).
	 *
	 * Note: The Binary class expects backends to create a table of data starting at the meta() label
	 * where each element looks like this:
	 *   size_t freeFn; - a pointer to the function to be executed when this variable is to be freed.
	 *   size_t offset; - a signed offset to the variable relative to the stack frame provided by the backend.
	 * There shall be one entry for each variable in the Listing. Variable 0 shall be at index 0.
	 */
	class Binary : public Content {
		STORM_CLASS;
	public:
		// Translate a listing into machine code.
		STORM_CTOR Binary(Arena *arena, Listing *src);

		// Data structure containing more information about the generated code.
		class Info {
			STORM_VALUE;
		public:
			// The created binary.
			Binary *binary;

			// The transformed listing.
			Listing *transformed;

			// Offsets of all labels.
			Array<Nat> *offsets;

			// The variable layout. Not available when 'compileTransformed' is called.
			Array<Offset> *varLayout;

			// Create.
			STORM_CTOR Info(Binary *binary, Listing *transformed, Array<Nat> *offsets, Array<Offset> *layout)
				: binary(binary), transformed(transformed), offsets(offsets), varLayout(layout) {}
		};

		// Create a binary, returning more information than the constructor.
		static Info STORM_FN compile(Arena *arena, Listing *src);

		// Create a binary, but from a Listing that is already transformed for the current arena.
		static Info STORM_FN compileTransformed(Arena *arena, Listing *transformed);

		// Clean up a stack frame from this function.
		void cleanup(StackFrame &frame);

		// Clean up a stack frame from this function from the current block, up to and including
		// 'until'. Returns the parent of 'until', which is now to be considered the current part.
		Nat cleanup(StackFrame &frame, Nat until);

		// Check if we have any catch-clauses at all (used for pre-screening in exception handlers).
		inline bool hasCatch() const { return tryBlocks != null; }

		// Information on how to resume from a try-clause.
		struct Resume {
			// Next instruction to execute. 'null' if nothing is to be done.
			void *ip;

			// Offset from the frame pointer to the stack pointer.
			ptrdiff_t stackOffset;

			// Part outside the one handling the exception.
			size_t cleanUntil;
		};

		// Check if we have a catch-clause for the active part or any of its parents.
		bool hasCatch(Nat part, RootObject *exception, Resume &resume);

		// Get the stack offset for this binary, i.e. the difference between the stack pointer and
		// the frame pointer for this function (mainly used for cleanup during exceptions).
		ptrdiff_t stackOffset() const;

		// Get the size of the stack frame. On some platforms, this differs from the stack offset,
		// as it depends on where in the stack frame pointer refers to.
		size_t stackSize() const;

		// Exception status:
		inline Bool STORM_FN exceptionCleanup() const { return (flags & ehClean) != 0; }
		inline Bool STORM_FN exceptionCaught() const { return (flags & ehCatch) != 0; }
		inline Bool STORM_FN exceptionAware() const { return (flags & (ehCatch | ehClean)) != 0; }

		// Is this a binary for a member function?
		inline Bool STORM_FN isMember() const { return (flags & isMemberFn) != 0; }
		// Get result from the function.
		MAYBE(TypeDesc *) STORM_FN result() const;
		// Get parameters to the function.
		Array<TypeDesc *> *STORM_FN params() const;

		// Output to string.
		virtual void STORM_FN toS(StrBuf *to) const;

		// Information about a single variable.
		struct Variable {
			Nat id;

			// The low 16 bits contain FreeOpt, the high 16 bits contain the size of the variable.
			Nat flags;

			enum {
				// Parameter size
				sUnknown = 0x0000,
				sByte = 0x1000,
				sInt = 0x2000,
				sLong = 0x3000,
				sPtr = 0x4000,
				sMask = 0xFF000,

				// Mask for freeOpts.
				sFreeOptMask = 0xFFF,

				// Mask for finding the parameter index (+1).
				sParamMask = 0x0FF00000,
				sParamShift = 20,
			};

			// Variable information. Might be null.
			Listing::VarInfo *varInfo;
		};

		// Remember the block hierarchy. These are allocated as GcArray:s to reduce the number of allocations.
		struct Block {
			// Number of elements.
			const size_t count;

			// Parent block.
			size_t parent;

			// Variables in here.
			Variable vars[1];
		};

		// Get access to the block table, intended for 'compatibleSkeleton':
		GcArray<Block *> *blockInfo() { return blocks; }

		// Get information about variable cleanup.
		VarCleanup *cleanupInfo();

		// Find a code updater for a specific offset in the code here.
		MAYBE(Reference *) STORM_FN findReferenceByOffset(Nat offset);

		// Find a code updater for a specific CodeRef slot in the code here.
		MAYBE(Reference *) STORM_FN findReferenceBySlot(Nat refSlot);

	private:
		// For use inside 'compile'.
		Binary();

		// All blocks.
		GcArray<Block *> *blocks;

		// Information for try-blocks.
		struct TryInfo {
			// Current block id.
			Nat blockId;

			// Offset to continue execution from.
			Nat resumeOffset;

			// Type to catch.
			Type *type;
		};

		// Try-block information. 'null' if no exceptions are caught. Indices do not correspond to
		// parts here since the array is sparse. It is necessary to search the array (perhaps using
		// a binary search).
		GcArray<TryInfo> *tryBlocks;

		// Result and parameter TypeDescs. Element 0 is the result typedesc, remaining is parameters.
		GcArray<TypeDesc *> *resultAndParams;

		// Offset of the metadata label.
		Nat metaOffset;

		// Other misc. flags that contains information about the code.
		enum {
			// Mirrors 'exceptionCleanup' and 'exceptionCaught' in the Listing object.
			ehClean = 0x01,
			ehCatch = 0x02,

			// Is this a member function?
			isMemberFn = 0x10,
		};
		Nat flags;

		// Compile the Listing object.
		Info compileI(Arena *arena, Listing *src, Bool skipTransform);

		// Fill the 'blocks' array.
		void fillBlocks(Listing *src);

		// Fill the 'tryBlocks' array if necessary.
		void fillTryBlocks(Listing *src, LabelOutput *labels);

		// Clean a single variable.
		void cleanup(StackFrame &frame, Variable &v);

		// Fill 'resultAndParams'.
		void fillResultAndParams(Listing *src);

		// Get the raw value of 'stackOffset'.
		ptrdiff_t rawStackOffset() const;

		// Type declarations for the GC.
		static const GcType blockType;
		static const GcType tryInfoArrayType;
	};

}