Another wild tail chase

It appears I’ve been waiting in vain! It’s been more than a month since my last blog post, and still no pull requests for TailCop! In particular, no pulls requests that implement rewriting of recursive calls to loops for instance methods. I don’t know why.

I guess it’s up to me, then.

To recap, TailCop is a simple utility I wrote to rewrite tail-recursive static methods to use loops instead (which prevents stack overflow in cases where the recursion goes very deep). The reason we shied away from instance methods last time is dynamic dispatch, which complicates matters a bit. We’ll tackle that in this blog post. To do so, however, we need to impose a couple of constraints.

First, we need to make sure that the instance method is non-virtual, that is, that it cannot be overridden in a subclass. Why? Well, let’s suppose you let Add be virtual, so that people may override it. Sounds reasonable? If it isn’t overridden, then it will behave just the same whether or not it’s rewritten. If it is overridden, then it shouldn’t matter if we override the recursive or the rewritten version, right? Well, you’d think, but unfortunately that’s not the case.

Say you decided to make Add virtual and rewrote it using TailCop. A few months pass by. Along comes your enthusiastic, dim-witted co-worker, ready to redefine the semantics of Add. He’s been reading up on object-orientation and is highly motivated to put all his hard-won knowledge to work. Unfortunately, he didn’t quite get to the Liskov thing, and so he ends up with this:


class Adder
{
virtual int Add(int x, int y)
{
return x > 0 ? Add(x 1, y + 1) : y;
}
}
class BlackAdder : Adder
{
override int Add(int x, int y)
{
return base.Add(x, x > 0 ? y + 1 : y);
}
}

So while he overrides the Add method in a subclass, he doesn’t replace it wholesale – he still invokes the original Add method as well. But then we have a problem. Due to dynamic dispatch, the recursive Add call in Adder will invoke BlackAdder.Add which will then invoke Adder.Add and so forth. Basically we’re taking the elevator up and down in the inheritance hierarchy. If we rewrite Adder.Add to use a loop, we will never be allowed to take the elevator back down to BlackAdder.Add. Obviously, then, the rewrite is not safe. Running BlackAdder.Add(30, 30) yields 90 with the original recursive version of Adder.Add and 61 with the rewritten version. Long story short: we will not rewrite virtual methods.

Our second constraint is that, obviously, the recursive call has to be made on the same object instance. If we call the same method on a different instance, there’s no guarantee that we’ll get the same result. For instance, if the calculation relies on object state in any way, we’re toast. So we need to invoke the method on this, not that. So how do we ensure that a recursive call is always made on the same instance – that is, on this? Well, obviously we need to be in a situation where the evaluation stack contains a reference to this in the right place when we’re making the recursive call. In IL, the this parameter to instance methods is always passed explicitly, unlike in C#. So a C# instance method with n parameters is represented as a method with n+1 parameters on the IL level. The additional parameter in IL is for the this reference, and is passed as the first parameter to the instance method. (This is similar to Python, where the self parameter is always passed explicitly to instance methods.) So anyways, if we take the evaluation stack at the point of a call to an instance methods and pop off n values (corresponding to the n parameters in the C# method), we should find a this there. If we find something else, we won’t rewrite.

While the first constraint is trivial to check for, the second one is a bit more involved. What we have at hand is a data-flow problem, which is a big thing in program analysis. In our case, we need to identify places in the code where this references are pushed onto the stack, and emulate how the stack changes when different opcodes are executed. To model the flow of data in a method (in particular: flow of this references), we first need to construct a control flow graph (CFG for short). A CFG shows (statically) the different possible execution paths through the method. It consists of nodes that represents blocks of instructions and edges that represents paths from one such block to another. A method without branching instructions has a trivial CFG, consisting of a single node representing a block with all the instructions in the method. Once we have branching instructions, however, things become a little more interesting. For instance, consider the code below:


public static int Loop(int x, int y)
{
while (x > 0)
{
x;
++y;
}
return y;
}

view raw

Loop.Add.cs

hosted with ❤ by GitHub

The CFG for (the IL representation of) that code looks like this:

cfg

