254 lines
No EOL
6.5 KiB
Rust
254 lines
No EOL
6.5 KiB
Rust
use std::collections::HashMap;
|
|
use std::rc::Rc;
|
|
use crate::{CpEntry, opcodes};
|
|
|
|
#[derive(Debug)]
|
|
//TODO create factory function
|
|
pub struct Class {
|
|
pub minor_version: u16,
|
|
pub major_version: u16,
|
|
pub constant_pool: Rc<Vec<CpEntry>>,
|
|
pub access_flags: u16,
|
|
pub this_class: u16,
|
|
pub super_class: u16,
|
|
pub interfaces: Vec<u16>,
|
|
pub fields: Vec<Field>,
|
|
pub methods: HashMap<String, Method>,
|
|
pub attributes: HashMap<String, AttributeType>,
|
|
}
|
|
|
|
impl Class {
|
|
pub fn get_version(&self) -> (u16, u16) {
|
|
(self.major_version, self.minor_version)
|
|
}
|
|
|
|
pub fn execute(&self, method_name: &str) -> Value {
|
|
let m = self.methods.get(method_name).unwrap();
|
|
m.execute().unwrap() //TODO remove unwrap
|
|
}
|
|
}
|
|
|
|
pub struct Method {
|
|
constant_pool: Rc<Vec<CpEntry>>,
|
|
access_flags: u16,
|
|
name_index: usize,
|
|
descriptor_index: usize,
|
|
attributes: HashMap<String, AttributeType>,
|
|
}
|
|
|
|
impl fmt::Debug for Method {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "Method {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}",
|
|
self.access_flags, self.name_index, self.descriptor_index, self.attributes)
|
|
}
|
|
}
|
|
|
|
impl Method {
|
|
pub fn new(constant_pool: Rc<Vec<CpEntry>>,
|
|
access_flags: u16,
|
|
name_index: usize,
|
|
descriptor_index: usize,
|
|
attributes: HashMap<String, AttributeType>, ) -> Self {
|
|
Method { constant_pool, access_flags, name_index, descriptor_index, attributes }
|
|
}
|
|
|
|
pub fn name(&self) -> String {
|
|
let mut full_name = get_modifier(self.access_flags);
|
|
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.name_index - 1] {
|
|
full_name.push_str(s);
|
|
}
|
|
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.descriptor_index - 1] {
|
|
full_name.push_str(s);
|
|
}
|
|
|
|
|
|
full_name
|
|
}
|
|
|
|
pub fn execute(&self) -> Option<Value> {
|
|
if let AttributeType::Code(code) = self.attributes.get("Code").unwrap() {
|
|
let mut stack = Stack::new();
|
|
let mut pc: usize = 0;
|
|
while pc < code.opcodes.len() {
|
|
let opcode = &code.opcodes[pc];
|
|
match opcode {
|
|
&opcodes::bipush => {
|
|
pc += 1;
|
|
let c = code.opcodes[pc] as i32;
|
|
stack.push(Value::I32(c));
|
|
},
|
|
&opcodes::ireturn => {
|
|
return stack.pop();
|
|
},
|
|
//TODO implement all opcodes
|
|
_ => {}
|
|
}
|
|
pc += 1;
|
|
}
|
|
}
|
|
None // TODO error situation
|
|
}
|
|
}
|
|
|
|
pub struct Field {
|
|
constant_pool: Rc<Vec<CpEntry>>,
|
|
access_flags: u16,
|
|
name_index: usize,
|
|
descriptor_index: usize,
|
|
attributes: HashMap<String, AttributeType>,
|
|
}
|
|
|
|
use std::fmt;
|
|
use std::hash::Hash;
|
|
use crate::io::read_u16;
|
|
|
|
impl fmt::Debug for Field {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "Field {{access_flags: {}, name_index: {}, descriptor_index: {}, attributes: {:?} }}",
|
|
self.access_flags, self.name_index, self.descriptor_index, self.attributes)
|
|
}
|
|
}
|
|
|
|
impl Field {
|
|
pub fn new(constant_pool: Rc<Vec<CpEntry>>,
|
|
access_flags: u16,
|
|
name_index: usize,
|
|
descriptor_index: usize,
|
|
attributes: HashMap<String, AttributeType>, ) -> Self {
|
|
Field { constant_pool, access_flags, name_index, descriptor_index, attributes: attributes }
|
|
}
|
|
|
|
pub fn name(&self) -> String {
|
|
let mut full_name = get_modifier(self.access_flags);
|
|
|
|
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.descriptor_index - 1] {
|
|
full_name.push_str(s);
|
|
}
|
|
full_name.push(' ');
|
|
if let CpEntry::Utf8(_, s) = &self.constant_pool[&self.name_index - 1] {
|
|
full_name.push_str(s);
|
|
}
|
|
|
|
full_name
|
|
}
|
|
}
|
|
|
|
const MODIFIERS: [(u16, &str); 12] = [
|
|
(0x0001, "public "),
|
|
(0x0002, "private "),
|
|
(0x0004, "protected "),
|
|
(0x0008, "static "),
|
|
(0x0010, "final "),
|
|
(0x0020, "synchronized "),
|
|
(0x0040, "volatile "),
|
|
(0x0080, "transient "),
|
|
(0x0100, "native "),
|
|
(0x0200, "interface "),
|
|
(0x0400, "interface "),
|
|
(0x0800, "strict ")];
|
|
|
|
pub fn get_modifier(modifier: u16) -> String {
|
|
let mut output = String::new();
|
|
for m in MODIFIERS {
|
|
if modifier & m.0 == m.0 { output.push_str(m.1) }
|
|
}
|
|
output
|
|
}
|
|
|
|
|
|
#[derive(Debug)]
|
|
pub enum AttributeType {
|
|
ConstantValue(u16),
|
|
Code(MethodCode),
|
|
StackMapTable,
|
|
BootstrapMethods,
|
|
NestHost,
|
|
NestMembers,
|
|
PermittedSubclasses,
|
|
Exceptions,
|
|
InnerClasses,
|
|
EnclosingMethod,
|
|
Synthetic,
|
|
Signature,
|
|
Record,
|
|
SourceFile,
|
|
LineNumberTable,
|
|
LocalVariableTable,
|
|
LocalVariableTypeTable,
|
|
SourceDebugExtension,
|
|
Deprecated,
|
|
RuntimeVisibleAnnotations,
|
|
RuntimeInvisibleAnnotations,
|
|
RuntimeVisibleParameterAnnotations,
|
|
RuntimeInvisibleParameterAnnotations,
|
|
RuntimeVisibleTypeAnnotations,
|
|
RuntimeInvisibleTypeAnnotations,
|
|
AnnotationDefault,
|
|
MethodParameters,
|
|
Module,
|
|
ModulePackages,
|
|
ModuleMainClass,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Exception {
|
|
pub start_pc: u16,
|
|
pub end_pc: u16,
|
|
pub handler_pc: u16,
|
|
pub catch_type: u16,
|
|
}
|
|
|
|
impl Exception {
|
|
pub fn read(code: &[u8], index: usize) -> Self {
|
|
Self {
|
|
start_pc: read_u16(code, index),
|
|
end_pc: read_u16(code, index + 2),
|
|
handler_pc: read_u16(code, index + 4),
|
|
catch_type: read_u16(code, index + 6),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct MethodCode {
|
|
max_stack: u16,
|
|
max_locals: u16,
|
|
opcodes: Vec<u8>,
|
|
exception_table: Vec<Exception>,
|
|
code_attributes: HashMap<String, AttributeType>,
|
|
}
|
|
|
|
impl MethodCode {
|
|
pub(crate) fn new(max_stack: u16, max_locals: u16,
|
|
code: Vec<u8>,
|
|
exception_table: Vec<Exception>,
|
|
code_attributes: HashMap<String, AttributeType>) -> Self {
|
|
Self { max_stack, max_locals, opcodes: code, exception_table, code_attributes }
|
|
}
|
|
}
|
|
|
|
struct Stack {
|
|
data: Vec<Value>,
|
|
}
|
|
|
|
impl Stack {
|
|
fn new() -> Self {
|
|
Self {
|
|
data: vec![]
|
|
}
|
|
}
|
|
|
|
fn push(&mut self, val: Value) {
|
|
self.data.push(val);
|
|
}
|
|
|
|
fn pop(&mut self) -> Option<Value> {
|
|
self.data.pop()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Value {
|
|
Void,
|
|
I32(i32),
|
|
} |