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;
}
}
|