As you can see, some nodes now have multiple inbound edges. This matters when we try to describe how data flows through the method. Let’s see if we can sketch it out by looking at what happens inside a single node first. A node represents a block of n instructions. Each instruction can be thought of as a function f : S -> S' that accepts a stack as input and produces a stack as output. We can then produce an aggregated stack transformation function for an entire node in the CFG by composing such functions. Since each node represents a block of n instructions, we have a corresponding sequence of functions f0, f1, ..., fn-1 of stack transformations. We can use this sequence to compose a new function g : S -> S' by applying each function fi in order, as follows: g(s) = fn-1(...(f1(f0(s)))). In superior languages, this is sometimes written g = fn-1 o ... o f1 o f0, where o is the composition operator.

Each node in the CFG is associated with such a transformation function g. Now the edges come into play: since it is possible to arrive at some node n in the CFG by following different paths, we may end up with more than a single stack as potential input for n‘s g function – and hence more than a single stack as potential output. In general, therefore, we associate with each node a set I of distinct input stacks and a set O of distinct output stacks. Obviously, if there is an edge from node n to node m in CFG, then all stacks in n‘s output set will be elements in m‘s input set. To determine the sets I and O for each node in the CFG, we traverse the edges in the CFG until the various Is and Os stabilize, that is, until we no longer produce additional distinct stacks in any of the sets.

This gives us the following pseudocode for processing a node in the CFG, given a set S of stacks as input:


def process S
if exists s in S where not I contains s
I = I union S
O = map g I
foreach e in edges
process e.target O
end
end
end

Initially, I and O for all nodes will be empty sets. We start processing at the entry node, with S containing just the empty stack. When we’re done, each node will have their appropriate sets I and O.

So now we have the theory pretty much in place. We still need a way to dermine the potential stack state(s) at the place in the code where it matters, though: at the call instruction for the recursive method call. It’s very easy at this point – we already have all the machinery we need. Assuming that a recursive call happens as the k‘th instruction in some node, all we have to do is compose the function h(s) = fk-1(...f1(f0(s))), alternatively h = fk-1 o ... o f1 o f0. Mapping h onto the stack elements of the node’s I set, we get a set C of stack elements at the call site. Now we pop off any “regular” argument values for the method call off the stacks in C to produce a new set C'. Finally we verify that for all elements in C', we have a this reference at the top of the stack.

Now we should be in good shape to tackle the practicalities of our implementation. One thing we obviously need is a data type to represent our evaluation stack – after all, our description above is littered with stack instances. The stack can be really simple, in that it only needs to distinguish between two kinds of values: this and anything else. So it’s easy, we’ll just use the plain ol’ Stack<bool>, right? Unfortunately we can’t, since Stack<bool> is mutable (in that push and pop mutates the stack they operate on). That’s definitely not going to work. When producing the stack instances in O, we don’t want the g function to mutate the actual stack instances in I in the process. We might return later on with stack instances we’ll want to compare to the instances in I, so we need to preserve those as-is. Hence we need an immutable data structure. So we should use ImmutableStack<bool> from the Immutable Collections, right? I wish! Unfortunately, ImmutableStack<bool>.Equals has another problem (which Stack<bool> also has) – it implements reference equality, whereas we really need value equality (so that two distinct stack instances containing the same values are considered equal). So I ended up throwing together my own EvalStack class instead, highly unoptimized and probably buggy, but still serving our needs.


class EvalStack
{
private const char YesThis = '1';
private const char NotThis = '0';
private readonly string _;
private EvalStack(string s) { _ = s; }
public EvalStack() : this("") {}
public bool Peek()
{
if (IsEmpty)
{
throw new Exception("Cannot Peek an empty stack.");
}
return _[0] == YesThis;
}
public EvalStack Pop()
{
if (IsEmpty)
{
throw new Exception("Cannot Pop an empty stack.");
}
return new EvalStack(_.Substring(1));
}
public EvalStack Push(bool b)
{
char c = b ? YesThis : NotThis;
return new EvalStack(c + _);
}
public bool IsEmpty
{
get { return _.Length == 0; }
}
public override bool Equals(object that)
{
return Equals(that as EvalStack);
}
public bool Equals(EvalStack that)
{
return _.Equals(that._);
}
public override int GetHashCode()
{
return (_ != null ? _.GetHashCode() : 0);
}
public override string ToString()
{
return "[" + _ + "]";
}
}

view raw

EvalStack.cs

hosted with ❤ by GitHub

