diff --git a/Cargo.lock b/Cargo.lock index b3948b7..d0a2761 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,110 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "indexmap" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ristretto_classfile" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83023fe9f9154bbdbaffb4e3f2767509baf9dc4b3e9c725b8ae845abe2bbd23c" +dependencies = [ + "bitflags", + "byteorder", + "indexmap", + "thiserror", +] + [[package]] name = "rustc_codegen_jvm" version = "0.1.0" +dependencies = [ + "ristretto_classfile", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/Cargo.toml b/Cargo.toml index 2eaa04d..8354ac9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +ristretto_classfile = { version = "0.14.0" } [lib] crate-type = ["dylib"] diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 07ade69..0000000 --- a/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -nightly \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..14d8e6c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly" +components = ["rustc-dev", "llvm-tools-preview"] diff --git a/setup.sh b/setup.sh old mode 100644 new mode 100755 diff --git a/src/lib.rs b/src/lib.rs index 0192c3e..9991169 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,20 +20,20 @@ extern crate rustc_middle; extern crate rustc_session; extern crate rustc_target; +use rustc_codegen_ssa::back::archive::{ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder}; use rustc_codegen_ssa::{ CodegenResults, CompiledModule, CrateInfo, ModuleKind, traits::CodegenBackend, }; use rustc_data_structures::fx::FxIndexMap; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::ty::{Instance, Ty, TyCtxt}; -use rustc_session::{Session, config::OutputFilenames}; -use std::{any::Any, io::Write, path::Path, vec}; use rustc_middle::mir::{ BasicBlock, BasicBlockData, BinOp, Body, Location, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, visit::Visitor, }; -use rustc_codegen_ssa::back::archive::{ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder}; +use rustc_middle::ty::{Instance, Ty, TyCtxt}; +use rustc_session::{Session, config::OutputFilenames}; +use std::{any::Any, io::Write, path::Path, vec}; /// An instance of our Java bytecode codegen backend. struct MyBackend; @@ -73,7 +73,7 @@ impl CodegenBackend for MyBackend { let mir = tcx.optimized_mir(instance.def_id()); println!("--- Starting MIR Visitor for function: {i} ---"); - let method_bytecode_instructions: Vec = Vec::new(); + let method_bytecode_instructions: Vec = Vec::new(); let function_name = i.to_string(); // Capture function name let mut visitor = MirToBytecodeVisitor::new( method_bytecode_instructions, @@ -95,7 +95,8 @@ impl CodegenBackend for MyBackend { crate_name.as_str(), &function_bytecodes, tcx, - ); // Modified function to pass tcx + ) + .unwrap_or_default(); // Modified function to pass tcx Box::new(( bytecode, @@ -118,8 +119,8 @@ impl CodegenBackend for MyBackend { let class_path = outputs.temp_path_ext("class", None); - let mut class_file = std::fs::File::create(&class_path) - .expect("Could not create the Java .class file!"); + let mut class_file = + std::fs::File::create(&class_path).expect("Could not create the Java .class file!"); class_file .write_all(&bytecode) .expect("Could not write Java bytecode to file!"); @@ -151,7 +152,7 @@ impl CodegenBackend for MyBackend { use rustc_codegen_ssa::back::link::link_binary; link_binary(sess, &RlibArchiveBuilder, codegen_results, outputs); - } + } } #[unsafe(no_mangle)] @@ -160,134 +161,55 @@ pub extern "Rust" fn __rustc_codegen_backend() -> Box { Box::new(MyBackend) } +use ristretto_classfile::attributes::{Attribute, Instruction}; +use ristretto_classfile::{ + BaseType, ClassAccessFlags, ClassFile, ConstantPool, Method, MethodAccessFlags, Version, +}; use std::alloc::Layout; + /// # Panics -/// +/// /// Panics when called, every time, with a message statating the memory allocation of the bytes /// corresponding to the provided layout failed. pub fn custom_alloc_error_hook(layout: Layout) { panic!("Memory allocation failed: {} bytes", layout.size()); } -// --- Constant Pool Helper Functions --- - -fn add_utf8_constant( - constant_pool: &mut Vec, - constant_pool_count: &mut u16, - text: &str, -) -> u16 { - let index = *constant_pool_count; - *constant_pool_count += 1; - - constant_pool.push(0x01); // CONSTANT_Utf8 tag - let utf8_bytes = text.as_bytes(); - constant_pool.extend_from_slice(&(utf8_bytes.len() as u16).to_be_bytes()); - constant_pool.extend_from_slice(utf8_bytes); - - index -} - -fn add_class_constant( - constant_pool: &mut Vec, - constant_pool_count: &mut u16, - name_index: u16, -) -> u16 { - let index = *constant_pool_count; - *constant_pool_count += 1; - - constant_pool.push(0x07); // CONSTANT_Class tag - constant_pool.extend_from_slice(&name_index.to_be_bytes()); - - index -} - -fn add_name_and_type_constant( - constant_pool: &mut Vec, - constant_pool_count: &mut u16, - name_index: u16, - descriptor_index: u16, -) -> u16 { - let index = *constant_pool_count; - *constant_pool_count += 1; - - constant_pool.push(0x0c); // CONSTANT_NameAndType tag - constant_pool.extend_from_slice(&name_index.to_be_bytes()); - constant_pool.extend_from_slice(&descriptor_index.to_be_bytes()); - - index -} - -// Unused for now, useful for later -#[allow(dead_code)] -fn add_fieldref_constant( - constant_pool: &mut Vec, - constant_pool_count: &mut u16, - class_index: u16, - name_and_type_index: u16, -) -> u16 { - let index = *constant_pool_count; - *constant_pool_count += 1; - - constant_pool.push(0x09); // CONSTANT_Fieldref tag - constant_pool.extend_from_slice(&class_index.to_be_bytes()); - constant_pool.extend_from_slice(&name_and_type_index.to_be_bytes()); - - index -} - -// Unused for now, useful for later -#[allow(dead_code)] -fn add_methodref_constant( - constant_pool: &mut Vec, - constant_pool_count: &mut u16, - class_index: u16, - name_and_type_index: u16, -) -> u16 { - let index = *constant_pool_count; - *constant_pool_count += 1; - - constant_pool.push(0x0a); // CONSTANT_Methodref tag - constant_pool.extend_from_slice(&class_index.to_be_bytes()); - constant_pool.extend_from_slice(&name_and_type_index.to_be_bytes()); - - index -} - // --- Improved helper function to convert Rust Ty to JVM descriptor --- fn rust_ty_to_jvm_descriptor(rust_ty: Ty<'_>, _tcx: TyCtxt<'_>) -> String { - use rustc_middle::ty::{TyKind, IntTy, UintTy, FloatTy}; + use rustc_middle::ty::{FloatTy, IntTy, TyKind, UintTy}; match rust_ty.kind() { // Primitive types - TyKind::Bool => "Z".to_string(), // JVM boolean - TyKind::Char => "C".to_string(), // JVM char + TyKind::Bool => BaseType::Boolean.code().to_string(), + TyKind::Char => BaseType::Char.code().to_string(), // Signed integers mapped to JVM types or fallback to BigInteger for i128 TyKind::Int(int_ty) => match int_ty { - IntTy::I8 => "B".to_string(), // JVM byte - IntTy::I16 => "S".to_string(), // JVM short - IntTy::I32 => "I".to_string(), // JVM int - IntTy::I64 => "J".to_string(), // JVM long - IntTy::Isize => "I".to_string(), // Fallback for isize - IntTy::I128 => "Ljava/math/BigInteger;".to_string(), // No primitive for i128 + IntTy::I8 => BaseType::Byte.code().to_string(), + IntTy::I16 => BaseType::Short.code().to_string(), + IntTy::I32 => BaseType::Int.code().to_string(), + IntTy::I64 => BaseType::Long.code().to_string(), + IntTy::Isize => BaseType::Int.code().to_string(), // Fallback for isize + IntTy::I128 => "Ljava/math/BigInteger;".to_string(), // No primitive for i128 }, // Unsigned integers mapped to JVM types or fallback to BigInteger for u128 TyKind::Uint(uint_ty) => match uint_ty { - UintTy::U8 => "B".to_string(), // JVM byte - UintTy::U16 => "S".to_string(), // JVM short - UintTy::U32 => "I".to_string(), // JVM int - UintTy::U64 => "J".to_string(), // JVM long - UintTy::Usize => "I".to_string(), // Fallback for usize - UintTy::U128 => "Ljava/math/BigInteger;".to_string(), // No primitive for u128 + UintTy::U8 => BaseType::Byte.code().to_string(), + UintTy::U16 => BaseType::Short.code().to_string(), + UintTy::U32 => BaseType::Int.code().to_string(), + UintTy::U64 => BaseType::Long.code().to_string(), + UintTy::Usize => BaseType::Int.code().to_string(), // Fallback for usize + UintTy::U128 => "Ljava/math/BigInteger;".to_string(), // No primitive for u128 }, // Floating-point numbers mapped to appropriate JVM primitives. TyKind::Float(float_ty) => match float_ty { - FloatTy::F32 => "F".to_string(), // JVM float - FloatTy::F64 => "D".to_string(), // JVM double - FloatTy::F16 => "F".to_string(), // Fallback for half-precision float - FloatTy::F128 => "D".to_string(), // Fallback for extended precision + FloatTy::F32 => BaseType::Float.code().to_string(), + FloatTy::F64 => BaseType::Double.code().to_string(), + FloatTy::F16 => BaseType::Float.code().to_string(), // Fallback for half-precision float + FloatTy::F128 => BaseType::Double.code().to_string(), // Fallback for extended precision }, // Handle references: if it’s a string slice, map it to java.lang.String; @@ -298,7 +220,7 @@ fn rust_ty_to_jvm_descriptor(rust_ty: Ty<'_>, _tcx: TyCtxt<'_>) -> String { } else { "Ljava/lang/Object;".to_string() } - }, + } // For raw pointers, allow string pointers but panic otherwise. TyKind::RawPtr(ptr_ty, _) => { @@ -307,7 +229,7 @@ fn rust_ty_to_jvm_descriptor(rust_ty: Ty<'_>, _tcx: TyCtxt<'_>) -> String { } else { panic!("Pointers are not supported in Java.") } - }, + } // Map Rust string slices directly to java.lang.String TyKind::Str => "Ljava/lang/String;".to_string(), @@ -320,7 +242,7 @@ fn rust_ty_to_jvm_descriptor(rust_ty: Ty<'_>, _tcx: TyCtxt<'_>) -> String { } else { "Ljava/lang/Object;".to_string() } - }, + } // Map Rust's never type to void (even though it is conceptually different) TyKind::Never => "V".to_string(), @@ -333,7 +255,7 @@ fn rust_ty_to_jvm_descriptor(rust_ty: Ty<'_>, _tcx: TyCtxt<'_>) -> String { // --- MIR Visitor --- struct MirToBytecodeVisitor<'tcx> { - method_bytecode_instructions: Vec, + method_bytecode_instructions: Vec, function_name: String, // Store function name tcx: TyCtxt<'tcx>, // Store TyCtxt instance: Instance<'tcx>, // Store Instance @@ -341,7 +263,7 @@ struct MirToBytecodeVisitor<'tcx> { impl<'tcx> MirToBytecodeVisitor<'tcx> { fn new( - method_bytecode_instructions: Vec, + method_bytecode_instructions: Vec, function_name: &str, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -390,11 +312,11 @@ impl Visitor<'_> for MirToBytecodeVisitor<'_> { // --- Generate Java bytecode for iadd --- // Load the first operand (argument 0) - self.method_bytecode_instructions.push(0x1a); // iload_0 + self.method_bytecode_instructions.push(Instruction::Iload_0); // Load the second operand (argument 1) - self.method_bytecode_instructions.push(0x1b); // iload_1 + self.method_bytecode_instructions.push(Instruction::Iload_1); // Perform integer addition - self.method_bytecode_instructions.push(0x60); // iadd + self.method_bytecode_instructions.push(Instruction::Iadd); println!(" Generated bytecode: iload_0, iload_1, iadd"); // --- End bytecode generation --- } @@ -406,11 +328,11 @@ impl Visitor<'_> for MirToBytecodeVisitor<'_> { // --- Generate Java bytecode for isub --- // Load the first operand (argument 0) - self.method_bytecode_instructions.push(0x1a); // iload_0 + self.method_bytecode_instructions.push(Instruction::Iload_0); // Load the second operand (argument 1) - self.method_bytecode_instructions.push(0x1b); // iload_1 + self.method_bytecode_instructions.push(Instruction::Iload_1); // Perform integer subtraction - self.method_bytecode_instructions.push(0x64); // isub + self.method_bytecode_instructions.push(Instruction::Isub); println!(" Generated bytecode: iload_0, iload_1, isub"); // --- End bytecode generation --- } @@ -440,21 +362,21 @@ impl Visitor<'_> for MirToBytecodeVisitor<'_> { match jvm_return_descriptor.as_str() { "V" => { - self.method_bytecode_instructions.push(0xb1); // _return for void + self.method_bytecode_instructions.push(Instruction::Return); // _return for void println!(" Generated bytecode: return (_return)"); } "I" | "F" | "Z" | "B" | "C" | "S" => { // Integer, Float, Boolean, Byte, Char, Short returns - self.method_bytecode_instructions.push(0xac); // ireturn (return integer value) - Correct return for i32, and others mapped to 'I' + self.method_bytecode_instructions.push(Instruction::Ireturn); // ireturn (return integer value) - Correct return for i32, and others mapped to 'I' println!(" Generated bytecode: ireturn"); } "Ljava/lang/String;" | "Ljava/lang/Object;" => { // Object returns (String, etc. for now) - self.method_bytecode_instructions.push(0xb0); // areturn (return object reference) + self.method_bytecode_instructions.push(Instruction::Areturn); // areturn (return object reference) println!(" Generated bytecode: areturn"); } _ => { - self.method_bytecode_instructions.push(0xb1); // default to void return if type is unknown or unsupported for now + self.method_bytecode_instructions.push(Instruction::Return); // default to void return if type is unknown or unsupported for now println!( " Generated bytecode: return (_return) - default void return for unknown type" ); @@ -467,49 +389,18 @@ impl Visitor<'_> for MirToBytecodeVisitor<'_> { fn generate_class_with_static_methods_bytecode( crate_name: &str, - function_bytecodes: &FxIndexMap>, + function_bytecodes: &FxIndexMap>, tcx: TyCtxt<'_>, // Take TyCtxt as argument -) -> Vec { - let mut bytecode: Vec = Vec::new(); - - // 1. Magic Number and Version (same as before) - bytecode.extend_from_slice(&[0xCA, 0xFE, 0xBA, 0xBE]); - bytecode.extend_from_slice(&[0x00, 0x00, 0x00, 0x34]); - - // 3. Constant Pool (modified) - let mut constant_pool: Vec = Vec::new(); - let mut constant_pool_count = 1; - - // Class name is the crate name - let class_name_index = - add_utf8_constant(&mut constant_pool, &mut constant_pool_count, crate_name); - let basic_class_index = add_class_constant( - &mut constant_pool, - &mut constant_pool_count, - class_name_index, - ); - - // Superclass "java/lang/Object" (same as before) - let object_class_name_index = add_utf8_constant( - &mut constant_pool, - &mut constant_pool_count, - "java/lang/Object", - ); - let object_class_index = add_class_constant( - &mut constant_pool, - &mut constant_pool_count, - object_class_name_index, - ); // Moved definition up - - // Constant pool entries for each function - let mut method_constant_pool_indices = FxIndexMap::default(); // Store indices for each method - - for (function_name, _method_bytecode_instructions) in function_bytecodes { - // Changed to borrow &function_bytecodes - // Method name (e.g., "add") - let method_name_index = - add_utf8_constant(&mut constant_pool, &mut constant_pool_count, function_name); +) -> ristretto_classfile::Result> { + let mut constant_pool = ConstantPool::default(); + let super_class = constant_pool.add_class("java/lang/Object")?; + let this_class = constant_pool.add_class(crate_name)?; + let code_index = constant_pool.add_utf8("Code")?; + let mut methods = Vec::new(); + + for (function_name, method_bytecode_instructions) in function_bytecodes { + let method_name_index = constant_pool.add_utf8(function_name)?; // Method descriptor - determine based on function signature, special case for "main" let instance = find_instance_by_name(tcx, function_name).expect("Instance not found for function"); @@ -532,107 +423,44 @@ fn generate_class_with_static_methods_bytecode( let output_ty = fn_sig.skip_binder().output(); method_descriptor.push_str(&rust_ty_to_jvm_descriptor(output_ty.skip_binder(), tcx)); } + let method_descriptor_index = constant_pool.add_utf8(method_descriptor)?; - let method_descriptor_index = add_utf8_constant( - &mut constant_pool, - &mut constant_pool_count, - &method_descriptor, - ); - - // NameAndType for the method - let method_name_and_type_index = add_name_and_type_constant( - &mut constant_pool, - &mut constant_pool_count, - method_name_index, - method_descriptor_index, - ); - method_constant_pool_indices.insert( - function_name.clone(), - ( - method_name_index, - method_descriptor_index, - method_name_and_type_index, - ), - ); - } - - // "Code" attribute name (same as before) - let code_attribute_name_index = - add_utf8_constant(&mut constant_pool, &mut constant_pool_count, "Code"); - - bytecode.extend_from_slice(&constant_pool_count.to_be_bytes()); // Constant pool count - bytecode.extend_from_slice(&constant_pool); - - // 4. Access Flags, This Class, Superclass, Interfaces Count, Fields Count (same as before) - bytecode.extend_from_slice(&[0x00, 0x21]); // Access flags (public class, ACC_SUPER) - bytecode.extend_from_slice(&basic_class_index.to_be_bytes()); // This Class - bytecode.extend_from_slice(&object_class_index.to_be_bytes()); // Superclass - bytecode.extend_from_slice(&[0x00, 0x00]); // Interfaces Count - bytecode.extend_from_slice(&[0x00, 0x00]); // Fields Count - - // 9. Methods Count (now based on the number of functions) - bytecode.extend_from_slice(&(function_bytecodes.len() as u16).to_be_bytes()); + let mut method = Method { + access_flags: MethodAccessFlags::PUBLIC | MethodAccessFlags::STATIC, + name_index: method_name_index, + descriptor_index: method_descriptor_index, + attributes: Vec::new(), + }; - // --- Method Definitions for each function --- - for (function_name, method_bytecode_instructions) in function_bytecodes { - let (_method_name_index, method_descriptor_index, _method_name_and_type_index) = - method_constant_pool_indices.get(function_name).unwrap(); - - // --- Method Definition --- - // Access flags (public static) - bytecode.extend_from_slice(&[0x00, 0x09]); // ACC_PUBLIC, ACC_STATIC - // Name index (index to function name - fetch from method_constant_pool_indices) - let method_name_index_for_bytecode = - method_constant_pool_indices.get(function_name).unwrap().0; // Get name index - bytecode.extend_from_slice(&method_name_index_for_bytecode.to_be_bytes()); - // Descriptor index (fetch from method_constant_pool_indices) - bytecode.extend_from_slice(&method_descriptor_index.to_be_bytes()); - // Attributes count (1, for Code attribute) - bytecode.extend_from_slice(&[0x00, 0x01]); - - // --- Code Attribute for method --- - // Attribute name index (index to "Code") - bytecode.extend_from_slice(&code_attribute_name_index.to_be_bytes()); - // Attribute length (placeholder, updated later) - bytecode.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); - - let mut code_attribute_bytecode: Vec = Vec::new(); // Calculate max stack size based on instructions let max_stack = calculate_max_stack_size(method_bytecode_instructions); - code_attribute_bytecode.extend_from_slice(&max_stack.to_be_bytes()); - // Max locals (adjust based on function arguments and locals) - for main, 1 for args array - let instance = - find_instance_by_name(tcx, function_name).expect("Instance not found for function"); - let fn_sig = tcx.fn_sig(instance.def_id()); let max_locals = fn_sig.skip_binder().inputs().skip_binder().len() as u16 + 1; // +1 for 'this' (even for static methods in JVM, slot 0 exists) // Skip binder twice! - code_attribute_bytecode.extend_from_slice(&(max_locals as u16).to_be_bytes()); - // Code length (placeholder, updated later) - let code_length_placeholder_index = code_attribute_bytecode.len(); - code_attribute_bytecode.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); - - let code_length = method_bytecode_instructions.len() as u32; - let code_length_bytes = code_length.to_be_bytes(); - code_attribute_bytecode[code_length_placeholder_index..code_length_placeholder_index + 4] - .copy_from_slice(&code_length_bytes); - code_attribute_bytecode.extend_from_slice(method_bytecode_instructions); // Use function's bytecode - // Exception table length (0) - code_attribute_bytecode.extend_from_slice(&[0x00, 0x00]); - // Attributes count in Code attribute (0) - code_attribute_bytecode.extend_from_slice(&[0x00, 0x00]); - - // Update attribute_length placeholder - let attribute_length = code_attribute_bytecode.len() as u32; - let attribute_length_bytes = attribute_length.to_be_bytes(); - let len = bytecode.len() - 4; - bytecode[len..].copy_from_slice(&attribute_length_bytes); - - bytecode.extend_from_slice(&code_attribute_bytecode); - } - // 10. Attributes Count (0) (same as before) - bytecode.extend_from_slice(&[0x00, 0x00]); + method.attributes.push(Attribute::Code { + name_index: code_index, + max_stack, + max_locals, + code: method_bytecode_instructions.clone(), + exception_table: Vec::new(), + attributes: Vec::new(), + }); + methods.push(method); + } - bytecode + let class_file = ClassFile { + version: Version::Java8 { minor: 0 }, + access_flags: ClassAccessFlags::PUBLIC | ClassAccessFlags::SUPER, + constant_pool, + this_class, + super_class, + methods, + ..Default::default() + }; + class_file.verify()?; + + let mut bytes = Vec::new(); + class_file.to_bytes(&mut bytes)?; + Ok(bytes) } // Helper function to find Instance by function name (for descriptor generation) @@ -650,15 +478,12 @@ fn find_instance_by_name<'tcx>(tcx: TyCtxt<'tcx>, function_name: &str) -> Option None // Instance not found } -fn calculate_max_stack_size(instructions: &[u8]) -> u16 { +fn calculate_max_stack_size(instructions: &Vec) -> u16 { let mut stack_depth: i32 = 0; let mut max_stack_depth: i32 = 0; - let mut instruction_pointer = 0; - while instruction_pointer < instructions.len() { - let opcode = instructions[instruction_pointer]; - instruction_pointer += 1; - + for instruction in instructions { + let opcode = instruction.code(); let stack_effect: i32 = match opcode { // 0x03 to 0x08 is iconst_m1, iconst_0, ..., iconst_5 // 0x1a to 0x23 is iload_0, iload_1, ..., iload_3, iload, aload @@ -704,4 +529,4 @@ impl ArchiveBuilderBuilder for RlibArchiveBuilder { ) { unimplemented!("creating dll imports is not supported"); } -} \ No newline at end of file +}