aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bf/bf.rs.html184
-rw-r--r--src/fib/fib.rs.html2
-rw-r--r--src/juicebox_asm/insn/cmp.rs.html16
3 files changed, 172 insertions, 30 deletions
diff --git a/src/bf/bf.rs.html b/src/bf/bf.rs.html
index b29403b..556b131 100644
--- a/src/bf/bf.rs.html
+++ b/src/bf/bf.rs.html
@@ -337,7 +337,72 @@
<a href="#336" id="336">336</a>
<a href="#337" id="337">337</a>
<a href="#338" id="338">338</a>
-<a href="#339" id="339">339</a></pre></div><pre class="rust"><code><span class="doccomment">//! Brainfuck VM.
+<a href="#339" id="339">339</a>
+<a href="#340" id="340">340</a>
+<a href="#341" id="341">341</a>
+<a href="#342" id="342">342</a>
+<a href="#343" id="343">343</a>
+<a href="#344" id="344">344</a>
+<a href="#345" id="345">345</a>
+<a href="#346" id="346">346</a>
+<a href="#347" id="347">347</a>
+<a href="#348" id="348">348</a>
+<a href="#349" id="349">349</a>
+<a href="#350" id="350">350</a>
+<a href="#351" id="351">351</a>
+<a href="#352" id="352">352</a>
+<a href="#353" id="353">353</a>
+<a href="#354" id="354">354</a>
+<a href="#355" id="355">355</a>
+<a href="#356" id="356">356</a>
+<a href="#357" id="357">357</a>
+<a href="#358" id="358">358</a>
+<a href="#359" id="359">359</a>
+<a href="#360" id="360">360</a>
+<a href="#361" id="361">361</a>
+<a href="#362" id="362">362</a>
+<a href="#363" id="363">363</a>
+<a href="#364" id="364">364</a>
+<a href="#365" id="365">365</a>
+<a href="#366" id="366">366</a>
+<a href="#367" id="367">367</a>
+<a href="#368" id="368">368</a>
+<a href="#369" id="369">369</a>
+<a href="#370" id="370">370</a>
+<a href="#371" id="371">371</a>
+<a href="#372" id="372">372</a>
+<a href="#373" id="373">373</a>
+<a href="#374" id="374">374</a>
+<a href="#375" id="375">375</a>
+<a href="#376" id="376">376</a>
+<a href="#377" id="377">377</a>
+<a href="#378" id="378">378</a>
+<a href="#379" id="379">379</a>
+<a href="#380" id="380">380</a>
+<a href="#381" id="381">381</a>
+<a href="#382" id="382">382</a>
+<a href="#383" id="383">383</a>
+<a href="#384" id="384">384</a>
+<a href="#385" id="385">385</a>
+<a href="#386" id="386">386</a>
+<a href="#387" id="387">387</a>
+<a href="#388" id="388">388</a>
+<a href="#389" id="389">389</a>
+<a href="#390" id="390">390</a>
+<a href="#391" id="391">391</a>
+<a href="#392" id="392">392</a>
+<a href="#393" id="393">393</a>
+<a href="#394" id="394">394</a>
+<a href="#395" id="395">395</a>
+<a href="#396" id="396">396</a>
+<a href="#397" id="397">397</a>
+<a href="#398" id="398">398</a>
+<a href="#399" id="399">399</a>
+<a href="#400" id="400">400</a>
+<a href="#401" id="401">401</a>
+<a href="#402" id="402">402</a>
+<a href="#403" id="403">403</a>
+<a href="#404" id="404">404</a></pre></div><pre class="rust"><code><span class="doccomment">//! Brainfuck VM.
//!
//! This example implements a simple
//! [brainfuck](https://en.wikipedia.org/wiki/Brainfuck) interpreter
@@ -514,11 +579,20 @@
<span class="comment">// Use callee saved registers to hold vm state, such that we don't need to
// save any state before calling out to putchar.
</span><span class="kw">let </span>dmem_base = Reg64::rbx;
- <span class="kw">let </span>dmem_idx = Reg64::r12;
+ <span class="kw">let </span>dmem_size = Reg64::r12;
+ <span class="kw">let </span>dmem_idx = Reg64::r13;
<span class="kw">let </span><span class="kw-2">mut </span>asm = Asm::new();
+
+ <span class="comment">// Save callee saved registers before we tamper them.
+ </span>asm.push(dmem_base);
+ asm.push(dmem_size);
+ asm.push(dmem_idx);
+
<span class="comment">// Move data memory pointer (argument on jit entry) into correct register.
</span>asm.mov(dmem_base, Reg64::rdi);
+ <span class="comment">// Move data memory size into correct register.
+ </span>asm.mov(dmem_size, Reg64::rsi);
<span class="comment">// Clear data memory index.
</span>asm.xor(dmem_idx, dmem_idx);
@@ -526,17 +600,28 @@
// given '[]' pair.
</span><span class="kw">let </span><span class="kw-2">mut </span>label_stack = Vec::new();
+ <span class="comment">// Label to jump to when a data pointer overflow is detected.
+ </span><span class="kw">let </span><span class="kw-2">mut </span>oob_ov = Label::new();
+ <span class="comment">// Label to jump to when a data pointer underflow is detected.
+ </span><span class="kw">let </span><span class="kw-2">mut </span>oob_uv = Label::new();
+
<span class="comment">// Generate code for each instruction in the bf program.
</span><span class="kw">let </span><span class="kw-2">mut </span>pc = <span class="number">0</span>;
<span class="kw">while </span>pc &lt; vm.imem.len() {
<span class="kw">match </span>vm.imem[pc] {
<span class="string">'&gt;' </span>=&gt; {
- <span class="comment">// TODO: generate runtime bounds check.
- </span>asm.inc(dmem_idx);
+ asm.inc(dmem_idx);
+
+ <span class="comment">// Check for data pointer overflow and jump to error handler if needed.
+ </span>asm.cmp(dmem_idx, dmem_size);
+ asm.jz(<span class="kw-2">&amp;mut </span>oob_ov);
}
<span class="string">'&lt;' </span>=&gt; {
- <span class="comment">// TODO: generate runtime bounds check.
- </span>asm.dec(dmem_idx);
+ <span class="comment">// Check for data pointer underflow and jump to error handler if needed.
+ </span>asm.test(dmem_idx, dmem_idx);
+ asm.jz(<span class="kw-2">&amp;mut </span>oob_uv);
+
+ asm.dec(dmem_idx);
}
<span class="string">'+' </span>=&gt; {
<span class="comment">// Apply optimization to fold consecutive '+' instructions to a
@@ -546,10 +631,8 @@
<span class="number">1 </span>=&gt; {
asm.inc(Mem8::indirect_base_index(dmem_base, dmem_idx));
}
- cnt <span class="kw">if </span>cnt &lt;= i8::MAX <span class="kw">as </span>usize =&gt; {
- <span class="comment">// For add m64, imm8, the immediate is sign-extend and
- // hence treated as signed.
- </span>asm.add(
+ cnt <span class="kw">if </span>cnt &lt;= u8::MAX <span class="kw">as </span>usize =&gt; {
+ asm.add(
Mem8::indirect_base_index(dmem_base, dmem_idx),
Imm8::from(cnt <span class="kw">as </span>u8),
);
@@ -569,10 +652,8 @@
<span class="number">1 </span>=&gt; {
asm.dec(Mem8::indirect_base_index(dmem_base, dmem_idx));
}
- cnt <span class="kw">if </span>cnt &lt;= i8::MAX <span class="kw">as </span>usize =&gt; {
- <span class="comment">// For sub m64, imm8, the immediate is sign-extend and
- // hence treated as signed.
- </span>asm.sub(
+ cnt <span class="kw">if </span>cnt &lt;= u8::MAX <span class="kw">as </span>usize =&gt; {
+ asm.sub(
Mem8::indirect_base_index(dmem_base, dmem_idx),
Imm8::from(cnt <span class="kw">as </span>u8),
);
@@ -639,30 +720,48 @@
</span>pc += <span class="number">1</span>;
}
- <span class="comment">// Return from bf program.
- </span>asm.ret();
+ <span class="kw">let </span><span class="kw-2">mut </span>ret_epilogue = Label::new();
+
+ <span class="comment">// Successful return from bf program.
+ </span>asm.xor(Reg64::rax, Reg64::rax);
+ asm.bind(<span class="kw-2">&amp;mut </span>ret_epilogue);
+ <span class="comment">// Restore callee saved registers before returning from jit.
+ </span>asm.pop(dmem_idx);
+ asm.pop(dmem_size);
+ asm.pop(dmem_base);
+ asm.ret();
+
+ <span class="comment">// Return because of data pointer overflow.
+ </span>asm.bind(<span class="kw-2">&amp;mut </span>oob_ov);
+ asm.mov(Reg64::rax, Imm64::from(<span class="number">1</span>));
+ asm.jmp(<span class="kw-2">&amp;mut </span>ret_epilogue);
+
+ <span class="comment">// Return because of data pointer underflow.
+ </span>asm.bind(<span class="kw-2">&amp;mut </span>oob_uv);
+ asm.mov(Reg64::rax, Imm64::from(<span class="number">2</span>));
+ asm.jmp(<span class="kw-2">&amp;mut </span>ret_epilogue);
<span class="kw">if </span>!label_stack.is_empty() {
<span class="macro">panic!</span>(<span class="string">"encountered un-balanced brackets, left-over '[' after jitting bf program"</span>)
}
- <span class="comment">// Execute jitted bf program.
+ <span class="comment">// Get function pointer to jitted bf program.
</span><span class="kw">let </span><span class="kw-2">mut </span>rt = Runtime::new();
- <span class="kw">let </span>bf_entry = <span class="kw">unsafe </span>{ rt.add_code::&lt;<span class="kw">extern </span><span class="string">"C" </span><span class="kw">fn</span>(<span class="kw-2">*mut </span>u8)&gt;(asm.into_code()) };
- bf_entry(<span class="kw-2">&amp;mut </span>vm.dmem <span class="kw">as </span><span class="kw-2">*mut </span>u8);
+ <span class="kw">let </span>bf_entry = <span class="kw">unsafe </span>{ rt.add_code::&lt;<span class="kw">extern </span><span class="string">"C" </span><span class="kw">fn</span>(<span class="kw-2">*mut </span>u8, usize) -&gt; u64&gt;(asm.into_code()) };
+
+ <span class="comment">// Execute jitted bf program.
+ </span><span class="kw">match </span>bf_entry(<span class="kw-2">&amp;mut </span>vm.dmem <span class="kw">as </span><span class="kw-2">*mut </span>u8, vm.dmem.len()) {
+ <span class="number">0 </span>=&gt; {}
+ <span class="number">1 </span>=&gt; <span class="macro">panic!</span>(<span class="string">"oob: data pointer overflow"</span>),
+ <span class="number">2 </span>=&gt; <span class="macro">panic!</span>(<span class="string">"oob: data pointer underflow"</span>),
+ <span class="kw">_ </span>=&gt; <span class="macro">unreachable!</span>(),
+ }
}
<span class="comment">// -- MAIN ---------------------------------------------------------------------
</span><span class="kw">fn </span>main() {
- <span class="comment">// https://en.wikipedia.org/wiki/Brainfuck#Adding_two_values
- //let inp = "++&gt;+++++ [&lt;+&gt;-] ++++++++[&lt;++++++&gt;-]&lt;.";
- //println!("add-print-7 (wikipedia.org) - interp");
- //run_interp(inp);
- //println!("add-print-7 (wikipedia.org) - jit");
- //run_jit(inp);
-
- // https://en.wikipedia.org/wiki/Brainfuck#Hello_World!
+ <span class="comment">// https://en.wikipedia.org/wiki/Brainfuck#Hello_World!
</span><span class="kw">let </span>inp = <span class="string">"++++++++[&gt;++++[&gt;++&gt;+++&gt;+++&gt;+&lt;&lt;&lt;&lt;-]&gt;+&gt;+&gt;-&gt;&gt;+[&lt;]&lt;-]&gt;&gt;.&gt;---.+++++++..+++.&gt;&gt;.&lt;-.&lt;.+++.------.--------.&gt;&gt;+.&gt;++."</span>;
<span class="macro">println!</span>(<span class="string">"hello-world (wikipedia.org) - interp"</span>);
run_interp(inp);
@@ -676,4 +775,35 @@
<span class="macro">println!</span>(<span class="string">"hello-world (programmingwiki.de) - jit"</span>);
run_jit(inp);
}
+
+<span class="attr">#[cfg(test)]
+</span><span class="kw">mod </span>test {
+ <span class="kw">use super</span>::<span class="kw-2">*</span>;
+
+ <span class="attr">#[test]
+ </span><span class="kw">fn </span>data_ptr_no_overflow() {
+ <span class="kw">let </span>inp = std::iter::repeat(<span class="string">'&gt;'</span>).take(<span class="number">255</span>).collect::&lt;String&gt;();
+ run_jit(<span class="kw-2">&amp;</span>inp);
+ }
+
+ <span class="attr">#[test]
+ #[should_panic]
+ </span><span class="kw">fn </span>data_ptr_overflow() {
+ <span class="kw">let </span>inp = std::iter::repeat(<span class="string">'&gt;'</span>).take(<span class="number">255 </span>+ <span class="number">1</span>).collect::&lt;String&gt;();
+ run_jit(<span class="kw-2">&amp;</span>inp);
+ }
+
+ <span class="attr">#[test]
+ </span><span class="kw">fn </span>data_ptr_no_underflow() {
+ <span class="kw">let </span>inp = <span class="string">"&gt;&gt;&lt;&lt; &gt;&lt;"</span>;
+ run_jit(inp);
+ }
+
+ <span class="attr">#[test]
+ #[should_panic]
+ </span><span class="kw">fn </span>data_ptr_underflow() {
+ <span class="kw">let </span>inp = <span class="string">"&gt;&gt;&lt;&lt; &gt;&lt; &lt;"</span>;
+ run_jit(<span class="kw-2">&amp;</span>inp);
+ }
+}
</code></pre></div></section></main></body></html> \ No newline at end of file
diff --git a/src/fib/fib.rs.html b/src/fib/fib.rs.html
index 0b7a4bf..32ebea0 100644
--- a/src/fib/fib.rs.html
+++ b/src/fib/fib.rs.html
@@ -124,7 +124,7 @@
<span class="kw">let </span>sum = Reg64::rax;
<span class="kw">let </span>tmp = Reg64::rcx;
- <span class="kw">let </span>prv = Reg64::rbx;
+ <span class="kw">let </span>prv = Reg64::rdx;
asm.mov(tmp, Imm64::from(<span class="number">0</span>));
asm.mov(prv, Imm64::from(<span class="number">1</span>));
diff --git a/src/juicebox_asm/insn/cmp.rs.html b/src/juicebox_asm/insn/cmp.rs.html
index 35bb5b7..166f22f 100644
--- a/src/juicebox_asm/insn/cmp.rs.html
+++ b/src/juicebox_asm/insn/cmp.rs.html
@@ -12,8 +12,14 @@
<a href="#11" id="11">11</a>
<a href="#12" id="12">12</a>
<a href="#13" id="13">13</a>
-<a href="#14" id="14">14</a></pre></div><pre class="rust"><code><span class="kw">use </span><span class="kw">super</span>::Cmp;
-<span class="kw">use crate</span>::{Asm, Imm16, Imm8, Mem16, Mem8};
+<a href="#14" id="14">14</a>
+<a href="#15" id="15">15</a>
+<a href="#16" id="16">16</a>
+<a href="#17" id="17">17</a>
+<a href="#18" id="18">18</a>
+<a href="#19" id="19">19</a>
+<a href="#20" id="20">20</a></pre></div><pre class="rust"><code><span class="kw">use </span><span class="kw">super</span>::Cmp;
+<span class="kw">use crate</span>::{Asm, Imm16, Imm8, Mem16, Mem8, Reg64};
<span class="kw">impl </span>Cmp&lt;Mem8, Imm8&gt; <span class="kw">for </span>Asm {
<span class="kw">fn </span>cmp(<span class="kw-2">&amp;mut </span><span class="self">self</span>, op1: Mem8, op2: Imm8) {
@@ -26,4 +32,10 @@
<span class="self">self</span>.encode_mi(<span class="number">0x81</span>, <span class="number">0x7</span>, op1, op2);
}
}
+
+<span class="kw">impl </span>Cmp&lt;Reg64, Reg64&gt; <span class="kw">for </span>Asm {
+ <span class="kw">fn </span>cmp(<span class="kw-2">&amp;mut </span><span class="self">self</span>, op1: Reg64, op2: Reg64) {
+ <span class="self">self</span>.encode_rr(<span class="kw-2">&amp;</span>[<span class="number">0x3b</span>], op1, op2);
+ }
+}
</code></pre></div></section></main></body></html> \ No newline at end of file