I’m particularly happy about the way the code for the ToString method ended up.

Now that we have a data structure for the evaluation stack, we can proceed to look at how to implement the functions f : S -> S' associated with each instruction in the method body. At first glance, this might seem like a gargantuan task – in fact, panic might grip your heart – as there are rather a lot of different opcodes in IL. I haven’t bothered to count them, but it’s more than 200. Luckily, we don’t have to implement unique functions for all of them. Instead, we’ll treat groups of them in bulk. At a high level, we’ll distinguish between three groups of instructions: generators, propagators and consumers.

The generators are instructions that conjure up this references out of thin air and push them onto the stack. The prime example is ldarg.0 which loads the first argument to the method and pushes it. For instance methods, the first argument is always this. In addition to ldarg.0, there are a few other instructions that in principle could perform the same task (such as ldarg n).

The propagators are instructions that can derive or pass on a this reference from an existing this reference. The dup instruction is such an instruction. It duplicates whatever is currently at the top of the stack. If that happens to be a this reference, the result will be this references at the two topmost locations in the stack.

The vast majority of the instructions, however, are mere consumers in our scenario. They might vary in their exact effect on the stack (how many values they pop and push), but they’ll never produce a this reference. Hence we can treat them generically, as long as we know the number of pops and pushes for each – we’ll just pop values regardless of whether or not there they are this references, and we’ll push zero or more non-this values onto the stack.

At this point, it’s worth considering the soundness of our approach. In particular, what happens if I fail to identify a generator or a propagator? Will the resulting code still be correct? Yes! Why? Because we’re always erring on the conservative side. As long as we don’t falsely produce a this reference that shouldn’t be there, we’re good. Failing to produce a this reference that should be there is not much of a problem, since the worst thing that can happen is that we miss a tail call that could have been rewritten. For instance, I’m not even bothering to try to track this references that are written to fields with stflda (for whatever reason!) and then read back and pushed onto the stack with ldflda.

Does this mean TailCop is safe to use and you should apply it to your business critical applications to benefit from the immense speed benefits and reduced risk for stack overflows that stems from rewriting recursive calls to loops? Absolutely not! Are you crazy? Expect to find bugs, oversights and gaffes all over the place. In fact, TailCop is very likely to crash when run on code examples that deviate much at all from the simplistic examples found in this post. All I’m saying is that the principles should be sound.

Mono.Cecil does try to make our implementation task as simple as possible, though. The OpCode class makes it almost trivial to write f-functions for most consumers – which is terrific news, since so many instructions end up in that category. Each OpCode in Mono.Cecil knows how many values it pops and pushes, and so we can easily compose each f from the primitive functions pop and push. For instance, assume we want to create the function fadd for the add instruction. Since Mono.Cecil is kind enough to tell us that add pops two values and pushes one value, we’ll use that information to compose the function fadd(s) = push(*non-this*, pop(pop(s))).

Here’s how we compose such f-functions for consumer instructions in TailCop:


public Func<EvalStack, EvalStack> CreateConsumerF(int pops, int pushes)
{
Func<EvalStack, EvalStack> pop = stack => stack.Pop();
Func<EvalStack, EvalStack> push = stack => stack.Push(false);
Func<EvalStack, EvalStack> result = stack => stack;
for (int i = 0; i < pops; i++)
{
var fresh = result;
result = stack => pop(fresh(stack));
}
for (int i = 0; i < pushes; i++)
{
var fresh = result;
result = stack => push(fresh(stack));
}
return result;
}

Notice the two fresh variables, which are there to avoid problems related to closure modification. Eric Lippert explains the problem here and here. TL;DR is: we need a fresh variable to capture each intermediate result closure.

We’ll call the CreateConsumerF method from the general CreateF method which also handles generators and propagators. The simplest possible version looks like this:


private Func<EvalStack, EvalStack> CreateF(Instruction insn)
{
var op = insn.OpCode;
if (op == OpCodes.Ldarg_0)
{
// Prototypical *this* generator!!
return stack => stack.Push(true);
}
if (op == OpCodes.Dup)
{
// Prototypical *this* propagator!!
return stack => stack.Push(stack.Peek());
}
return CreateConsumerF(insn);
}

view raw

CreateF.cs

hosted with ❤ by GitHub

