File: codehints.bs

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 (148 lines) | stat: -rw-r--r-- 4,273 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
use core:lang;
use core:asm;
use lang:bs:macro;

/**
 * Code hints, see description of Hints.
 *
 * This class gets the chance to intercept how local variables are stored and saved by the Program
 * class, so that a backend may hide that it, for example, stores everything by reference instead of
 * by value for whatever reason.
 */
class CodeHints on Compiler {
	// Attempt to find the 'main' function. This is called on all hints objects until one responds.
	Fn<void>? findMain(Package pkg) : abstract;

	// Called to find a Hints object that feels responsible for a particular function.
	// Only the first hint object that returns true here will get the remaining functions called for that function.
	Bool handlesFunction(Function fn) : abstract;

	// Provide a user-friendly name of the function.
	Str cleanName(Function fn, Package pkg) : abstract;

	// Should we patch an external function? The main purpose of this is to keep track of memory
	// accesses. 'fn' is known to not reside inside the package that contains the code to be
	// visualized. 'state' can be used to make robust queries as to which package the function
	// resides in (it creates copies of packages, so comparing based on name does not always work).
	// Note, this function is called for *all* hints, so that they may collectively determine a
	// union of functions that should be patched.
	Bool patchExternal(PatchEquivalence eq, Function fn) : abstract;

	// How to treat the external function in terms of barriers? Only called for functions that have
	// no SrcBarrier located after them.
	Barrier functionBarrier(Function fn) : abstract;

	/**
	 * How to handle the saved variable.
	 */
	enum Save {
		// Don't save it.
		none,

		// Save it, it is a copy of something that needs to be destroyed later.
		copy,

		// Save it, it is a reference to something, so we don't need to destroy it.
		ref,
	}

	// Create a Variant containing a copy of the variable at the indicated location. Return 'false'
	// if it is not possible.
	Save saveVariable(Listing to, Var var, Listing:VarInfo info, Operand dest) : abstract;
}


/**
 * Default implementation of the code hints.
 *
 * Suitable for Basic Storm for example.
 */
class DefaultCodeHints extends CodeHints {
	// We handle all functions!
	Bool handlesFunction(Function f) {
		true;
	}

	// Generate the name of a function, ignoring everything above "remove".
	Str cleanName(Function f, Package remove) : override {
		Name name;
		addParts(name, f, remove, true);
		Str n = name.toS;
		if (n.endsWith(")"))
			n;
		else
			n + "()";
	}

	// Helper for 'cleanName'.
	private void addParts(Name to, Named at, Package remove, Bool skipFirst) {
		if (at is remove)
			return;
		if (at is named{core})
			return;

		// Don't include the root package either.
		unless (parent = at.parent as Named)
			return;

		addParts(to, parent, remove, false);

		Name[] params;
		for (p in at.params) {
			if (skipFirst) {
				skipFirst = false;
			} else {
				if (t = p.type) {
					Name n;
					addParts(n, t, remove, false);
					params << n;
				}
			}
		}

		RecPart p(at.name, params);
		to.add(p);
	}

	// Don't patch external functions.
	Bool patchExternal(PatchEquivalence eq, Function fn) : override { false; }

	// The default is to not have any explicit barriers at all.
	Barrier functionBarrier(Function fn) : override { Barrier:none; }

	// Save a variable.
	Save saveVariable(Listing to, Var var, Listing:VarInfo info, Operand dest) : override {
		// We don't do references at the moment.
		if (info.ref)
			return Save:none;

		Type variant = named{Variant};
		Value param(info.type);
		SimplePart ctorName("__init", [Value(variant, true), param]);
		unless (ctor = variant.find(ctorName, Scope()) as Function) {
			print("Warning: No Variant constructor for ${param}");
			return Save:none;
		}

		to << lea(ptrA, dest);
		if (param.isValue())
			to << lea(ptrB, var);
		else
			to << mov(ptrB, var);
		to << fnParam(ptrDesc, ptrA);
		to << fnParam(ptrDesc, ptrB);
		to << fnCall(ctor.ref(), true);
		Save:copy;
	}

	// Find 'main'.
	Fn<void>? findMain(Package pkg) {
		unless (main = pkg.find(SimplePart("main"), Scope(pkg)) as Function)
			return null;

		unless (mainPtr = main.pointer as Fn<void>)
			return null;

		return mainPtr;
	}
}