├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── diff.sh ├── examples ├── hello_world.rs ├── if_statement.rs ├── if_statement2.rs ├── simple_addition.rs └── static_methods.rs └── src ├── class_builder.rs ├── classfile.rs ├── java_type_signatures.rs ├── lib.rs ├── main.rs ├── pretty_printing.rs └── serialization.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.class 3 | /target 4 | /tmp 5 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "jvm-assembler" 3 | version = "0.0.1" 4 | 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jvm-assembler" 3 | version = "0.0.1" 4 | authors = ["Ken Pratt "] 5 | description = "Tools for working with Java Virtual Machine Class files from Rust." 6 | license = "MIT" 7 | repository = "https://github.com/kenpratt/jvm-assembler" 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ken Pratt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JVM Assembler 2 | ============= 3 | 4 | Tools for working with Java Virtual Machine Class files from Rust. 5 | 6 | Converts back and forth between binary `.class` files and Rust structs. 7 | 8 | Supports JVM version 8. 9 | 10 | Examples 11 | -------- 12 | 13 | To run the examples: 14 | 15 | ``` 16 | cargo run --example hello_world && java hello_world 17 | cargo run --example simple_addition && java simple_addition 18 | ``` 19 | 20 | Inspecting existing `.class` files 21 | ---------------------------------- 22 | 23 | The following command will print out a nicely-formatted representation of the structure of a `.class` file: 24 | 25 | ``` 26 | cargo run read myfile.class 27 | ``` 28 | -------------------------------------------------------------------------------- /diff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | a=$1 3 | b=$2 4 | xxd $a > $a.hex 5 | xxd $b > $b.hex 6 | diff $a.hex $b.hex 7 | rm *.hex 8 | -------------------------------------------------------------------------------- /examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | extern crate jvm_assembler; 2 | 3 | use jvm_assembler::*; 4 | 5 | fn main() { 6 | let mut class = define_class(ACC_PUBLIC, "hello_world", "java/lang/Object"); 7 | 8 | { 9 | // create main method 10 | let mut method = class.define_method(ACC_PUBLIC | ACC_STATIC, "main", &[Java::Array(Box::new(Java::Class("java/lang/String")))], &Java::Void); 11 | 12 | // push PrintStream object and string to print onto the stack, and then call println function 13 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 14 | method.load_constant("Hello, World!"); 15 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 16 | 17 | // add return statement 18 | method.do_return(); 19 | 20 | // fini! 21 | method.done(); 22 | } 23 | 24 | let classfile = class.done(); 25 | write_classfile(classfile, "hello_world.class"); 26 | } 27 | -------------------------------------------------------------------------------- /examples/if_statement.rs: -------------------------------------------------------------------------------- 1 | extern crate jvm_assembler; 2 | 3 | use jvm_assembler::*; 4 | 5 | fn main() { 6 | let mut class = define_class(ACC_PUBLIC, "if_statement", "java/lang/Object"); 7 | 8 | { 9 | // create main method 10 | let mut method = class.define_method(ACC_PUBLIC | ACC_STATIC, "main", &[Java::Array(Box::new(Java::Class("java/lang/String")))], &Java::Void); 11 | 12 | // if (args.length > 0) { 13 | // System.out.println("Hello with args!"); 14 | // } else { 15 | // System.out.println("Hello without args!"); 16 | // } 17 | method.aload0(); 18 | method.array_length(); 19 | method.ifle("false"); 20 | 21 | // true case 22 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 23 | method.load_constant("Hello with args!"); 24 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 25 | method.goto("after"); 26 | 27 | // false case 28 | method.label("false"); 29 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 30 | method.load_constant("Hello without args!"); 31 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 32 | 33 | // after 34 | method.label("after"); 35 | method.do_return(); 36 | 37 | // fini! 38 | method.done(); 39 | } 40 | 41 | let classfile = class.done(); 42 | write_classfile(classfile, "if_statement.class"); 43 | } 44 | -------------------------------------------------------------------------------- /examples/if_statement2.rs: -------------------------------------------------------------------------------- 1 | extern crate jvm_assembler; 2 | 3 | use jvm_assembler::*; 4 | 5 | fn main() { 6 | let mut class = define_class(ACC_PUBLIC, "if_statement2", "java/lang/Object"); 7 | 8 | { 9 | // create main method 10 | let mut method = class.define_method(ACC_PUBLIC | ACC_STATIC, "main", &[Java::Array(Box::new(Java::Class("java/lang/String")))], &Java::Void); 11 | 12 | // if (args.length > 0) { 13 | // System.out.println("Hello with args!"); 14 | // if (args[0].length() >= 5) { 15 | // System.out.println("First arg had at least 5 characters"); 16 | // } else { 17 | // System.out.println("First arg has less than 5 characters"); 18 | // } 19 | // } else { 20 | // System.out.println("Hello without args!"); 21 | // } 22 | method.aload0(); 23 | method.array_length(); 24 | method.ifle("outer-else"); 25 | 26 | // outer if: true case 27 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 28 | method.load_constant("Hello with args!"); 29 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 30 | 31 | // inner if: load the first arg and calculate string length 32 | method.aload0(); 33 | method.iconst0(); 34 | method.aaload(); 35 | method.invoke_virtual("java/lang/String", "length", &[], &Java::Int); 36 | 37 | // inner if: do comparison against 5 38 | method.iconst5(); 39 | method.if_icmp_lt("inner-else"); 40 | 41 | // inner if: true case 42 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 43 | method.load_constant("First arg has at least 5 characters"); 44 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 45 | method.goto("outer-after"); 46 | 47 | // inner if: false case 48 | method.label("inner-else"); 49 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 50 | method.load_constant("First arg has less than 5 characters"); 51 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 52 | 53 | // outer if: done true case 54 | method.goto("outer-after"); 55 | 56 | // outer if: false case 57 | method.label("outer-else"); 58 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 59 | method.load_constant("Hello without args!"); 60 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 61 | 62 | // after outer if 63 | method.label("outer-after"); 64 | method.do_return(); 65 | 66 | // fini! 67 | method.done(); 68 | } 69 | 70 | let classfile = class.done(); 71 | write_classfile(classfile, "if_statement2.class"); 72 | } 73 | -------------------------------------------------------------------------------- /examples/simple_addition.rs: -------------------------------------------------------------------------------- 1 | extern crate jvm_assembler; 2 | 3 | use jvm_assembler::*; 4 | 5 | fn main() { 6 | let mut class = define_class(ACC_PUBLIC, "simple_addition", "java/lang/Object"); 7 | 8 | { 9 | // create main method 10 | let mut method = class.define_method(ACC_PUBLIC | ACC_STATIC, "main", &[Java::Array(Box::new(Java::Class("java/lang/String")))], &Java::Void); 11 | 12 | // push PrintStream object onto the stack for later use 13 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 14 | 15 | // execute 11 + 37 + 42 16 | method.bipush(11); 17 | method.bipush(37); 18 | method.iadd(); 19 | method.bipush(42); 20 | method.iadd(); 21 | 22 | // print the result 23 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Int], &Java::Void); 24 | 25 | // add return statement 26 | method.do_return(); 27 | 28 | // fini! 29 | method.done(); 30 | } 31 | 32 | let classfile = class.done(); 33 | write_classfile(classfile, "simple_addition.class"); 34 | } 35 | -------------------------------------------------------------------------------- /examples/static_methods.rs: -------------------------------------------------------------------------------- 1 | extern crate jvm_assembler; 2 | 3 | use jvm_assembler::*; 4 | 5 | fn main() { 6 | let mut class = define_class(ACC_PUBLIC, "static_methods", "java/lang/Object"); 7 | 8 | { 9 | let mut method = class.define_method(ACC_PUBLIC | ACC_STATIC, "main", &[Java::Array(Box::new(Java::Class("java/lang/String")))], &Java::Void); 10 | method.invoke_static("static_methods", "hello_world", &[], &Java::Void); 11 | method.load_constant("Rust"); 12 | method.invoke_static("static_methods", "hello_someone", &[Java::Class("java/lang/String")], &Java::Void); 13 | method.do_return(); 14 | method.done(); 15 | } 16 | 17 | { 18 | let mut method = class.define_method(ACC_STATIC, "hello_world", &[], &Java::Void); 19 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 20 | method.load_constant("Hello, World!"); 21 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 22 | method.do_return(); 23 | method.done(); 24 | } 25 | 26 | { 27 | let mut method = class.define_method(ACC_STATIC, "hello_someone", &[Java::Class("java/lang/String")], &Java::Void); 28 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 29 | method.load_constant("Hello, "); 30 | method.invoke_virtual("java/io/PrintStream", "print", &[Java::Class("java/lang/String")], &Java::Void); 31 | 32 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 33 | method.aload0(); 34 | method.invoke_virtual("java/io/PrintStream", "print", &[Java::Class("java/lang/String")], &Java::Void); 35 | 36 | method.get_static("java/lang/System", "out", &Java::Class("java/io/PrintStream")); 37 | method.load_constant("!"); 38 | method.invoke_virtual("java/io/PrintStream", "println", &[Java::Class("java/lang/String")], &Java::Void); 39 | 40 | method.do_return(); 41 | method.done(); 42 | } 43 | 44 | let classfile = class.done(); 45 | write_classfile(classfile, "static_methods.class"); 46 | } 47 | -------------------------------------------------------------------------------- /src/class_builder.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use classfile::*; 4 | use java_type_signatures::*; 5 | 6 | pub const ACC_PUBLIC: u16 = 0x1; 7 | pub const ACC_STATIC: u16 = 0x8; 8 | 9 | pub struct ClassBuilder { 10 | access_flags: u16, 11 | this_class_index: u16, 12 | super_class_index: u16, 13 | constants: Vec, 14 | methods: Vec, 15 | } 16 | 17 | impl ClassBuilder { 18 | pub fn new(access_flags: u16, this_class: &str, super_class: &str) -> ClassBuilder { 19 | let mut builder = ClassBuilder { 20 | access_flags: access_flags, 21 | this_class_index: 0, 22 | super_class_index: 0, 23 | constants: vec![], 24 | methods: vec![], 25 | }; 26 | builder.this_class_index = builder.define_class(this_class); 27 | builder.super_class_index = builder.define_class(super_class); 28 | builder 29 | } 30 | 31 | pub fn define_method(&mut self, access_flags: u16, name: &str, argument_types: &[Java], return_type: &Java) -> MethodBuilder { 32 | MethodBuilder::new(self, access_flags, name, argument_types, return_type) 33 | } 34 | 35 | fn push_constant(&mut self, constant: Constant) -> u16 { 36 | // TODO check if this constant is exactly equal to anything already defined in constants. If so, return the existing index instead of re-defining it. 37 | self.constants.push(constant); 38 | self.constants.len() as u16 39 | } 40 | 41 | fn define_utf8(&mut self, string: &str) -> u16 { 42 | self.push_constant(Constant::Utf8(string.to_owned())) 43 | } 44 | 45 | fn define_class(&mut self, class: &str) -> u16 { 46 | let name_index = self.define_utf8(class); 47 | self.push_constant(Constant::Class(name_index)) 48 | } 49 | 50 | fn define_string(&mut self, value: &str) -> u16 { 51 | let string_index = self.define_utf8(value); 52 | self.push_constant(Constant::String(string_index)) 53 | } 54 | 55 | fn define_fieldref(&mut self, class: &str, name: &str, field_type: &Java) -> u16 { 56 | let class_index = self.define_class(class); 57 | let descriptor = format!("{}", field_type); 58 | let name_and_type_index = self.define_name_and_type(name, &descriptor); 59 | self.push_constant(Constant::Fieldref(class_index, name_and_type_index)) 60 | } 61 | 62 | fn define_methodref(&mut self, class: &str, name: &str, argument_types: &[Java], return_type: &Java) -> u16 { 63 | let class_index = self.define_class(class); 64 | let descriptor = method_signature(argument_types, return_type); 65 | let name_and_type_index = self.define_name_and_type(name, &descriptor); 66 | self.push_constant(Constant::Methodref(class_index, name_and_type_index)) 67 | } 68 | 69 | fn define_name_and_type(&mut self, name: &str, descriptor: &str) -> u16 { 70 | let name_index = self.define_utf8(name); 71 | let descriptor_index = self.define_utf8(&descriptor); 72 | self.push_constant(Constant::NameAndType(name_index, descriptor_index)) 73 | } 74 | 75 | pub fn done(self) -> Classfile { 76 | Classfile::new(self.constants, self.access_flags, self.this_class_index, self.super_class_index, self.methods) 77 | } 78 | } 79 | 80 | pub struct MethodBuilder<'a> { 81 | classfile: &'a mut ClassBuilder, 82 | access_flags: u16, 83 | name_index: u16, 84 | descriptor_index: u16, 85 | instructions: Vec<(u16, IntermediateInstruction<'a>)>, 86 | labels: HashMap, 87 | stack_index: u16, 88 | curr_stack_depth: u16, 89 | max_stack_depth: u16, 90 | stack_frames: Vec, 91 | last_stack_frame_index: Option, 92 | } 93 | 94 | #[derive(Debug)] 95 | pub enum IntermediateInstruction<'a> { 96 | Ready(Instruction), 97 | Waiting(&'a str, Instruction), 98 | } 99 | 100 | impl<'a> MethodBuilder<'a> { 101 | fn new(classfile: &'a mut ClassBuilder, access_flags: u16, name: &str, argument_types: &[Java], return_type: &Java) -> MethodBuilder<'a> { 102 | let name_index = classfile.define_utf8(name); 103 | let descriptor = method_signature(argument_types, return_type); 104 | let descriptor_index = classfile.define_utf8(&descriptor); 105 | MethodBuilder { 106 | classfile: classfile, 107 | access_flags: access_flags, 108 | name_index: name_index, 109 | descriptor_index: descriptor_index, 110 | instructions: vec![], 111 | labels: HashMap::new(), 112 | stack_index: 0, 113 | curr_stack_depth: 0, 114 | max_stack_depth: 0, 115 | stack_frames: vec![], 116 | last_stack_frame_index: None, 117 | } 118 | } 119 | 120 | pub fn iconstm1(&mut self) { 121 | self.push_instruction(Instruction::IconstM1); 122 | self.increase_stack_depth(); 123 | } 124 | 125 | pub fn iconst0(&mut self) { 126 | self.push_instruction(Instruction::Iconst0); 127 | self.increase_stack_depth(); 128 | } 129 | 130 | pub fn iconst1(&mut self) { 131 | self.push_instruction(Instruction::Iconst1); 132 | self.increase_stack_depth(); 133 | } 134 | 135 | pub fn iconst2(&mut self) { 136 | self.push_instruction(Instruction::Iconst2); 137 | self.increase_stack_depth(); 138 | } 139 | 140 | pub fn iconst3(&mut self) { 141 | self.push_instruction(Instruction::Iconst3); 142 | self.increase_stack_depth(); 143 | } 144 | 145 | pub fn iconst4(&mut self) { 146 | self.push_instruction(Instruction::Iconst4); 147 | self.increase_stack_depth(); 148 | } 149 | 150 | pub fn iconst5(&mut self) { 151 | self.push_instruction(Instruction::Iconst5); 152 | self.increase_stack_depth(); 153 | } 154 | 155 | pub fn bipush(&mut self, value: i8) { 156 | self.push_instruction(Instruction::Bipush(value as u8)); 157 | self.increase_stack_depth(); 158 | } 159 | 160 | pub fn load_constant(&mut self, value: &str) { 161 | let string_index = self.classfile.define_string(value); 162 | if string_index > ::std::u8::MAX as u16 { 163 | panic!("Placed a constant in too high of an index: {}", string_index) 164 | } 165 | self.push_instruction(Instruction::LoadConstant(string_index as u8)); 166 | self.increase_stack_depth(); 167 | } 168 | 169 | pub fn aload0(&mut self) { 170 | self.push_instruction(Instruction::Aload0); 171 | self.increase_stack_depth(); 172 | } 173 | 174 | pub fn aload1(&mut self) { 175 | self.push_instruction(Instruction::Aload1); 176 | self.increase_stack_depth(); 177 | } 178 | 179 | pub fn aload2(&mut self) { 180 | self.push_instruction(Instruction::Aload2); 181 | self.increase_stack_depth(); 182 | } 183 | 184 | pub fn aload3(&mut self) { 185 | self.push_instruction(Instruction::Aload3); 186 | self.increase_stack_depth(); 187 | } 188 | 189 | pub fn aaload(&mut self) { 190 | self.push_instruction(Instruction::Aaload); 191 | self.decrease_stack_depth(); 192 | } 193 | 194 | pub fn iadd(&mut self) { 195 | self.push_instruction(Instruction::Iadd); 196 | self.decrease_stack_depth(); 197 | } 198 | 199 | pub fn ifeq(&mut self, label: &'a str) { 200 | self.delay_instruction(label, Instruction::IfEq(0)); 201 | self.decrease_stack_depth(); 202 | } 203 | 204 | pub fn ifne(&mut self, label: &'a str) { 205 | self.delay_instruction(label, Instruction::IfNe(0)); 206 | self.decrease_stack_depth(); 207 | } 208 | 209 | pub fn iflt(&mut self, label: &'a str) { 210 | self.delay_instruction(label, Instruction::IfLt(0)); 211 | self.decrease_stack_depth(); 212 | } 213 | 214 | pub fn ifge(&mut self, label: &'a str) { 215 | self.delay_instruction(label, Instruction::IfGe(0)); 216 | self.decrease_stack_depth(); 217 | } 218 | 219 | pub fn ifgt(&mut self, label: &'a str) { 220 | self.delay_instruction(label, Instruction::IfGt(0)); 221 | self.decrease_stack_depth(); 222 | } 223 | 224 | pub fn ifle(&mut self, label: &'a str) { 225 | self.delay_instruction(label, Instruction::IfLe(0)); 226 | self.decrease_stack_depth(); 227 | } 228 | 229 | pub fn if_icmp_eq(&mut self, label: &'a str) { 230 | self.delay_instruction(label, Instruction::IfIcmpEq(0)); 231 | self.decrease_stack_depth_by(2); 232 | } 233 | 234 | pub fn if_icmp_ne(&mut self, label: &'a str) { 235 | self.delay_instruction(label, Instruction::IfIcmpNe(0)); 236 | self.decrease_stack_depth_by(2); 237 | } 238 | 239 | pub fn if_icmp_lt(&mut self, label: &'a str) { 240 | self.delay_instruction(label, Instruction::IfIcmpLt(0)); 241 | self.decrease_stack_depth_by(2); 242 | } 243 | 244 | pub fn if_icmp_ge(&mut self, label: &'a str) { 245 | self.delay_instruction(label, Instruction::IfIcmpGe(0)); 246 | self.decrease_stack_depth_by(2); 247 | } 248 | 249 | pub fn if_icmp_gt(&mut self, label: &'a str) { 250 | self.delay_instruction(label, Instruction::IfIcmpGt(0)); 251 | self.decrease_stack_depth_by(2); 252 | } 253 | 254 | pub fn if_icmp_le(&mut self, label: &'a str) { 255 | self.delay_instruction(label, Instruction::IfIcmpLe(0)); 256 | self.decrease_stack_depth_by(2); 257 | } 258 | 259 | pub fn goto(&mut self, label: &'a str) { 260 | self.delay_instruction(label, Instruction::Goto(0)); 261 | } 262 | 263 | pub fn do_return(&mut self) { 264 | self.push_instruction(Instruction::Return); 265 | } 266 | 267 | pub fn get_static(&mut self, class: &str, name: &str, argument_type: &Java) { 268 | let fieldref_index = self.classfile.define_fieldref(class, name, argument_type); 269 | self.push_instruction(Instruction::GetStatic(fieldref_index)); 270 | self.increase_stack_depth(); 271 | } 272 | 273 | pub fn invoke_virtual(&mut self, class: &str, name: &str, argument_types: &[Java], return_type: &Java) { 274 | let methodref_index = self.classfile.define_methodref(class, name, argument_types, return_type); 275 | self.push_instruction(Instruction::InvokeVirtual(methodref_index)); 276 | self.decrease_stack_depth_by(argument_types.len() as u8 + 1); 277 | if *return_type != Java::Void { self.increase_stack_depth(); } 278 | } 279 | 280 | pub fn invoke_special(&mut self, class: &str, name: &str, argument_types: &[Java], return_type: &Java) { 281 | let methodref_index = self.classfile.define_methodref(class, name, argument_types, return_type); 282 | self.push_instruction(Instruction::InvokeSpecial(methodref_index)); 283 | self.decrease_stack_depth_by(argument_types.len() as u8 + 1); 284 | if *return_type != Java::Void { self.increase_stack_depth(); } 285 | } 286 | 287 | pub fn invoke_static(&mut self, class: &str, name: &str, argument_types: &[Java], return_type: &Java) { 288 | let methodref_index = self.classfile.define_methodref(class, name, argument_types, return_type); 289 | self.push_instruction(Instruction::InvokeStatic(methodref_index)); 290 | self.decrease_stack_depth_by(argument_types.len() as u8); 291 | if *return_type != Java::Void { self.increase_stack_depth(); } 292 | } 293 | 294 | pub fn array_length(&mut self) { 295 | self.push_instruction(Instruction::ArrayLength); 296 | } 297 | 298 | pub fn label(&mut self, name: &str) { 299 | self.labels.insert(name.to_owned(), self.stack_index); 300 | 301 | // create a stack map table entry 302 | let offset = match self.last_stack_frame_index { 303 | Some(i) => self.stack_index - i - 1, 304 | None => self.stack_index 305 | }; 306 | let frame = if offset > ::std::u8::MAX as u16 { 307 | StackMapFrame::SameFrameExtended(offset) 308 | } else { 309 | StackMapFrame::SameFrame(offset as u8) 310 | }; 311 | self.stack_frames.push(frame); 312 | self.last_stack_frame_index = Some(self.stack_index); 313 | } 314 | 315 | fn push_instruction(&mut self, instruction: Instruction) { 316 | let index = self.stack_index; 317 | self.stack_index += instruction.size() as u16; 318 | self.instructions.push((index, IntermediateInstruction::Ready(instruction))); 319 | } 320 | 321 | fn delay_instruction(&mut self, label: &'a str, instruction: Instruction) { 322 | let index = self.stack_index; 323 | self.stack_index += instruction.size() as u16; 324 | self.instructions.push((index, IntermediateInstruction::Waiting(label, instruction))); 325 | } 326 | 327 | fn increase_stack_depth(&mut self) { 328 | self.curr_stack_depth += 1; 329 | if self.curr_stack_depth > self.max_stack_depth { 330 | self.max_stack_depth = self.curr_stack_depth; 331 | } 332 | } 333 | 334 | fn decrease_stack_depth(&mut self) { 335 | self.curr_stack_depth -= 1; 336 | } 337 | 338 | fn decrease_stack_depth_by(&mut self, n: u8) { 339 | self.curr_stack_depth -= n as u16; 340 | } 341 | 342 | pub fn done(self) { 343 | if self.curr_stack_depth != 0 { 344 | println!("Warning: stack depth at the end of a method should be 0, but is {} instead", self.curr_stack_depth); 345 | } 346 | 347 | let classfile = self.classfile; 348 | let labels = self.labels; 349 | let real_instructions = self.instructions.into_iter().map(|(pos, ir)| match ir { 350 | IntermediateInstruction::Ready(i) => i, 351 | IntermediateInstruction::Waiting(l, i) => { 352 | let label_pos = labels.get(l).unwrap(); 353 | let offset = label_pos - pos; 354 | fill_offset(i, offset) 355 | } 356 | }).collect(); 357 | 358 | let stack_map_table_index = classfile.define_utf8("StackMapTable"); 359 | let stack_map_table = Attribute::StackMapTable(stack_map_table_index, self.stack_frames); 360 | 361 | // TODO track max_locals counts instead of hard-coding to 1 362 | let code_index = classfile.define_utf8("Code"); 363 | let code = Attribute::Code(code_index, self.max_stack_depth, 1, real_instructions, vec![], vec![stack_map_table]); 364 | 365 | let method = Method::new(self.access_flags, self.name_index, self.descriptor_index, vec![code]); 366 | classfile.methods.push(method); 367 | } 368 | } 369 | 370 | fn fill_offset(instruction: Instruction, offset: u16) -> Instruction { 371 | match instruction { 372 | Instruction::IfEq(_) => Instruction::IfEq(offset), 373 | Instruction::IfNe(_) => Instruction::IfNe(offset), 374 | Instruction::IfLt(_) => Instruction::IfLt(offset), 375 | Instruction::IfGe(_) => Instruction::IfGe(offset), 376 | Instruction::IfGt(_) => Instruction::IfGt(offset), 377 | Instruction::IfLe(_) => Instruction::IfLe(offset), 378 | Instruction::IfIcmpEq(_) => Instruction::IfIcmpEq(offset), 379 | Instruction::IfIcmpNe(_) => Instruction::IfIcmpNe(offset), 380 | Instruction::IfIcmpLt(_) => Instruction::IfIcmpLt(offset), 381 | Instruction::IfIcmpGe(_) => Instruction::IfIcmpGe(offset), 382 | Instruction::IfIcmpGt(_) => Instruction::IfIcmpGt(offset), 383 | Instruction::IfIcmpLe(_) => Instruction::IfIcmpLe(offset), 384 | Instruction::Goto(_) => Instruction::Goto(offset), 385 | _ => panic!("Instruction type doesn't have an offset to fill: {:?}", instruction) 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /src/classfile.rs: -------------------------------------------------------------------------------- 1 | const CAFEBABE: u32 = 0xCAFEBABE; 2 | const MAJOR_VERSION: u16 = 52; 3 | const MINOR_VERSION: u16 = 0; 4 | 5 | #[derive(Clone, Debug, PartialEq)] 6 | pub struct Classfile { 7 | pub magic: u32, 8 | pub minor_version: u16, 9 | pub major_version: u16, 10 | pub constant_pool: Vec, 11 | pub access_flags: u16, 12 | pub this_class: u16, 13 | pub super_class: u16, 14 | pub interfaces: Vec, 15 | pub fields: Vec, 16 | pub methods: Vec, 17 | pub attributes: Vec, 18 | } 19 | 20 | #[derive(Clone, Debug, PartialEq)] 21 | pub enum Constant { 22 | Utf8(String), // 1 23 | Class(u16), // 7 24 | String(u16), // 8 25 | Fieldref(u16, u16), // 9 26 | Methodref(u16, u16), // 10 27 | NameAndType(u16, u16), // 12 28 | } 29 | 30 | #[derive(Clone, Debug, PartialEq)] 31 | pub struct Interface; 32 | 33 | #[derive(Clone, Debug, PartialEq)] 34 | pub struct Field; 35 | 36 | #[derive(Clone, Debug, PartialEq)] 37 | pub struct Method { 38 | pub access_flags: u16, 39 | pub name_index: u16, 40 | pub descriptor_index: u16, 41 | pub attributes: Vec, 42 | } 43 | 44 | #[derive(Clone, Debug, PartialEq)] 45 | pub enum Attribute { 46 | Code(u16, u16, u16, Vec, Vec, Vec), 47 | LineNumberTable(u16, Vec), 48 | SourceFile(u16, u16), 49 | StackMapTable(u16, Vec), 50 | } 51 | 52 | #[derive(Clone, Debug, PartialEq)] 53 | pub struct ExceptionTableEntry; 54 | 55 | #[derive(Clone, Debug, PartialEq)] 56 | pub struct LineNumberTableEntry { 57 | pub start_pc: u16, 58 | pub line_number: u16, 59 | } 60 | 61 | #[derive(Clone, Debug, PartialEq)] 62 | pub enum StackMapFrame { 63 | SameFrame(u8), 64 | SameLocals1StackItemFrame(u8, VerificationType), 65 | SameLocals1StackItemFrameExtended(u16, VerificationType), 66 | ChopFrame(u8, u16), 67 | SameFrameExtended(u16), 68 | AppendFrame(u8, u16, Vec), 69 | FullFrame(u16, Vec, Vec), 70 | } 71 | 72 | #[derive(Clone, Debug, PartialEq)] 73 | pub enum VerificationType { 74 | Top, // 0 75 | Integer, // 1 76 | Float, // 2 77 | Long, // 3 78 | Double, // 4 79 | Null, // 5 80 | UninitializedThis, // 6 81 | Object(u16), // 7 82 | Uninitialized(u16), // 8 83 | } 84 | 85 | #[derive(Clone, Debug, PartialEq)] 86 | pub enum Instruction { 87 | IconstM1, // 0x02 88 | Iconst0, // 0x03 89 | Iconst1, // 0x04 90 | Iconst2, // 0x05 91 | Iconst3, // 0x06 92 | Iconst4, // 0x07 93 | Iconst5, // 0x08 94 | Bipush(u8), // 0x10 95 | LoadConstant(u8), // 0x12 96 | Aload0, // 0x2A 97 | Aload1, // 0x2B 98 | Aload2, // 0x2C 99 | Aload3, // 0x2D 100 | Aaload, // 0x32 101 | Iadd, // 0x60 102 | IfEq(u16), // 0x99 103 | IfNe(u16), // 0x9A 104 | IfLt(u16), // 0x9B 105 | IfGe(u16), // 0x9C 106 | IfGt(u16), // 0x9D 107 | IfLe(u16), // 0x9E 108 | IfIcmpEq(u16), // 0x9F 109 | IfIcmpNe(u16), // 0xA0 110 | IfIcmpLt(u16), // 0xA1 111 | IfIcmpGe(u16), // 0xA2 112 | IfIcmpGt(u16), // 0xA3 113 | IfIcmpLe(u16), // 0xA4 114 | Goto(u16), // 0xA7 115 | Return, // 0xB1 116 | GetStatic(u16), // 0xB2 117 | InvokeVirtual(u16), // 0xB6 118 | InvokeSpecial(u16), // 0xB7 119 | InvokeStatic(u16), // 0xB8 120 | ArrayLength, // 0xBE 121 | } 122 | 123 | impl Classfile { 124 | pub fn new(constants: Vec, access_flags: u16, this_class: u16, super_class: u16, methods: Vec) -> Classfile { 125 | Classfile { 126 | magic: CAFEBABE, 127 | minor_version: MINOR_VERSION, 128 | major_version: MAJOR_VERSION, 129 | constant_pool: constants, 130 | access_flags: access_flags, 131 | this_class: this_class, 132 | super_class: super_class, 133 | interfaces: vec![], 134 | fields: vec![], 135 | methods: methods, 136 | attributes: vec![], 137 | } 138 | } 139 | 140 | pub fn lookup_constant(&self, index: u16) -> &Constant { 141 | &self.constant_pool[index as usize - 1] 142 | } 143 | 144 | pub fn lookup_string(&self, index: u16) -> &str { 145 | let val = self.lookup_constant(index); 146 | match *val { 147 | Constant::Utf8(ref str) => str, 148 | _ => panic!("Wanted string, found {:?}", val) 149 | } 150 | } 151 | } 152 | 153 | impl Method { 154 | pub fn new(access_flags: u16, name_index: u16, descriptor_index: u16, attributes: Vec) -> Method { 155 | Method { 156 | access_flags: access_flags, 157 | name_index: name_index, 158 | descriptor_index: descriptor_index, 159 | attributes: attributes, 160 | } 161 | } 162 | } 163 | 164 | impl Instruction { 165 | pub fn size(&self) -> u8 { 166 | match *self { 167 | Instruction::IconstM1 => 1, 168 | Instruction::Iconst0 => 1, 169 | Instruction::Iconst1 => 1, 170 | Instruction::Iconst2 => 1, 171 | Instruction::Iconst3 => 1, 172 | Instruction::Iconst4 => 1, 173 | Instruction::Iconst5 => 1, 174 | Instruction::Bipush(_) => 2, 175 | Instruction::LoadConstant(_) => 2, 176 | Instruction::Aload0 => 1, 177 | Instruction::Aload1 => 1, 178 | Instruction::Aload2 => 1, 179 | Instruction::Aload3 => 1, 180 | Instruction::Aaload => 1, 181 | Instruction::Iadd => 1, 182 | Instruction::IfEq(_) => 3, 183 | Instruction::IfNe(_) => 3, 184 | Instruction::IfLt(_) => 3, 185 | Instruction::IfGe(_) => 3, 186 | Instruction::IfGt(_) => 3, 187 | Instruction::IfLe(_) => 3, 188 | Instruction::IfIcmpEq(_) => 3, 189 | Instruction::IfIcmpNe(_) => 3, 190 | Instruction::IfIcmpLt(_) => 3, 191 | Instruction::IfIcmpGe(_) => 3, 192 | Instruction::IfIcmpGt(_) => 3, 193 | Instruction::IfIcmpLe(_) => 3, 194 | Instruction::Goto(_) => 3, 195 | Instruction::Return => 1, 196 | Instruction::GetStatic(_) => 3, 197 | Instruction::InvokeVirtual(_) => 3, 198 | Instruction::InvokeSpecial(_) => 3, 199 | Instruction::InvokeStatic(_) => 3, 200 | Instruction::ArrayLength => 1, 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/java_type_signatures.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | #[derive(Clone, Debug, PartialEq)] 4 | pub enum Java<'a> { 5 | Boolean, // Z 6 | Byte, // B 7 | Char, // C 8 | Short, // S 9 | Int, // I 10 | Long, // J 11 | Float, // F 12 | Double, // D 13 | Void, // V 14 | Class(&'a str), // Lclassname; 15 | Array(Box>), // [type 16 | } 17 | 18 | impl<'a> fmt::Display for Java<'a> { 19 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 20 | match *self { 21 | Java::Boolean => write!(f, "Z"), 22 | Java::Byte => write!(f, "B"), 23 | Java::Char => write!(f, "C"), 24 | Java::Short => write!(f, "S"), 25 | Java::Int => write!(f, "I"), 26 | Java::Long => write!(f, "J"), 27 | Java::Float => write!(f, "F"), 28 | Java::Double => write!(f, "D"), 29 | Java::Void => write!(f, "V"), 30 | Java::Class(ref s) => write!(f, "L{};", s), 31 | Java::Array(ref t) => write!(f, "[{}", t), 32 | } 33 | } 34 | } 35 | 36 | pub fn method_signature(argument_types: &[Java], return_type: &Java) -> String { 37 | let mut args = "".to_owned(); 38 | for t in argument_types { 39 | args.push_str(&format!("{}", t)); 40 | } 41 | format!("({}){}", args, return_type) 42 | } 43 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod classfile; 2 | mod class_builder; 3 | mod java_type_signatures; 4 | mod pretty_printing; 5 | mod serialization; 6 | 7 | use std::fs::File; 8 | use std::io::Write; 9 | 10 | pub use classfile::*; 11 | pub use class_builder::*; 12 | pub use java_type_signatures::*; 13 | 14 | pub fn write_classfile(classfile: Classfile, filename: &str) { 15 | let mut bytes = vec![]; 16 | classfile.serialize(&mut bytes); 17 | 18 | let mut f = File::create(filename).unwrap(); 19 | f.write_all(&bytes).unwrap(); 20 | } 21 | 22 | pub fn read_classfile(filename: &str) -> Classfile { 23 | let f = File::open(filename).unwrap(); 24 | Classfile::deserialize(Box::new(f)) 25 | } 26 | 27 | pub fn define_class(access_flags: u16, this_class: &str, super_class: &str) -> ClassBuilder { 28 | ClassBuilder::new(access_flags, this_class, super_class) 29 | } 30 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate jvm_assembler; 2 | 3 | use std::env; 4 | 5 | use jvm_assembler::*; 6 | 7 | fn main() { 8 | let args: Vec = env::args().collect(); 9 | if args.len() != 3 { 10 | panic!("You must provide 3 arguments to {}", &args[0]); 11 | } 12 | 13 | let command = &args[1]; 14 | let filename = &args[2]; 15 | 16 | match command.as_ref() { 17 | "read" => print!("{}", read_classfile(filename)), 18 | _ => panic!("Unknown command: {}", command) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/pretty_printing.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use classfile::*; 4 | 5 | impl fmt::Display for Classfile { 6 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 7 | try!(writeln!(f, "Magic: 0x{:X}", self.magic)); 8 | try!(writeln!(f, "Minor version: {}", self.minor_version)); 9 | try!(writeln!(f, "Major version: {}", self.major_version)); 10 | try!(writeln!(f, "Constant pool:")); 11 | let constant_pool_with_indices: Vec<(u16, &Constant)> = self.constant_pool.iter().enumerate().map(|(i, v)| (i as u16 + 1, v)).collect(); 12 | try!(constant_pool_with_indices.pretty_println(f, 2)); 13 | try!(writeln!(f, "Access flags: 0x{:X}", self.access_flags)); 14 | try!(writeln!(f, "This class: {}", self.this_class)); 15 | try!(writeln!(f, "Super class: {}", self.super_class)); 16 | try!(writeln!(f, "Interfaces:")); 17 | try!(self.interfaces.pretty_println(f, 2)); 18 | try!(writeln!(f, "Fields:")); 19 | try!(self.fields.pretty_println(f, 2)); 20 | try!(writeln!(f, "Methods:")); 21 | try!(self.methods.pretty_println(f, 2)); 22 | try!(writeln!(f, "Attributes:")); 23 | Ok(()) 24 | } 25 | } 26 | 27 | trait PrettyPrint { 28 | fn pretty_print(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result; 29 | 30 | fn pretty_println(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 31 | try!(self.pretty_print(f, indent)); 32 | write!(f, "\n") 33 | } 34 | 35 | fn pretty_print_preln(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 36 | try!(write!(f, "\n")); 37 | self.pretty_print(f, indent) 38 | } 39 | } 40 | 41 | impl PrettyPrint for Vec { 42 | fn pretty_print(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 43 | let mut count = 0; 44 | for item in self { 45 | try!(write!(f, "{0:1$}", "", indent)); 46 | try!(item.pretty_print(f, indent + 2)); 47 | count += 1; 48 | if count < self.len() { 49 | try!(write!(f, "\n")); 50 | } 51 | } 52 | Ok(()) 53 | } 54 | 55 | fn pretty_println(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 56 | if self.len() > 0 { 57 | try!(self.pretty_print(f, indent)); 58 | write!(f, "\n") 59 | } else { 60 | Ok(()) 61 | } 62 | } 63 | 64 | 65 | fn pretty_print_preln(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 66 | if self.len() > 0 { 67 | try!(write!(f, "\n")); 68 | self.pretty_print(f, indent) 69 | } else { 70 | Ok(()) 71 | } 72 | } 73 | } 74 | 75 | impl PrettyPrint for (T, U) { 76 | fn pretty_print(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 77 | let (ref t, ref u) = *self; 78 | try!(t.pretty_print(f, indent)); 79 | try!(write!(f, ": ")); 80 | try!(u.pretty_print(f, indent)); 81 | Ok(()) 82 | } 83 | } 84 | 85 | impl PrettyPrint for u8 { 86 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 87 | write!(f, "{:2}", self) 88 | } 89 | } 90 | 91 | impl PrettyPrint for u16 { 92 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 93 | write!(f, "{:2}", self) 94 | } 95 | } 96 | 97 | impl PrettyPrint for u32 { 98 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 99 | write!(f, "{:2}", self) 100 | } 101 | } 102 | 103 | impl<'a> PrettyPrint for &'a Constant { 104 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 105 | write!(f, "{:?}", self) 106 | } 107 | } 108 | 109 | impl PrettyPrint for Interface { 110 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 111 | write!(f, "{:?}", self) 112 | } 113 | } 114 | 115 | impl PrettyPrint for Field { 116 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 117 | write!(f, "{:?}", self) 118 | } 119 | } 120 | 121 | impl PrettyPrint for Method { 122 | fn pretty_print(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 123 | try!(write!(f, "Method(access_flags: 0x{:X}, name_index: {}, descriptor_index: {})\n", self.access_flags, self.name_index, self.descriptor_index)); 124 | try!(write!(f, "{0:1$}Attributes:", "", indent)); 125 | try!(self.attributes.pretty_print_preln(f, indent + 2)); 126 | Ok(()) 127 | } 128 | } 129 | 130 | impl PrettyPrint for Attribute { 131 | fn pretty_print(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { 132 | match *self { 133 | Attribute::Code(_, max_stack, max_locals, ref code, ref exception_table, ref attributes) => { 134 | try!(write!(f, "Code(max_stack: {}, max_locals: {})\n", max_stack, max_locals)); 135 | try!(write!(f, "{0:1$}Instructions:\n", "", indent)); 136 | try!(code.pretty_println(f, indent + 2)); 137 | try!(write!(f, "{0:1$}Exception table:\n", "", indent)); 138 | try!(exception_table.pretty_println(f, indent + 2)); 139 | try!(write!(f, "{0:1$}Attributes:", "", indent)); 140 | try!(attributes.pretty_print_preln(f, indent + 2)); 141 | Ok(()) 142 | }, 143 | Attribute::LineNumberTable(_, ref entries) => { 144 | try!(write!(f, "LineNumberTable:")); 145 | try!(entries.pretty_print_preln(f, indent)); 146 | Ok(()) 147 | }, 148 | Attribute::SourceFile(_, index) => { 149 | try!(write!(f, "SourceFile(index: {}):", index)); 150 | Ok(()) 151 | } 152 | Attribute::StackMapTable(_, ref entries) => { 153 | try!(write!(f, "StackMapTable:")); 154 | try!(entries.pretty_print_preln(f, indent)); 155 | Ok(()) 156 | }, 157 | } 158 | } 159 | } 160 | 161 | impl PrettyPrint for ExceptionTableEntry { 162 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 163 | write!(f, "{:?}", self) 164 | } 165 | } 166 | 167 | impl PrettyPrint for LineNumberTableEntry { 168 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 169 | write!(f, "start_pc: {:2}, line_number: {:2}", self.start_pc, self.line_number) 170 | } 171 | } 172 | 173 | impl PrettyPrint for StackMapFrame { 174 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 175 | write!(f, "{:?}", self) 176 | } 177 | } 178 | 179 | impl PrettyPrint for VerificationType { 180 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 181 | write!(f, "{:?}", self) 182 | } 183 | } 184 | 185 | impl PrettyPrint for Instruction { 186 | fn pretty_print(&self, f: &mut fmt::Formatter, _indent: usize) -> fmt::Result { 187 | write!(f, "{:?}", self) 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/serialization.rs: -------------------------------------------------------------------------------- 1 | use std::io::Read; 2 | 3 | use classfile::*; 4 | 5 | impl Classfile { 6 | pub fn serialize(self, buf: &mut Vec) { 7 | self.magic.serialize(buf); 8 | self.minor_version.serialize(buf); 9 | self.major_version.serialize(buf); 10 | self.constant_pool.serialize(buf); 11 | self.access_flags.serialize(buf); 12 | self.this_class.serialize(buf); 13 | self.super_class.serialize(buf); 14 | self.interfaces.serialize(buf); 15 | self.fields.serialize(buf); 16 | self.methods.serialize(buf); 17 | self.attributes.serialize(buf); 18 | } 19 | 20 | pub fn deserialize(stream: Box) -> Classfile { 21 | let mut buf = &mut Deserializer::new(Box::new(stream.bytes().map(|r| r.unwrap()))); 22 | let mut c = Classfile { 23 | magic: 0, 24 | minor_version: 0, 25 | major_version: 0, 26 | constant_pool: vec![], 27 | access_flags: 0, 28 | this_class: 0, 29 | super_class: 0, 30 | interfaces: vec![], 31 | fields: vec![], 32 | methods: vec![], 33 | attributes: vec![], 34 | }; 35 | c.magic = u32::deserialize(buf, &c); 36 | c.minor_version = u16::deserialize(buf, &c); 37 | c.major_version = u16::deserialize(buf, &c); 38 | c.constant_pool = Vec::deserialize(buf, &c); 39 | c.access_flags = u16::deserialize(buf, &c); 40 | c.this_class = u16::deserialize(buf, &c); 41 | c.super_class = u16::deserialize(buf, &c); 42 | c.interfaces = Vec::deserialize(buf, &c); 43 | c.fields = Vec::deserialize(buf, &c); 44 | c.methods = Vec::deserialize(buf, &c); 45 | c.attributes = Vec::deserialize(buf, &c); 46 | c 47 | } 48 | } 49 | 50 | struct Deserializer { 51 | stream: Box>, 52 | bytes_taken: u32, 53 | } 54 | 55 | impl Deserializer { 56 | fn new(stream: Box>) -> Deserializer { 57 | Deserializer { stream: stream, bytes_taken: 0 } 58 | } 59 | 60 | fn take_byte(&mut self) -> u8 { 61 | let v = self.take_bytes(1); 62 | v[0] 63 | } 64 | 65 | fn take_bytes(&mut self, n: u32) -> Vec { 66 | self.bytes_taken += n; 67 | (&mut self.stream).take(n as usize).collect() 68 | } 69 | } 70 | 71 | trait Serializable { 72 | fn serialize(self, &mut Vec); 73 | fn deserialize(&mut Deserializer, &Classfile) -> Self; 74 | } 75 | 76 | impl Serializable for u8 { 77 | fn serialize(self, buf: &mut Vec) { 78 | buf.push(self) 79 | } 80 | 81 | fn deserialize(buf: &mut Deserializer, _classfile: &Classfile) -> u8 { 82 | buf.take_byte() 83 | } 84 | } 85 | 86 | impl Serializable for u16 { 87 | fn serialize(self, buf: &mut Vec) { 88 | buf.push((self >> 8) as u8); 89 | buf.push(self as u8); 90 | } 91 | 92 | fn deserialize(buf: &mut Deserializer, _classfile: &Classfile) -> u16 { 93 | let v = buf.take_bytes(2); 94 | ((v[0] as u16) << 8) + (v[1] as u16) 95 | } 96 | } 97 | 98 | impl Serializable for u32 { 99 | fn serialize(self, buf: &mut Vec) { 100 | buf.push((self >> 24) as u8); 101 | buf.push((self >> 16) as u8); 102 | buf.push((self >> 8) as u8); 103 | buf.push(self as u8); 104 | } 105 | 106 | fn deserialize(buf: &mut Deserializer, _classfile: &Classfile) -> u32 { 107 | let v = buf.take_bytes(4); 108 | ((v[0] as u32) << 24) + ((v[1] as u32) << 16) + ((v[2] as u32) << 8) + (v[3] as u32) 109 | } 110 | } 111 | 112 | impl Serializable for String { 113 | fn serialize(self, buf: &mut Vec) { 114 | (self.len() as u16).serialize(buf); 115 | for b in self.as_bytes() { 116 | b.serialize(buf); 117 | } 118 | } 119 | 120 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> String { 121 | let len = u16::deserialize(buf, classfile); 122 | let v = buf.take_bytes(len as u32); 123 | String::from_utf8(v).unwrap() 124 | } 125 | } 126 | 127 | impl Serializable for Vec { 128 | fn serialize(self, buf: &mut Vec) { 129 | (self.len() as u32).serialize(buf); // byte vectors use a 4-byte length prefix, not 2-byte 130 | for b in self.into_iter() { 131 | b.serialize(buf); 132 | } 133 | } 134 | 135 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 136 | let len = u32::deserialize(buf, classfile); // byte vectors use a 4-byte length prefix, not 2-byte 137 | buf.take_bytes(len) 138 | } 139 | } 140 | 141 | impl Serializable for Vec { 142 | fn serialize(self, buf: &mut Vec) { 143 | ((self.len() + 1) as u16).serialize(buf); // IMPORTANT: constant_pool_length is len + 1 144 | for constant in self.into_iter() { 145 | constant.serialize(buf); 146 | } 147 | } 148 | 149 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 150 | let len = u16::deserialize(buf, classfile) - 1; // IMPORTANT: constant_pool_length is len + 1 151 | (0..len).into_iter().map(|_| Constant::deserialize(buf, classfile)).collect() 152 | } 153 | } 154 | 155 | impl Serializable for Vec { 156 | fn serialize(self, buf: &mut Vec) { 157 | (self.len() as u16).serialize(buf); 158 | for constant in self.into_iter() { 159 | constant.serialize(buf); 160 | } 161 | } 162 | 163 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 164 | let len = u16::deserialize(buf, classfile); 165 | (0..len).into_iter().map(|_| Interface::deserialize(buf, classfile)).collect() 166 | } 167 | } 168 | 169 | impl Serializable for Vec { 170 | fn serialize(self, buf: &mut Vec) { 171 | (self.len() as u16).serialize(buf); 172 | for constant in self.into_iter() { 173 | constant.serialize(buf); 174 | } 175 | } 176 | 177 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 178 | let len = u16::deserialize(buf, classfile); 179 | (0..len).into_iter().map(|_| Field::deserialize(buf, classfile)).collect() 180 | } 181 | } 182 | 183 | impl Serializable for Vec { 184 | fn serialize(self, buf: &mut Vec) { 185 | (self.len() as u16).serialize(buf); 186 | for constant in self.into_iter() { 187 | constant.serialize(buf); 188 | } 189 | } 190 | 191 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 192 | let len = u16::deserialize(buf, classfile); 193 | (0..len).into_iter().map(|_| Method::deserialize(buf, classfile)).collect() 194 | } 195 | } 196 | 197 | impl Serializable for Vec { 198 | fn serialize(self, buf: &mut Vec) { 199 | (self.len() as u16).serialize(buf); 200 | for constant in self.into_iter() { 201 | constant.serialize(buf); 202 | } 203 | } 204 | 205 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 206 | let len = u16::deserialize(buf, classfile); 207 | (0..len).into_iter().map(|_| Attribute::deserialize(buf, classfile)).collect() 208 | } 209 | } 210 | 211 | impl Serializable for Vec { 212 | fn serialize(self, buf: &mut Vec) { 213 | (self.len() as u16).serialize(buf); 214 | for constant in self.into_iter() { 215 | constant.serialize(buf); 216 | } 217 | } 218 | 219 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 220 | let len = u16::deserialize(buf, classfile); 221 | (0..len).into_iter().map(|_| ExceptionTableEntry::deserialize(buf, classfile)).collect() 222 | } 223 | } 224 | 225 | impl Serializable for Vec { 226 | fn serialize(self, buf: &mut Vec) { 227 | (self.len() as u16).serialize(buf); 228 | for constant in self.into_iter() { 229 | constant.serialize(buf); 230 | } 231 | } 232 | 233 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 234 | let len = u16::deserialize(buf, classfile); 235 | (0..len).into_iter().map(|_| LineNumberTableEntry::deserialize(buf, classfile)).collect() 236 | } 237 | } 238 | 239 | impl Serializable for Vec { 240 | fn serialize(self, buf: &mut Vec) { 241 | (self.len() as u16).serialize(buf); 242 | for constant in self.into_iter() { 243 | constant.serialize(buf); 244 | } 245 | } 246 | 247 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 248 | let len = u16::deserialize(buf, classfile); 249 | (0..len).into_iter().map(|_| StackMapFrame::deserialize(buf, classfile)).collect() 250 | } 251 | } 252 | 253 | impl Serializable for Vec { 254 | fn serialize(self, buf: &mut Vec) { 255 | (self.len() as u16).serialize(buf); 256 | for constant in self.into_iter() { 257 | constant.serialize(buf); 258 | } 259 | } 260 | 261 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 262 | let len = u16::deserialize(buf, classfile); 263 | (0..len).into_iter().map(|_| VerificationType::deserialize(buf, classfile)).collect() 264 | } 265 | } 266 | 267 | impl Serializable for Vec { 268 | fn serialize(self, buf: &mut Vec) { 269 | let mut code = vec![]; 270 | for inst in self.into_iter() { 271 | inst.serialize(&mut code); 272 | } 273 | code.serialize(buf); 274 | } 275 | 276 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Vec { 277 | let code: Vec = Vec::deserialize(buf, classfile); 278 | let code_len = code.len() as u32; 279 | let mut code_buf = &mut Deserializer::new(Box::new(code.into_iter())); 280 | let mut out = vec![]; 281 | while code_buf.bytes_taken < code_len { 282 | out.push(Instruction::deserialize(code_buf, classfile)); 283 | } 284 | out 285 | } 286 | } 287 | 288 | impl Serializable for Constant { 289 | fn serialize(self, buf: &mut Vec) { 290 | match self { 291 | Constant::Utf8(string) => { 292 | (1 as u8).serialize(buf); 293 | string.serialize(buf); 294 | }, 295 | Constant::Class(name_index) => { 296 | (7 as u8).serialize(buf); 297 | name_index.serialize(buf); 298 | }, 299 | Constant::String(string_index) => { 300 | (8 as u8).serialize(buf); 301 | string_index.serialize(buf); 302 | }, 303 | Constant::Fieldref(class_index, name_and_type_index) => { 304 | (9 as u8).serialize(buf); 305 | class_index.serialize(buf); 306 | name_and_type_index.serialize(buf); 307 | }, 308 | Constant::Methodref(class_index, name_and_type_index) => { 309 | (10 as u8).serialize(buf); 310 | class_index.serialize(buf); 311 | name_and_type_index.serialize(buf); 312 | }, 313 | Constant::NameAndType(name_index, descriptor_index) => { 314 | (12 as u8).serialize(buf); 315 | name_index.serialize(buf); 316 | descriptor_index.serialize(buf); 317 | }, 318 | } 319 | } 320 | 321 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Constant { 322 | let code = u8::deserialize(buf, classfile); 323 | match code { 324 | 1 => Constant::Utf8(String::deserialize(buf, classfile)), 325 | 7 => Constant::Class(u16::deserialize(buf, classfile)), 326 | 8 => Constant::String(u16::deserialize(buf, classfile)), 327 | 9 => Constant::Fieldref(u16::deserialize(buf, classfile), u16::deserialize(buf, classfile)), 328 | 10 => Constant::Methodref(u16::deserialize(buf, classfile), u16::deserialize(buf, classfile)), 329 | 12 => Constant::NameAndType(u16::deserialize(buf, classfile), u16::deserialize(buf, classfile)), 330 | _ => panic!("Don't know how to deserialize Constant of type: {}", code) 331 | } 332 | } 333 | } 334 | 335 | impl Serializable for Interface { 336 | fn serialize(self, _buf: &mut Vec) { 337 | panic!("TODO implement Interface::serialize") 338 | } 339 | 340 | fn deserialize(_buf: &mut Deserializer, _classfile: &Classfile) -> Interface { 341 | panic!("TODO implement Interface::deserialize") 342 | } 343 | } 344 | 345 | impl Serializable for Field { 346 | fn serialize(self, _buf: &mut Vec) { 347 | panic!("TODO implement Field::serialize") 348 | } 349 | 350 | fn deserialize(_buf: &mut Deserializer, _classfile: &Classfile) -> Field { 351 | panic!("TODO implement Field::deserialize") 352 | } 353 | } 354 | 355 | impl Serializable for Method { 356 | fn serialize(self, buf: &mut Vec) { 357 | self.access_flags.serialize(buf); 358 | self.name_index.serialize(buf); 359 | self.descriptor_index.serialize(buf); 360 | self.attributes.serialize(buf); 361 | } 362 | 363 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Method { 364 | Method { 365 | access_flags: u16::deserialize(buf, classfile), 366 | name_index: u16::deserialize(buf, classfile), 367 | descriptor_index: u16::deserialize(buf, classfile), 368 | attributes: Vec::deserialize(buf, classfile), 369 | } 370 | } 371 | } 372 | 373 | impl Serializable for Attribute { 374 | fn serialize(self, buf: &mut Vec) { 375 | // generate a temporary buffer holding the attribute "body" 376 | let mut attribute_body = vec![]; 377 | let mut attribute_name_index; 378 | 379 | { 380 | let mut body_buf = &mut attribute_body; 381 | match self { 382 | Attribute::Code(name_index, max_stack, max_locals, code, exception_table, attributes) => { 383 | attribute_name_index = name_index; 384 | 385 | max_stack.serialize(body_buf); 386 | max_locals.serialize(body_buf); 387 | code.serialize(body_buf); 388 | exception_table.serialize(body_buf); 389 | attributes.serialize(body_buf); 390 | }, 391 | Attribute::LineNumberTable(name_index, entries) => { 392 | attribute_name_index = name_index; 393 | entries.serialize(body_buf); 394 | }, 395 | Attribute::SourceFile(name_index, sourcefile_index) => { 396 | attribute_name_index = name_index; 397 | sourcefile_index.serialize(body_buf); 398 | }, 399 | Attribute::StackMapTable(name_index, entries) => { 400 | attribute_name_index = name_index; 401 | entries.serialize(body_buf); 402 | }, 403 | } 404 | } 405 | 406 | // append the attribute body to the real buffer 407 | attribute_name_index.serialize(buf); 408 | attribute_body.serialize(buf); 409 | } 410 | 411 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Attribute { 412 | let attribute_name_index = u16::deserialize(buf, classfile); 413 | let attribute_name = classfile.lookup_string(attribute_name_index); 414 | 415 | let attribute_body: Vec = Vec::deserialize(buf, classfile); 416 | let mut buf2 = &mut Deserializer::new(Box::new(attribute_body.into_iter())); 417 | 418 | match attribute_name { 419 | "Code" => { 420 | let max_stack = u16::deserialize(buf2, classfile); 421 | let max_locals = u16::deserialize(buf2, classfile); 422 | let code = Vec::deserialize(buf2, classfile); 423 | let exception_table = Vec::deserialize(buf2, classfile); 424 | let attributes = Vec::deserialize(buf2, classfile); 425 | Attribute::Code(attribute_name_index, max_stack, max_locals, code, exception_table, attributes) 426 | }, 427 | "LineNumberTable" => { 428 | let entries = Vec::deserialize(buf2, classfile); 429 | Attribute::LineNumberTable(attribute_name_index, entries) 430 | }, 431 | "SourceFile" => { 432 | let sourcefile_index = u16::deserialize(buf2, classfile); 433 | Attribute::SourceFile(attribute_name_index, sourcefile_index) 434 | }, 435 | "StackMapTable" => { 436 | let entries = Vec::deserialize(buf2, classfile); 437 | Attribute::StackMapTable(attribute_name_index, entries) 438 | }, 439 | _ => panic!("TODO implement Attribute::deserialize for attribute type: {:?}", attribute_name) 440 | 441 | } 442 | } 443 | } 444 | 445 | impl Serializable for ExceptionTableEntry { 446 | fn serialize(self, _buf: &mut Vec) { 447 | panic!("TODO implement ExceptionTableEntry::serialize") 448 | } 449 | 450 | fn deserialize(_buf: &mut Deserializer, _classfile: &Classfile) -> ExceptionTableEntry { 451 | panic!("TODO implement ExceptionTableEntry::deserialize") 452 | } 453 | } 454 | 455 | impl Serializable for LineNumberTableEntry { 456 | fn serialize(self, buf: &mut Vec) { 457 | self.start_pc.serialize(buf); 458 | self.line_number.serialize(buf); 459 | } 460 | 461 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> LineNumberTableEntry { 462 | LineNumberTableEntry { 463 | start_pc: u16::deserialize(buf, classfile), 464 | line_number: u16::deserialize(buf, classfile), 465 | } 466 | } 467 | } 468 | 469 | impl Serializable for StackMapFrame { 470 | fn serialize(self, buf: &mut Vec) { 471 | match self { 472 | StackMapFrame::SameFrame(offset_delta) => { 473 | let frame_type = offset_delta; 474 | frame_type.serialize(buf); 475 | }, 476 | StackMapFrame::SameLocals1StackItemFrame(offset_delta, verification_type) => { 477 | let frame_type = offset_delta + 64; 478 | frame_type.serialize(buf); 479 | verification_type.serialize(buf); 480 | }, 481 | StackMapFrame::SameLocals1StackItemFrameExtended(offset_delta, verification_type) => { 482 | let frame_type: u8 = 247; 483 | frame_type.serialize(buf); 484 | offset_delta.serialize(buf); 485 | verification_type.serialize(buf); 486 | }, 487 | StackMapFrame::ChopFrame(k, offset_delta) => { 488 | let frame_type = 251 - k; 489 | frame_type.serialize(buf); 490 | offset_delta.serialize(buf); 491 | }, 492 | StackMapFrame::SameFrameExtended(offset_delta) => { 493 | let frame_type: u8 = 251; 494 | frame_type.serialize(buf); 495 | offset_delta.serialize(buf); 496 | }, 497 | StackMapFrame::AppendFrame(k, offset_delta, locals) => { 498 | let frame_type = 251 + k; 499 | frame_type.serialize(buf); 500 | offset_delta.serialize(buf); 501 | for local in locals { 502 | local.serialize(buf); 503 | } 504 | }, 505 | StackMapFrame::FullFrame(offset_delta, locals, stack_items) => { 506 | let frame_type: u8 = 255; 507 | frame_type.serialize(buf); 508 | offset_delta.serialize(buf); 509 | locals.serialize(buf); 510 | stack_items.serialize(buf); 511 | }, 512 | } 513 | } 514 | 515 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> StackMapFrame { 516 | let frame_type = u8::deserialize(buf, classfile); 517 | match frame_type { 518 | 0...63 => { 519 | let offset_delta = frame_type; 520 | StackMapFrame::SameFrame(offset_delta) 521 | }, 522 | 64...127 => { 523 | let offset_delta = frame_type - 64; 524 | let verification_type = VerificationType::deserialize(buf, classfile); 525 | StackMapFrame::SameLocals1StackItemFrame(offset_delta, verification_type) 526 | }, 527 | 247 => { 528 | let offset_delta = u16::deserialize(buf, classfile); 529 | let verification_type = VerificationType::deserialize(buf, classfile); 530 | StackMapFrame::SameLocals1StackItemFrameExtended(offset_delta, verification_type) 531 | }, 532 | 248...250 => { 533 | let k = 251 - frame_type; 534 | let offset_delta = u16::deserialize(buf, classfile); 535 | StackMapFrame::ChopFrame(k, offset_delta) 536 | }, 537 | 251 => { 538 | let offset_delta = u16::deserialize(buf, classfile); 539 | StackMapFrame::SameFrameExtended(offset_delta) 540 | }, 541 | 252...254 => { 542 | let k = frame_type - 251; 543 | let offset_delta = u16::deserialize(buf, classfile); 544 | let locals = (0..k).into_iter().map(|_| VerificationType::deserialize(buf, classfile)).collect(); 545 | StackMapFrame::AppendFrame(k, offset_delta, locals) 546 | }, 547 | 255 => { 548 | let offset_delta = u16::deserialize(buf, classfile); 549 | let locals = Vec::deserialize(buf, classfile); 550 | let stack_items = Vec::deserialize(buf, classfile); 551 | StackMapFrame::FullFrame(offset_delta, locals, stack_items) 552 | }, 553 | _ => panic!("Invalid StackMapFrame type: {}", frame_type) 554 | } 555 | } 556 | } 557 | 558 | impl Serializable for VerificationType { 559 | fn serialize(self, buf: &mut Vec) { 560 | match self { 561 | VerificationType::Top => { 562 | (0 as u8).serialize(buf); 563 | }, 564 | VerificationType::Integer => { 565 | (1 as u8).serialize(buf); 566 | }, 567 | VerificationType::Float => { 568 | (2 as u8).serialize(buf); 569 | }, 570 | VerificationType::Long => { 571 | (3 as u8).serialize(buf); 572 | }, 573 | VerificationType::Double => { 574 | (4 as u8).serialize(buf); 575 | }, 576 | VerificationType::Null => { 577 | (5 as u8).serialize(buf); 578 | }, 579 | VerificationType::UninitializedThis => { 580 | (6 as u8).serialize(buf); 581 | }, 582 | VerificationType::Object(cpool_index) => { 583 | (7 as u8).serialize(buf); 584 | cpool_index.serialize(buf); 585 | }, 586 | VerificationType::Uninitialized(offset) => { 587 | (8 as u8).serialize(buf); 588 | offset.serialize(buf); 589 | }, 590 | } 591 | } 592 | 593 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> VerificationType { 594 | let verification_type = u8::deserialize(buf, classfile); 595 | match verification_type { 596 | 0 => { 597 | VerificationType::Top 598 | }, 599 | 1 => { 600 | VerificationType::Integer 601 | }, 602 | 2 => { 603 | VerificationType::Float 604 | }, 605 | 3 => { 606 | VerificationType::Long 607 | }, 608 | 4 => { 609 | VerificationType::Double 610 | }, 611 | 5 => { 612 | VerificationType::Null 613 | }, 614 | 6 => { 615 | VerificationType::UninitializedThis 616 | }, 617 | 7 => { 618 | let cpool_index = u16::deserialize(buf, classfile); 619 | VerificationType::Object(cpool_index) 620 | }, 621 | 8 => { 622 | let offset = u16::deserialize(buf, classfile); 623 | VerificationType::Uninitialized(offset) 624 | }, 625 | _ => panic!("Invalid VerificationType: {}", verification_type) 626 | } 627 | } 628 | } 629 | 630 | impl Serializable for Instruction { 631 | fn serialize(self, buf: &mut Vec) { 632 | match self { 633 | Instruction::IconstM1 => { 634 | (0x2 as u8).serialize(buf); 635 | }, 636 | Instruction::Iconst0 => { 637 | (0x3 as u8).serialize(buf); 638 | }, 639 | Instruction::Iconst1 => { 640 | (0x4 as u8).serialize(buf); 641 | }, 642 | Instruction::Iconst2 => { 643 | (0x5 as u8).serialize(buf); 644 | }, 645 | Instruction::Iconst3 => { 646 | (0x6 as u8).serialize(buf); 647 | }, 648 | Instruction::Iconst4 => { 649 | (0x7 as u8).serialize(buf); 650 | }, 651 | Instruction::Iconst5 => { 652 | (0x8 as u8).serialize(buf); 653 | }, 654 | Instruction::Bipush(val) => { 655 | (0x10 as u8).serialize(buf); 656 | val.serialize(buf); 657 | }, 658 | Instruction::LoadConstant(index) => { 659 | (0x12 as u8).serialize(buf); 660 | index.serialize(buf); 661 | }, 662 | Instruction::Aload0 => { 663 | (0x2A as u8).serialize(buf); 664 | }, 665 | Instruction::Aload1 => { 666 | (0x2B as u8).serialize(buf); 667 | }, 668 | Instruction::Aload2 => { 669 | (0x2C as u8).serialize(buf); 670 | }, 671 | Instruction::Aload3 => { 672 | (0x2D as u8).serialize(buf); 673 | }, 674 | Instruction::Aaload => { 675 | (0x32 as u8).serialize(buf); 676 | }, 677 | Instruction::IfEq(index) => { 678 | (0x99 as u8).serialize(buf); 679 | index.serialize(buf); 680 | }, 681 | Instruction::IfNe(index) => { 682 | (0x9A as u8).serialize(buf); 683 | index.serialize(buf); 684 | }, 685 | Instruction::IfLt(index) => { 686 | (0x9B as u8).serialize(buf); 687 | index.serialize(buf); 688 | }, 689 | Instruction::IfGe(index) => { 690 | (0x9C as u8).serialize(buf); 691 | index.serialize(buf); 692 | }, 693 | Instruction::IfGt(index) => { 694 | (0x9D as u8).serialize(buf); 695 | index.serialize(buf); 696 | }, 697 | Instruction::IfLe(index) => { 698 | (0x9E as u8).serialize(buf); 699 | index.serialize(buf); 700 | }, 701 | Instruction::IfIcmpEq(index) => { 702 | (0x9F as u8).serialize(buf); 703 | index.serialize(buf); 704 | }, 705 | Instruction::IfIcmpNe(index) => { 706 | (0xA0 as u8).serialize(buf); 707 | index.serialize(buf); 708 | }, 709 | Instruction::IfIcmpLt(index) => { 710 | (0xA1 as u8).serialize(buf); 711 | index.serialize(buf); 712 | }, 713 | Instruction::IfIcmpGe(index) => { 714 | (0xA2 as u8).serialize(buf); 715 | index.serialize(buf); 716 | }, 717 | Instruction::IfIcmpGt(index) => { 718 | (0xA3 as u8).serialize(buf); 719 | index.serialize(buf); 720 | }, 721 | Instruction::IfIcmpLe(index) => { 722 | (0xA4 as u8).serialize(buf); 723 | index.serialize(buf); 724 | }, 725 | Instruction::Goto(index) => { 726 | (0xA7 as u8).serialize(buf); 727 | index.serialize(buf); 728 | }, 729 | Instruction::Iadd => { 730 | (0x60 as u8).serialize(buf); 731 | }, 732 | Instruction::Return => { 733 | (0xB1 as u8).serialize(buf); 734 | }, 735 | Instruction::GetStatic(index) => { 736 | (0xB2 as u8).serialize(buf); 737 | index.serialize(buf); 738 | }, 739 | Instruction::InvokeVirtual(index) => { 740 | (0xB6 as u8).serialize(buf); 741 | index.serialize(buf); 742 | }, 743 | Instruction::InvokeSpecial(index) => { 744 | (0xB7 as u8).serialize(buf); 745 | index.serialize(buf); 746 | }, 747 | Instruction::InvokeStatic(index) => { 748 | (0xB8 as u8).serialize(buf); 749 | index.serialize(buf); 750 | }, 751 | Instruction::ArrayLength => { 752 | (0xBE as u8).serialize(buf); 753 | }, 754 | } 755 | } 756 | 757 | fn deserialize(buf: &mut Deserializer, classfile: &Classfile) -> Instruction { 758 | let code = u8::deserialize(buf, classfile); 759 | match code { 760 | 0x02 => Instruction::IconstM1, 761 | 0x03 => Instruction::Iconst0, 762 | 0x04 => Instruction::Iconst1, 763 | 0x05 => Instruction::Iconst2, 764 | 0x06 => Instruction::Iconst3, 765 | 0x07 => Instruction::Iconst4, 766 | 0x08 => Instruction::Iconst5, 767 | 0x10 => Instruction::Bipush(u8::deserialize(buf, classfile)), 768 | 0x12 => Instruction::LoadConstant(u8::deserialize(buf, classfile)), 769 | 0x2A => Instruction::Aload0, 770 | 0x2B => Instruction::Aload1, 771 | 0x2C => Instruction::Aload2, 772 | 0x2D => Instruction::Aload3, 773 | 0x32 => Instruction::Aaload, 774 | 0x99 => Instruction::IfEq(u16::deserialize(buf, classfile)), 775 | 0x9A => Instruction::IfNe(u16::deserialize(buf, classfile)), 776 | 0x9B => Instruction::IfLt(u16::deserialize(buf, classfile)), 777 | 0x9C => Instruction::IfGe(u16::deserialize(buf, classfile)), 778 | 0x9D => Instruction::IfGt(u16::deserialize(buf, classfile)), 779 | 0x9E => Instruction::IfLe(u16::deserialize(buf, classfile)), 780 | 0x9F => Instruction::IfIcmpEq(u16::deserialize(buf, classfile)), 781 | 0xA0 => Instruction::IfIcmpNe(u16::deserialize(buf, classfile)), 782 | 0xA1 => Instruction::IfIcmpLt(u16::deserialize(buf, classfile)), 783 | 0xA2 => Instruction::IfIcmpGe(u16::deserialize(buf, classfile)), 784 | 0xA3 => Instruction::IfIcmpGt(u16::deserialize(buf, classfile)), 785 | 0xA4 => Instruction::IfIcmpLe(u16::deserialize(buf, classfile)), 786 | 0xA7 => Instruction::Goto(u16::deserialize(buf, classfile)), 787 | 0x60 => Instruction::Iadd, 788 | 0xB1 => Instruction::Return, 789 | 0xB2 => Instruction::GetStatic(u16::deserialize(buf, classfile)), 790 | 0xB6 => Instruction::InvokeVirtual(u16::deserialize(buf, classfile)), 791 | 0xB7 => Instruction::InvokeSpecial(u16::deserialize(buf, classfile)), 792 | 0xB8 => Instruction::InvokeStatic(u16::deserialize(buf, classfile)), 793 | 0xBE => Instruction::ArrayLength, 794 | _ => panic!("Don't know how to deserialize Instruction of type: 0x{:X}", code) 795 | } 796 | 797 | } 798 | } 799 | --------------------------------------------------------------------------------