You’ll note that I’ve only included a single generator and a single propagator! I might add more later on. The minimal CreateF version is sufficient to handle our na├»ve Add method though.

Now that we have a factory that produces f-functions for us, we’re all set to compose g-functions for each node in the CFG.


private Func<EvalStack, EvalStack> CreateG()
{
return CreateComposite(_first, _last);
}
private Func<EvalStack, EvalStack> CreateComposite(
Instruction first,
Instruction last)
{
Instruction insn = first;
Func<EvalStack, EvalStack> fun = stack => stack;
while (insn != null)
{
var f = CreateF(insn);
var fresh = fun;
fun = stack => f(fresh(stack));
insn = (insn == last) ? null : insn.Next;
}
return fun;
}

view raw

CreateG.cs

hosted with ❤ by GitHub

Once we have the g-function for each node, we can proceed to turn the pseudocode for processing nodes into actual C# code. In fact the C# code looks remarkably similar to the pseudocode.


public void Process(ImmutableHashSet<EvalStack> set)
{
var x = set.Except(_I);
if (!x.IsEmpty)
{
_I = _I.Union(x);
_O = _I.Select(s => G(s)).ToImmutableHashSet();
foreach (var n in _targets)
{
n.Process(_O);
}
}
}

view raw

Node.Process.cs

hosted with ❤ by GitHub

We process the nodes in the CFG, starting at the root node, until the I-sets of input stacks and the O-sets of output stacks stabilize. At that point, we can determine the stack state (with respect to this references) for any given instruction in the method – including for any recursive method call. We determine whether or not it is safe to rewrite a recursive call to a loop like this:


public bool SafeToRewrite(Instruction call,
Dictionary<Instruction, Node> map)
{
var insn = call;
while (!map.Keys.Contains(insn))
{
insn = insn.Previous;
}
var node = map[insn];
var stacks = node.GetPossibleStacksAt(call);
var callee = (MethodReference)call.Operand;
var pops = callee.Parameters.Count;
return stacks.Select(s =>
{
var st = s;
for (int i = 0; i < pops; i++)
{
st = st.Pop();
}
return st;
}).All(s => s.Peek());
}

We find the node that the call instruction belongs to, find the possible stack states at the call site, pop off any values intended to be passed as arguments to the method, and verify that we find a this reference at the top of each stack. Simple! To find the possible stack states, we need to compose the h-function for the call, but that’s easy at this point.


ImmutableHashSet<EvalStack> GetPossibleStacksAt(Instruction call)
{
var h = CreateH(call);
return _I.Select(h).ToImmutableHashSet();
}
Func<EvalStack, EvalStack> CreateH(Instruction call)
{
return CreateComposite(_first, call.Previous);
}

view raw

CreateH.cs

hosted with ❤ by GitHub

And with that, we’re done. Does it work? It works on my machine. You’ll have to download TailCop and try for yourself.


Chasing your tail with bytecode manipulation

Last week I was at the TDC conference in Trondheim to do a talk entitled “Bytecode for beginners”. In one of my demos, I showed how you might do a limited form of tail call elimination using bytecode manipulation. To appreciate what (recursive) tail calls are and why you might want to eliminate them, consider the following code snippet:


static int Add(int x, int y)
{
return x > 0 ? Add(x 1, y + 1) : y;
}

view raw

Add.cs

hosted with ❤ by GitHub

As you can see, it’s a simple recursive algorithm to add two (non-negative) integers together. Yes, I am aware that there is a bytecode operation available for adding integers, but let’s forget about such tedious practicalities for a while. It’s just there to serve as a minimal example of a recursive algorithm. Bear with me.

The algorithm exploits two simple facts:

1. Addition is trivial to do if one of the numbers is zero.
2. We can work our way to trivial case incrementally.

So basically we just decrement x and increment y until we run out of x, and then all we have left is y. Pretty simple.

This algorithm works really well for lots of integers, but the physical world of the computer puts a limit on how big x can be. The problem is this: each time we call Add, the .NET runtime will allocate a bit of memory known as a stack frame for the execution of the method. To illustrate, consider the addition of two small numbers, 6 + 6. If we imagine the stack frames -uh- stacked on top of each other, it might look something like this:

add-call-stack

