Add a fully functioning disassemblere?
This commit is contained in:
22
src/bin/ijvdisasm.rs
Normal file
22
src/bin/ijvdisasm.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
extern crate rustijvm;
|
||||||
|
|
||||||
|
use rustijvm::Disassembly;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
if args.len() < 2 {
|
||||||
|
println!("Usage: {} ijvmfile", args[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ijvmfile = &args[1];
|
||||||
|
|
||||||
|
|
||||||
|
match Disassembly::disassemble_file(ijvmfile) {
|
||||||
|
Err(e) => eprintln!("{}", e),
|
||||||
|
Ok(d) => println!("{}", d),
|
||||||
|
}
|
||||||
|
}
|
||||||
387
src/disassembler.rs
Normal file
387
src/disassembler.rs
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
use block::Block;
|
||||||
|
use ijvmreader::IJVMReader;
|
||||||
|
use binread::{BinRead, BinReadable};
|
||||||
|
use machine::MAGIC_HEADER;
|
||||||
|
use Result;
|
||||||
|
use ops;
|
||||||
|
|
||||||
|
use std::clone::Clone;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
type OpCode = u8;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Instruction {
|
||||||
|
op: OpCode,
|
||||||
|
name: &'static str,
|
||||||
|
params: Vec<i32>,
|
||||||
|
types: Vec<ops::Args>,
|
||||||
|
wide: bool,
|
||||||
|
pos: usize,
|
||||||
|
label: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Instruction {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.label {
|
||||||
|
write!(f, "\nLBL_{}:\n", self.pos)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, " {}", self.name)?;
|
||||||
|
|
||||||
|
for (typ, val) in self.types.iter().zip(&self.params) {
|
||||||
|
match *typ {
|
||||||
|
ops::Args::Label => write!(f, " LBL_{}", val)?,
|
||||||
|
ops::Args::Constant => {
|
||||||
|
if self.op == 0xB6 {
|
||||||
|
write!(f, " func_{}", val)?;
|
||||||
|
} else {
|
||||||
|
write!(f, " CONST_{}", val)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ops::Args::Var => write!(f, " var{}", val)?,
|
||||||
|
_ => write!(f, " {}", val)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "\n")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Constant {
|
||||||
|
value: i32,
|
||||||
|
method: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Constant {
|
||||||
|
fn new(value: i32) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
method: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Method {
|
||||||
|
name: String,
|
||||||
|
pos: usize,
|
||||||
|
args: usize,
|
||||||
|
vars: usize,
|
||||||
|
|
||||||
|
instructions: Vec<Instruction>,
|
||||||
|
labels: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Method {
|
||||||
|
pub fn new(i: i32, pos: usize, args: usize, vars: usize) -> Self {
|
||||||
|
let name;
|
||||||
|
if pos == 0 {
|
||||||
|
name = "main".to_string();
|
||||||
|
} else {
|
||||||
|
name = format!("func_{}", i);
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
pos,
|
||||||
|
args,
|
||||||
|
vars,
|
||||||
|
|
||||||
|
instructions: Vec::new(),
|
||||||
|
labels: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_vars(&mut self) {
|
||||||
|
let max = self.instructions
|
||||||
|
.iter()
|
||||||
|
.filter(|e| !e.types.is_empty())
|
||||||
|
.filter(|e| {
|
||||||
|
match e.types[0] {
|
||||||
|
ops::Args::Var => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|e| e.params[0] )
|
||||||
|
.max();
|
||||||
|
|
||||||
|
if let Some(v) = max {
|
||||||
|
self.vars = v as usize + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_labels(&mut self) {
|
||||||
|
for label in &self.labels {
|
||||||
|
let opt = self.instructions.iter_mut().find(|e| e.pos == *label);
|
||||||
|
if let Some(instruction) = opt {
|
||||||
|
instruction.label = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Method {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut main_var_off = 0;
|
||||||
|
if self.name == "main" {
|
||||||
|
write!(f, ".main\n")?;
|
||||||
|
main_var_off = 1;
|
||||||
|
} else {
|
||||||
|
write!(f, ".method {}(", self.name)?;
|
||||||
|
let mut comma = "";
|
||||||
|
for i in 1..=self.args {
|
||||||
|
write!(f, "{}var{}", comma, i)?;
|
||||||
|
comma = ", ";
|
||||||
|
}
|
||||||
|
write!(f,")\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.vars > 0 {
|
||||||
|
write!(f, "\n.var\n")?;
|
||||||
|
for i in 1..=self.vars {
|
||||||
|
write!(f, " var{}\n", i + self.args - main_var_off)?;
|
||||||
|
}
|
||||||
|
write!(f, ".end-var\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "\n")?;
|
||||||
|
|
||||||
|
for inst in &self.instructions {
|
||||||
|
write!(f, "{}", inst)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if self.name == "main" {
|
||||||
|
write!(f, "\n.end-main\n\n")?;
|
||||||
|
} else {
|
||||||
|
write!(f, "\n.end-method\n\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Disassembler {
|
||||||
|
disassembly: Disassembly,
|
||||||
|
text: Block,
|
||||||
|
pool: Block,
|
||||||
|
suspects: Vec<usize>,
|
||||||
|
found: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Disassembler {
|
||||||
|
pub fn new(text: Block, pool: Block) -> Disassembler {
|
||||||
|
Disassembler {
|
||||||
|
disassembly: Disassembly::default(),
|
||||||
|
text,
|
||||||
|
pool,
|
||||||
|
suspects: Vec::new(),
|
||||||
|
found: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_method(&self, addr: usize) -> bool {
|
||||||
|
self.suspects.contains(&addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disasm_instruction(&mut self, method: &mut Method) -> Result<()> {
|
||||||
|
let pos = self.text.cur();
|
||||||
|
let mut opcode = self.text.read_u8()?;
|
||||||
|
let mut wide = false;
|
||||||
|
let mut params = Vec::new();
|
||||||
|
|
||||||
|
// WIDE
|
||||||
|
if opcode == 0xC4 {
|
||||||
|
wide = true;
|
||||||
|
opcode = self.text.read_u8()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (name, args) = match ops::num_to_op(opcode) {
|
||||||
|
ops::Operation::Invalid(x) => {
|
||||||
|
eprintln!("INVALID OP 0x{:X}\n", x);
|
||||||
|
return Err("Invalid operation");
|
||||||
|
},
|
||||||
|
ops::Operation::Op(name, _, args) => (name, args),
|
||||||
|
};
|
||||||
|
|
||||||
|
for arg in args.clone() {
|
||||||
|
let v = match arg {
|
||||||
|
ops::Args::Byte => self.text.read_i8()? as i32,
|
||||||
|
ops::Args::Short => self.text.read_i16()? as i32,
|
||||||
|
ops::Args::Var => {
|
||||||
|
if wide {
|
||||||
|
self.text.read_u16()? as i32
|
||||||
|
} else {
|
||||||
|
self.text.read_u8()? as i32
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ops::Args::Label => {
|
||||||
|
let offset = self.text.read_i16()?;
|
||||||
|
let target = pos as i64 + offset as i64;
|
||||||
|
if target < 0 {
|
||||||
|
return Err("Invalid jump offset");
|
||||||
|
}
|
||||||
|
method.labels.push(target as usize);
|
||||||
|
target as i32
|
||||||
|
},
|
||||||
|
ops::Args::Constant => self.text.read_u16()? as i32,
|
||||||
|
};
|
||||||
|
params.push(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
let inst = Instruction {
|
||||||
|
op: opcode,
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
types: args,
|
||||||
|
wide,
|
||||||
|
pos,
|
||||||
|
label: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// eprintln!("i 0x{:x} ({}) @ {}", opcode, name, pos);
|
||||||
|
|
||||||
|
// INVOKEVIRTUAL
|
||||||
|
if opcode == 0xB6 {
|
||||||
|
let target_addr: usize;
|
||||||
|
|
||||||
|
{
|
||||||
|
let addr = &mut self.disassembly.constants[inst.params[0] as usize];
|
||||||
|
if !addr.method {
|
||||||
|
addr.method = true;
|
||||||
|
}
|
||||||
|
target_addr = addr.value as usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.found.contains(&target_addr) {
|
||||||
|
self.found.push(target_addr);
|
||||||
|
let save_pos = self.text.cur();
|
||||||
|
self.text.seek(target_addr)?;
|
||||||
|
|
||||||
|
let arg_count = (self.text.read_u16()? - 1) as usize;
|
||||||
|
let var_count = self.text.read_u16()? as usize;
|
||||||
|
|
||||||
|
let callee = self.disasm_method(inst.params[0], target_addr, arg_count, var_count)?;
|
||||||
|
self.disassembly.methods.push(callee);
|
||||||
|
|
||||||
|
self.text.seek(save_pos)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
method.instructions.push(inst);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disasm_method(&mut self, i: i32, pc: usize, args: usize, vars: usize) -> Result<Method> {
|
||||||
|
let mut method = Method::new(i, pc, args, vars);
|
||||||
|
|
||||||
|
while self.text.has_i8() && !self.is_method(self.text.cur()) {
|
||||||
|
self.disasm_instruction(&mut method)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
method.mark_labels();
|
||||||
|
|
||||||
|
Ok(method)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_methods(&mut self) -> Result<Vec<usize>> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
|
||||||
|
while self.text.has_i8() {
|
||||||
|
let op = self.text.read_u8()?;
|
||||||
|
// INVOKEVIRTUAL
|
||||||
|
if op == 0xB6 {
|
||||||
|
let constant_index = self.text.read_u16()? as usize;
|
||||||
|
|
||||||
|
let constant: &Constant = match self.disassembly.constants.get(constant_index) {
|
||||||
|
Some(x) => x,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let v = self.text[constant.value as usize];
|
||||||
|
if v == 0 {
|
||||||
|
res.push(constant.value as usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.text.seek(0)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disassemble(&mut self) -> Result<Disassembly> {
|
||||||
|
while self.pool.has_i32() {
|
||||||
|
self.disassembly.constants.push(Constant::new(self.pool.read_i32()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.suspects = self.find_methods()?;
|
||||||
|
|
||||||
|
let mut main = self.disasm_method(-1, 0, 0, 0)?;
|
||||||
|
main.update_vars();
|
||||||
|
self.disassembly.methods.insert(0, main);
|
||||||
|
|
||||||
|
|
||||||
|
Ok(self.disassembly.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct Disassembly {
|
||||||
|
constants: Vec<Constant>,
|
||||||
|
methods: Vec<Method>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Disassembly {
|
||||||
|
pub fn disassemble_reader(mut reader: IJVMReader) -> Result<Disassembly> {
|
||||||
|
let magic = reader.read_u32()?;
|
||||||
|
if magic != MAGIC_HEADER {
|
||||||
|
return Err("Invalid magic header");
|
||||||
|
}
|
||||||
|
let pool = match reader.read_block() {
|
||||||
|
Ok(a) => a,
|
||||||
|
Err(_) => return Err("Failed to read constants block")
|
||||||
|
};
|
||||||
|
let text = match reader.read_block() {
|
||||||
|
Ok(block) => block,
|
||||||
|
Err(_) => return Err("Failed to read text block")
|
||||||
|
};
|
||||||
|
|
||||||
|
Disassembler::new(text, pool).disassemble()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disassemble_file(file: &str) -> Result<Disassembly> {
|
||||||
|
let reader = IJVMReader::new(file)?;
|
||||||
|
Self::disassemble_reader(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_slice(source: &[u8]) -> Result<Disassembly> {
|
||||||
|
let reader = IJVMReader::new_from_slice(source);
|
||||||
|
Self::disassemble_reader(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Disassembly {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.constants.len() > 0 {
|
||||||
|
write!(f, ".constant\n")?;
|
||||||
|
for (i, c) in self.constants.iter().enumerate() {
|
||||||
|
if !c.method {
|
||||||
|
write!(f, " CONST_{:<6} {}\n", i, c.value)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, ".end-constant\n\n")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for method in &self.methods {
|
||||||
|
write!(f, "{}", method)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
extern crate core;
|
||||||
|
|
||||||
pub mod ijvmreader;
|
pub mod ijvmreader;
|
||||||
pub mod binread;
|
pub mod binread;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod ops;
|
pub mod ops;
|
||||||
pub mod machine;
|
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
pub mod pool;
|
pub mod pool;
|
||||||
pub mod frame;
|
pub mod frame;
|
||||||
@@ -14,4 +15,8 @@ pub mod heap;
|
|||||||
|
|
||||||
type Result<T> = ::std::result::Result<T, &'static str>;
|
type Result<T> = ::std::result::Result<T, &'static str>;
|
||||||
|
|
||||||
|
pub mod machine;
|
||||||
pub use machine::Machine;
|
pub use machine::Machine;
|
||||||
|
|
||||||
|
pub mod disassembler;
|
||||||
|
pub use disassembler::{Disassembler, Disassembly};
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use netstack::NetStack;
|
|||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
use heap::Heap;
|
use heap::Heap;
|
||||||
|
|
||||||
const MAGIC_HEADER:u32 = 0x1DEA_DFAD;
|
pub const MAGIC_HEADER:u32 = 0x1DEA_DFAD;
|
||||||
const ANTI_BS_SIZE:usize = 0xFF;
|
const ANTI_BS_SIZE:usize = 0xFF;
|
||||||
|
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
@@ -85,7 +85,7 @@ impl Machine {
|
|||||||
|
|
||||||
pub fn step(&mut self) -> Result<()> {
|
pub fn step(&mut self) -> Result<()> {
|
||||||
match self.block.read_op() {
|
match self.block.read_op() {
|
||||||
Ok(Operation::Op(a, func)) => {
|
Ok(Operation::Op(a, func, _)) => {
|
||||||
if cfg!(feature = "debug:instr") {
|
if cfg!(feature = "debug:instr") {
|
||||||
println!("{}", a);
|
println!("{}", a);
|
||||||
println!("Stack: {:?}", self.cur_frame().stack.data);
|
println!("Stack: {:?}", self.cur_frame().stack.data);
|
||||||
|
|||||||
82
src/ops.rs
82
src/ops.rs
@@ -6,8 +6,17 @@ use std::io::{Read};
|
|||||||
|
|
||||||
pub type OpFunc = fn(&mut Machine) -> Result<()>;
|
pub type OpFunc = fn(&mut Machine) -> Result<()>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Args {
|
||||||
|
Byte,
|
||||||
|
Short,
|
||||||
|
Var,
|
||||||
|
Label,
|
||||||
|
Constant,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Operation {
|
pub enum Operation {
|
||||||
Op(&'static str, OpFunc),
|
Op(&'static str, OpFunc, Vec<Args>),
|
||||||
Invalid(u8)
|
Invalid(u8)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15,50 +24,51 @@ const JUMP_OFFSET: i32 = 3;
|
|||||||
|
|
||||||
pub fn num_to_op(op: u8) -> Operation {
|
pub fn num_to_op(op: u8) -> Operation {
|
||||||
match op {
|
match op {
|
||||||
0x00 => Operation::Op("NOP", nop),
|
0x00 => Operation::Op("NOP", nop, vec![]),
|
||||||
0x10 => Operation::Op("BIPUSH", bipush),
|
0x10 => Operation::Op("BIPUSH", bipush, vec![Args::Byte]),
|
||||||
0x13 => Operation::Op("LDC_W", ldc_w),
|
0x13 => Operation::Op("LDC_W", ldc_w, vec![Args::Constant]),
|
||||||
0x15 => Operation::Op("ILOAD", iload),
|
0x15 => Operation::Op("ILOAD", iload, vec![Args::Var]),
|
||||||
0x36 => Operation::Op("ISTORE", istore),
|
0x36 => Operation::Op("ISTORE", istore, vec![Args::Var]),
|
||||||
0x57 => Operation::Op("POP", pop),
|
0x57 => Operation::Op("POP", pop, vec![]),
|
||||||
0x59 => Operation::Op("DUP", dup),
|
0x59 => Operation::Op("DUP", dup, vec![]),
|
||||||
0x5F => Operation::Op("SWAP", swap),
|
0x5F => Operation::Op("SWAP", swap, vec![]),
|
||||||
0x60 => Operation::Op("IADD", iadd),
|
0x60 => Operation::Op("IADD", iadd, vec![]),
|
||||||
0x64 => Operation::Op("ISUB", isub),
|
0x64 => Operation::Op("ISUB", isub, vec![]),
|
||||||
0x7E => Operation::Op("IAND", iand),
|
0x7E => Operation::Op("IAND", iand, vec![]),
|
||||||
0xB0 => Operation::Op("IOR", ior),
|
0xB0 => Operation::Op("IOR", ior, vec![]),
|
||||||
0x84 => Operation::Op("IINC", iinc),
|
0x84 => Operation::Op("IINC", iinc, vec![Args::Var, Args::Byte]),
|
||||||
0x99 => Operation::Op("IFEQ", ifeq),
|
0x99 => Operation::Op("IFEQ", ifeq, vec![Args::Label]),
|
||||||
0x9b => Operation::Op("IFLT", iflt),
|
0x9b => Operation::Op("IFLT", iflt, vec![Args::Label]),
|
||||||
0x9F => Operation::Op("IF_ICMPEQ", if_icmpeq),
|
0x9F => Operation::Op("IF_ICMPEQ", if_icmpeq, vec![Args::Label]),
|
||||||
0xA7 => Operation::Op("GOTO", goto),
|
0xA7 => Operation::Op("GOTO", goto, vec![Args::Label]),
|
||||||
0xAC => Operation::Op("IRETURN", ireturn),
|
0xAC => Operation::Op("IRETURN", ireturn, vec![]),
|
||||||
0xB6 => Operation::Op("INVOKEVIRTUAL", invokevirtual),
|
0xB6 => Operation::Op("INVOKEVIRTUAL", invokevirtual, vec![Args::Constant]),
|
||||||
0xC4 => Operation::Op("WIDE", wide),
|
0xC4 => Operation::Op("WIDE", wide, vec![]),
|
||||||
0xFC => Operation::Op("IN", _in),
|
0xFC => Operation::Op("IN", _in, vec![]),
|
||||||
0xFD => Operation::Op("OUT", out),
|
0xFD => Operation::Op("OUT", out, vec![]),
|
||||||
0xFF => Operation::Op("HALT", halt),
|
0xFE => Operation::Op("ERR", err, vec![]),
|
||||||
|
0xFF => Operation::Op("HALT", halt, vec![]),
|
||||||
|
|
||||||
#[cfg(feature = "extra:sleep")]
|
#[cfg(feature = "extra:sleep")]
|
||||||
0xF0 => Operation::Op("SLP", slp),
|
0xF0 => Operation::Op("SLP", slp, vec![Args::Byte]),
|
||||||
|
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
0xE1 => Operation::Op("NETBIND", netbind),
|
0xE1 => Operation::Op("NETBIND", netbind, vec![]),
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
0xE2 => Operation::Op("NETCONNECT", netconnect),
|
0xE2 => Operation::Op("NETCONNECT", netconnect, vec![]),
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
0xE3 => Operation::Op("NETIN", netin),
|
0xE3 => Operation::Op("NETIN", netin, vec![]),
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
0xE4 => Operation::Op("NETOUT", netout),
|
0xE4 => Operation::Op("NETOUT", netout, vec![]),
|
||||||
#[cfg(feature = "bonus:network")]
|
#[cfg(feature = "bonus:network")]
|
||||||
0xE5 => Operation::Op("NETCLOSE", netclose),
|
0xE5 => Operation::Op("NETCLOSE", netclose, vec![]),
|
||||||
|
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
0xD1 => Operation::Op("NEWARRAY", newarray),
|
0xD1 => Operation::Op("NEWARRAY", newarray, vec![]),
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
0xD2 => Operation::Op("IALOAD", iaload),
|
0xD2 => Operation::Op("IALOAD", iaload, vec![]),
|
||||||
#[cfg(feature = "bonus:heap")]
|
#[cfg(feature = "bonus:heap")]
|
||||||
0xD3 => Operation::Op("IASTORE", iastore),
|
0xD3 => Operation::Op("IASTORE", iastore, vec![]),
|
||||||
|
|
||||||
x => Operation::Invalid(x)
|
x => Operation::Invalid(x)
|
||||||
}
|
}
|
||||||
@@ -126,6 +136,12 @@ fn goto(machine: &mut Machine) -> Result<()> {
|
|||||||
machine.block.jump(offset)
|
machine.block.jump(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn err(machine: &mut Machine) -> Result<()> {
|
||||||
|
machine.halted = true;
|
||||||
|
eprintln!("MACHINE CALLED ERR");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn halt(machine: &mut Machine) -> Result<()> {
|
fn halt(machine: &mut Machine) -> Result<()> {
|
||||||
machine.halted = true;
|
machine.halted = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user