Skip to content

Commit

Permalink
Update documentation [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
pardeike-bot committed Sep 5, 2020
1 parent e515217 commit 855cf78
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 11 deletions.
16 changes: 8 additions & 8 deletions docs/articles/patching-transpiler-codes.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@
<h1 id="patching">Patching</h1>

<h2 id="codeinstruction">CodeInstruction</h2>
<p>The workhorse of a transpiler is the type <strong>CodeInstruction</strong>.</p>
<p><code>CodeInstruction</code> is an abstraction around the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit">Emit methods</a> in C#. The idea is to abstract most of the specific things you can do to help multiple mods that patch and manipulate the same method. As such, specific instructions like &quot;jump 4 instructions forward&quot; are not possible and instead there are a couple of concepts that differ from the arguments that you know from the ordinary Emit arguments.</p>
<p>Every transpiler will receive a list of <code>CodeInstruction</code> and is expected to return a modified list of <code>CodeInstruction</code>. In addition, you can inject an <code>ILGenerator</code> into the transpiler to create one or more <code>Label</code> and instances of <code>LocalBuilder</code> which represent local variables.</p>
<p>The workhorse of a transpiler is the type <a href="../api/HarmonyLib.CodeInstruction.html">CodeInstruction</a>.</p>
<p><code>CodeInstruction</code> is an abstraction around the .NET <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit">Emit namespace</a>. The idea is to abstract most of the specific things you can do in order to help multiple mods that patch/manipulate the same method to coexist. As such, specific instructions like &quot;jump 4 instructions forward&quot; are not possible and instead there are a couple of concepts that differ from the arguments that you know from the ordinary Emit arguments.</p>
<p>Every transpiler will receive a list of <code>CodeInstruction</code> and is expected to return a modified list of <code>CodeInstruction</code>. In addition, you can inject an <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.ilgenerator">ILGenerator</a> into the transpiler to create one or more <code>Label</code> and instances of <code>LocalBuilder</code> which represent local variables.</p>
<p>Most arguments from <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.ilgenerator.emit">Emit()</a> are used in the same way:</p>
<ul>
<li>Emit takes an <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcode">OpCode</a> and so does CodeInstruction</li>
Expand All @@ -88,24 +88,24 @@ <h2 id="codeinstruction">CodeInstruction</h2>
</ul>
<p>Some things though will be restricted:</p>
<ul>
<li>Operands of jumps cannot be numeric -&gt; use <code>Label</code> instead</li>
<li>Operands of jumps cannot be numeric, use <code>Label</code> instead</li>
<li><code>SignatureHelper</code> support is experimental at best</li>
<li>You should avoid using indices when referring to local variables</li>
</ul>
<p>In general, it is advinced to reuse and to copy existing operands for things like labels and local variables. Search for a significant and unique location in the existing codes and grab the operand from there. This will allow you to refer to local variables and labels in a change-resistant way.</p>
<h4 id="local-variables">Local variables</h4>
<p>The instructions that your transpiler will receive will contain existing local variables and Harmony will not alter the original operands of instructions. This means that you need to be prepared to deal with instructions that refer to local variables either with a number (like &quot;2nd local variable&quot;) or with a <code>LocalBuilder</code> object. A LocalBuilder object is an opaque representation of a local variable and you can create a new one using the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.ilgenerator">ILGenerator</a>s <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.ilgenerator.declarelocal">DeclareLocal</a> method or copy the operand of an existing instruction.</p>
<p>The instructions that your transpiler will receive will contain existing local variables and Harmony will not alter the original operands of instructions. This means that you need to be prepared to deal with instructions that refer to local variables either with a number (like &quot;2nd local variable&quot;) or with a <code>LocalBuilder</code> object. A LocalBuilder object is an opaque representation of a local variable and you can create a new one using the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.ilgenerator.declarelocal">DeclareLocal</a> method for <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.ilgenerator">ILGenerator</a> or copy the operand of an existing instruction.</p>
<h4 id="labels">Labels</h4>
<p>All original labels (or those generated by a previous transpiling) are represented by a <a href="https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.ilgenerator.definelabel">Label</a> object. They are used in operands of a <code>CodeInstruction</code> or in the <code>labels</code> field (of type <code>Label[]</code>) of it. When you want to create a jump, you specific the jump Opcode and the label as the operand. Then you append the label to the destinations labels.</p>
<h4 id="trycatch-boundaries">Try/catch boundaries</h4>
<p>When constructing methods with instructions, you need to specify the exception block boundaries. Harmony will automatically create the necessary meta information from them. Use the <code>blocks</code> field of an instruction (of type <code>ExceptionBlock[]</code>) to mark the different types of boundaries. They are named in correspondence to the actual names.</p>
<h3 id="convenience-methods">Convenience methods</h3>
<h4 id="convenience-methods">Convenience methods</h4>
<p>To create, search and compare instructions, Harmony defines a number of extension methods on <code>CodeInstruction</code>. Those methods make it easier to compare operands (which are defined as type <code>object</code>) with specific values as well as to find specific instructions easier.</p>
<p>You will find more information abou those methods in the <a href="../api/HarmonyLib.CodeInstructionExtensions.html">API documentation</a>.</p>
<h3 id="pitfalls">Pitfalls</h3>
<h4 id="pitfalls">Pitfalls</h4>
<p>A common error is to remove instructions that contain labels or exception blocks without dealing with the corresponding pair. You end up with a dynamic method compile error because an instruction will want to jump to a label that is not assigned to any other instruction. Another common case is if you copy an existing instruction and thus copy the labels and blocks fields with it. You end up with multiple defined labels/block boundaries. Makes you you clear those or use proper duplication.</p>
<p>To avoid such cases, it is important to keep an eye on the <code>labels</code> and <code>blocks</code> fields. CIL is quite sensitive to undefined or duplicate labels. Normally it is enough to move the contents of those fields around if you insert new instructions. One of the typical cases is inserting a new instruction at a place and pushing the old one one index up thus moving the labels on that instruction with it. Moving the labels/blocks from the old instruction to the newly inserted one usually solves the problem.</p>
<p>In general, it is useful to turn the Harmony debug log output on. It will contain all your generated instructions so you can verify the error more informed.</p>
<p>In general, it is useful to turn the Harmony debug log output on (set <code>Harmony.DEBUG = true</code> or use <code>[HarmonyDebug]</code>). The log will contain all your generated instructions, labels and blocks so you can verify the error more informed.</p>
</article>
</div>

Expand Down
2 changes: 1 addition & 1 deletion docs/articles/toc.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<a href="patching-transpiler.html" name="" title="Transpiler">Transpiler</a>
</li>
<li>
<a href="patching-transpiler-codes.html" name="" title="Transpiler: using CodeInstruction">Transpiler: using CodeInstruction</a>
<a href="patching-transpiler-codes.html" name="" title="Transpiler - CodeInstruction">Transpiler - CodeInstruction</a>
</li>
<li>
<a href="patching-finalizer.html" name="" title="Finalizer">Finalizer</a>
Expand Down
4 changes: 2 additions & 2 deletions docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@
"output": {
".html": {
"relative_path": "articles/patching-transpiler-codes.html",
"hash": "7mMchj5rTMpa3bS26tYwgQ=="
"hash": "I/Hlg4E2fVv5TRQW6IjF9w=="
}
},
"is_incremental": false,
Expand Down Expand Up @@ -957,7 +957,7 @@
"output": {
".html": {
"relative_path": "articles/toc.html",
"hash": "KTMk53V7gXSHtVaP4VhEfg=="
"hash": "g8zQLUDnUCxmmpkZzPRa7Q=="
}
},
"is_incremental": false,
Expand Down

0 comments on commit 855cf78

Please sign in to comment.