So we allocate a total of 7 stack frames to perform the calculation. The .NET runtime will handle that just fine, but 6 is a pretty small number. In general we allocate x + 1 stack frames, and at some point that becomes a problem. The .NET runtime can only accommodate so many stack frames before throwing in the towel (where the towel takes on the physical form of a StackOverflowException).

It’s worth noting, though, that all we’re really doing in each of the stack frames leading up to Add(0, 12) is wait around for the result of the next invocation of Add to finish, and when we get that result, that’s immediately what is returned as result from the current stack frame.

This is what is known as a tail recursive call. In general, a tail call is any call in tail position, that is, any call that happens as the last operation of a method. It may be a call to the same method (as in our example) or it may be a call to some other method. In either case, we’re making a method call at a point in time where we don’t have much need for the old stack frame anymore.

It should come as no surprise, therefore, that clever people have figured out that in principle, we don’t need a brand new stack frame for each tail call. Instead, we can reuse the old one, slightly modified, and simply jump to the appropriate method. This is known as tail call optimization or tail call elimination. You can find all the details in a classic paper by the eminent Guy L Steele Jr. The paper has the impressive title DEBUNKING THE “EXPENSIVE PROCEDURE CALL” MYTH or PROCEDURE CALL IMPLEMENTATIONS CONSIDERED HARMFUL or LAMBDA: THE ULTIMATE GOTO, but is affectionately known as simply Lambda: The Ultimate GOTO (probably because overly long and complex titles are considered harmful).

In this blog post, we’ll implement a poor man’s tail call elimination by transforming recursive tail calls into loops. Instead of actually making a recursive method call, we’ll just jump to the start of the method – with the arguments to the method set to the appropriate values. That’s actually remarkably easy to accomplish using bytecode rewriting with the ever-amazing Mono.Cecil library. Let’s see how we can do it.

First, we’ll take a look at the original bytecode, the one that does the recursive tail call.


.method private hidebysig static
int32 Add(
int32 x,
int32 y
) cil managed
{
// Code size 17 (0x11)
.maxstack 8
IL_0000: ldarg.0
IL_0001: brtrue.s IL_0005
IL_0003: ldarg.1
IL_0004: ret
IL_0005: ldarg.0
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: ldarg.1
IL_0009: ldc.i4.1
IL_000a: add
IL_0012: call int32 Program::Add(int32,int32)
IL_0013: ret
} // end of method Program::Add

view raw

Add.il

hosted with ❤ by GitHub

So the crucial line is at IL_0012, that’s where the recursive tail call happens. We’ll eliminate the call instruction and replace it with essentially a goto. In terms of IL we’ll use a br.s opcode (where “br” means branch), with the first instruction (IL_0000) as target. Prior to jumping to IL_0000, we need to update the argument values for the method. The way method calls work in IL is that the argument values have been pushed onto the execution stack prior to the call, with the first argument deepest down in the stack, and the last argument at the top. Therefore we already have the necessary values on the execution stack, it is merely a matter of writing them to the right argument locations. All we need to do is starg 1 and starg 0 in turn, to update the value of y and x respectively.


.method private hidebysig static
int32 Add (
int32 x,
int32 y
) cil managed
{
// Method begins at RVA 0x2088
// Code size 18 (0x12)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.0
IL_0002: bgt.s IL_0006
IL_0004: ldarg.1
IL_0005: ret
IL_0006: ldarg.0
IL_0007: ldc.i4.1
IL_0008: sub
IL_0009: ldarg.1
IL_000a: ldc.i4.1
IL_000b: add
IL_0010: starg 1
IL_0011: starg 0
IL_0012: br.s IL_0000
} // end of method Program::Add

view raw

AddLoop.il

hosted with ❤ by GitHub

If we reverse engineer this code into C# using a tool like ILSpy, we’ll see that we’ve indeed produced a loop.


private static int Add(int x, int y)
{
while (x != 0)
{
int arg_0F_0 = x 1;
y++;
x = arg_0F_0;
}
return y;
}

You may wonder where the arg_0F_0 variable comes from; I do too. ILSpy made it up for whatever reason. There’s nothing in the bytecode that mandates a local variable, but perhaps it makes for simpler reverse engineering.

Apart from that, we note that the elegant recursive algorithm is gone, replaced by a completely pedestrian and mundane one that uses mutable state. The benefit is that we no longer run the risk of running out of stack frames – the reverse engineered code never allocates more than a single stack frame. So that’s nice. Now if we could do this thing automatically, we could have the best of both worlds: we could write our algorithms in the recursive style, yet have them executed as loops. That’s where TailCop comes in.

TailCop is a simple command line utility I wrote that rewrites some tail calls into loops, as in the example we’ve just seen. Why some and not all? Well, first of all, rewriting to loops doesn’t help much for mutually recursive methods, say. So we’re restricted to strictly self-recursive tail calls. Furthermore, we have to be careful with dynamic dispatch of method calls. To keep TailCop as simple as possible, I evade that problem altogether and don’t target instance methods at all. Instead, TailCop will only rewrite tail calls for static methods. (Obviously, you should feel free, even encouraged, to extend TailCop to handle benign cases of self-recursive instance methods, i.e. cases where the method is always invoked on the same object. Update: I’ve done it myself.)

The first thing we need to do is find all the recursive tail calls.


private IList<Instruction> FindTailCalls(MethodDefinition method)
{
var calls = new List<Instruction>();
foreach (var insn in method.Body.Instructions)
{
if (insn.OpCode == OpCodes.Call)
{
var methodRef = (MethodReference)insn.Operand;
if (methodRef == method)
{
if (insn.Next != null && insn.Next.OpCode == OpCodes.Ret)
{
calls.Add(insn);
}
}
}
}
return calls;
}

So as you can see, there’s nothing mystical going on here. We’re simply selecting call instructions from method bodies where the invoked method is the same as the method we’re in (so it’s recursive) and the following instruction is a ret instruction.

The second (and final) thing is to do the rewriting described above.


private void TamperWith(
MethodDefinition method,
IEnumerable<Instruction> calls)
{
foreach (var call in calls)
{
var il = method.Body.GetILProcessor();
int counter = method.Parameters.Count;
while (counter > 0)
{
var starg = il.Create(OpCodes.Starg, counter);
il.InsertBefore(call, starg);
}
var start = method.Body.Instructions[0];
var loop = il.Create(OpCodes.Br_S, start);
il.InsertBefore(call, loop);
il.Remove(call.Next); // Ret
il.Remove(call);
}
}

view raw

TamperWith.cs

hosted with ❤ by GitHub

As you can see, we consistently inject new instructions before the recursive call. There are three things to do:

1. Loop to update the argument values using starg instructions.
2. Insert the br.s instruction that will jump to the start of the method.
3. Remove the recursive call instruction as well as the ret that follows immediately after it.

That’s all there is to it. If you run TailCop on an assembly that contains the tail recursive Add method, it will produce a new assembly where the Add method contains a loop instead. Magic!

To convince ourselves (or at least make it plausible) that TailCop works in general, not just for the Add example, let’s consider another example. It looks like this:


private static int Sum(List<int> numbers, int result = 0)
{
int size = numbers.Count();
if (size == 0)
{
return result;
}
int last = size 1;
int n = numbers[last];
numbers.RemoveAt(last);
return Sum(numbers, n + result);
}

view raw

Sum.cs

hosted with ❤ by GitHub

So once again we have a tail recursive algorithm, this time to compute the sum of numbers in a list. It would be sort of nice and elegant if it were implemented in a functional language, but we’ll make do. The idea is to exploit two simple facts about sums of lists of integers:

1. The sum of the empty list is zero.
2. The sum of the non-empty list is the value of the first element plus the sum of the rest of the list.

The only complicating detail is that we use an accumulator (the result variable) in order to make the implementation tail-recursive. That is, we pass the partial result of summing along until we run out of numbers to sum, and then the result is complete. But of course, this algorithm is now just a susceptible to stack overflows as the recursive Add method was. And so we run TailCop on it to produce this instead:


private static int Sum(List<int> numbers, int result = 0)
{
while (true)
{
int num = numbers.Count<int>();
if (num == 0)
{
break;
}
int index = num 1;
int num2 = numbers[index];
numbers.RemoveAt(index);
List<int> arg_27_0 = numbers;
result = num2 + result;
numbers = arg_27_0;
}
return result;
}

And we’re golden. You’ll note that ILSpy is just about as skilled at naming things as that guy you inherited code from last month, but there you go. You’re not supposed to look at reverse engineered code, you know.