1use super::class_file_parser::{ClassFile, ClassFileParser, MethodInfo};
2use super::jvm_types::{ConstantPool, ConstantPoolEntry, JvmInstruction};
3use crate::error::RuntimeError;
4use std::collections::HashMap;
5use std::fs;
6
7#[derive(Debug, Clone, PartialEq)]
8pub enum JvmValue {
9 Int(i32),
10 Float(f32),
11 Long(i64),
12 Double(f64),
13 Boolean(bool),
14 Char(u16),
15 Reference(Option<usize>),
16 ReturnAddress(usize),
17}
18
19#[derive(Debug, Clone)]
20enum ResolvedMethod {
21 PrintStreamPrintln, PrintStreamPrint, PrintStreamPrintlnString, PrintStreamPrintlnFloat, PrintStreamPrintlnDouble, PrintStreamPrintlnBoolean, PrintStreamPrintlnChar, MathRandom, MathMaxInt, MathMinInt, MathMaxDouble, MathMinDouble, MathAbs, MathAbsDouble, MathPow, MathSqrt, MathFloor, MathCeil, MathRound, MathSin, MathCos, MathTan, MathLog, MathExp, StringLength, StringBuilderAppendString, StringBuilderAppendInt, StringBuilderAppendDouble, StringBuilderToString, StringCharAt, StringSubstring, StringIndexOf, StringToUpperCase, StringToLowerCase, StringTrim, StringEquals, StringConcat, IntegerParseInt, IntegerToString, IntegerValueOf, DoubleParseDouble, DoubleToString, DoubleValueOf, BooleanParseBoolean, BooleanToString, BooleanValueOf, CharacterIsDigit, CharacterIsLetter, CharacterToUpperCase, CharacterToLowerCase, Unknown,
88}
89
90impl JvmValue {
91 pub fn as_int(&self) -> Result<i32, RuntimeError> {
92 match self {
93 JvmValue::Int(i) => Ok(*i),
94 JvmValue::Float(f) => Ok(*f as i32),
95 JvmValue::Char(c) => Ok(*c as i32),
96 JvmValue::Boolean(b) => Ok(if *b { 1 } else { 0 }),
97 _ => Err(RuntimeError::InvalidStackState),
98 }
99 }
100
101 pub fn as_float(&self) -> Result<f32, RuntimeError> {
102 match self {
103 JvmValue::Int(i) => Ok(*i as f32),
104 JvmValue::Float(f) => Ok(*f),
105 _ => Err(RuntimeError::InvalidStackState),
106 }
107 }
108
109 pub fn as_double(&self) -> Result<f64, RuntimeError> {
110 match self {
111 JvmValue::Double(d) => Ok(*d),
112 JvmValue::Float(f) => Ok(*f as f64),
113 JvmValue::Int(i) => Ok(*i as f64),
114 JvmValue::Long(l) => Ok(*l as f64),
115 _ => Err(RuntimeError::InvalidStackState),
116 }
117 }
118
119 pub fn as_char(&self) -> Result<u16, RuntimeError> {
120 match self {
121 JvmValue::Char(c) => Ok(*c),
122 JvmValue::Int(i) => Ok(*i as u16),
123 _ => Err(RuntimeError::InvalidStackState),
124 }
125 }
126
127 pub fn as_boolean(&self) -> Result<bool, RuntimeError> {
128 match self {
129 JvmValue::Boolean(b) => Ok(*b),
130 JvmValue::Int(i) => Ok(*i != 0),
131 _ => Err(RuntimeError::InvalidStackState),
132 }
133 }
134
135 pub fn is_null(&self) -> bool {
136 matches!(self, JvmValue::Reference(None))
137 }
138}
139
140#[derive(Debug, Clone)]
141pub struct MethodFrame {
142 pub locals: Vec<JvmValue>,
143 pub operand_stack: Vec<JvmValue>,
144 pub constant_pool: ConstantPool,
145 pub pc: usize,
146 pub bytecode: Vec<JvmInstruction>,
147}
148
149pub struct JvmCompatibleVm {
150 frames: Vec<MethodFrame>,
151 heap: HashMap<usize, JvmObject>,
152 string_data: HashMap<usize, String>,
153 next_object_id: usize,
154 max_steps: usize,
155 steps: usize,
156 verbose: bool,
157 current_class: Option<ClassFile>,
158}
159
160#[derive(Debug, Clone)]
161pub struct JvmObject {
162 pub class_name: String,
163 pub fields: HashMap<String, JvmValue>,
164}
165
166impl JvmCompatibleVm {
167 pub fn new() -> Self {
168 Self {
169 frames: Vec::new(),
170 heap: HashMap::new(),
171 string_data: HashMap::new(),
172 next_object_id: 1,
173 max_steps: 100_000,
174 steps: 0,
175 verbose: false,
176 current_class: None,
177 }
178 }
179
180 pub fn set_verbose(&mut self, verbose: bool) {
181 self.verbose = verbose;
182 }
183
184 fn create_string_object(&mut self, value: String) -> usize {
185 let object_id = self.next_object_id;
186 self.next_object_id += 1;
187
188 let mut fields = HashMap::new();
189 fields.insert("length".to_string(), JvmValue::Int(value.len() as i32));
190
191 let string_object = JvmObject {
192 class_name: "java/lang/String".to_string(),
193 fields,
194 };
195
196 self.heap.insert(object_id, string_object);
197 self.string_data.insert(object_id, value);
199
200 object_id
201 }
202
203 pub fn execute_method(
204 &mut self,
205 bytecode: Vec<JvmInstruction>,
206 constant_pool: ConstantPool,
207 max_locals: usize,
208 ) -> Result<Option<JvmValue>, RuntimeError> {
209 let frame = MethodFrame {
210 locals: vec![JvmValue::Int(0); max_locals],
211 operand_stack: Vec::new(),
212 constant_pool,
213 pc: 0,
214 bytecode,
215 };
216
217 self.frames.push(frame);
218 self.steps = 0;
219
220 while !self.frames.is_empty() {
221 if self.steps >= self.max_steps {
222 return Err(RuntimeError::InvalidStackState);
223 }
224
225 let result = self.execute_single_instruction()?;
226 self.steps += 1;
227
228 if let Some(return_value) = result {
229 return Ok(Some(return_value));
230 }
231 }
232
233 Ok(None)
234 }
235
236 pub fn execute_class_file(
238 &mut self,
239 class_file_path: &str,
240 ) -> Result<Option<JvmValue>, RuntimeError> {
241 let class_file_path = if class_file_path.ends_with(".class") {
243 class_file_path.to_string()
244 } else {
245 format!("{class_file_path}.class")
246 };
247
248 if self.verbose {
249 eprintln!("Reading class file: {class_file_path}");
250 }
251
252 let class_data = fs::read(&class_file_path).map_err(|_| RuntimeError::InvalidStackState)?;
254
255 if self.verbose {
256 eprintln!("Class file size: {} bytes", class_data.len());
257 }
258
259 let class_file = ClassFileParser::parse(&class_data)?;
261
262 if self.verbose {
263 eprintln!("Parsed class file successfully");
264 eprintln!(
265 "Main method bytecode length: {}",
266 class_file.main_method_bytecode.len()
267 );
268 eprintln!(
269 "Constant pool size: {}",
270 class_file.constant_pool.entries().len()
271 );
272 eprintln!("Max locals: {}", class_file.max_locals);
273 }
274
275 let main_method_bytecode = class_file.main_method_bytecode.clone();
277 let constant_pool = class_file.constant_pool.clone();
278 let max_locals = class_file.max_locals;
279 self.current_class = Some(class_file);
280
281 if self.verbose {
282 eprintln!("Starting main method execution");
283 }
284
285 self.execute_method(main_method_bytecode, constant_pool, max_locals)
287 }
288
289 fn execute_single_instruction(&mut self) -> Result<Option<JvmValue>, RuntimeError> {
290 let frame = self
291 .frames
292 .last_mut()
293 .ok_or(RuntimeError::CallStackUnderflow)?;
294
295 if frame.pc >= frame.bytecode.len() {
296 self.frames.pop();
297 return Ok(None);
298 }
299
300 let instruction = frame.bytecode[frame.pc].clone();
301 if self.verbose {
302 eprintln!("PC {}: Executing instruction: {:?}", frame.pc, instruction);
303 }
304
305 match instruction {
306 JvmInstruction::IconstM1 => {
307 frame.operand_stack.push(JvmValue::Int(-1));
308 frame.pc += 1;
309 }
310 JvmInstruction::Iconst0 => {
311 frame.operand_stack.push(JvmValue::Int(0));
312 frame.pc += 1;
313 }
314 JvmInstruction::Iconst1 => {
315 frame.operand_stack.push(JvmValue::Int(1));
316 frame.pc += 1;
317 }
318 JvmInstruction::Iconst2 => {
319 frame.operand_stack.push(JvmValue::Int(2));
320 frame.pc += 1;
321 }
322 JvmInstruction::Iconst3 => {
323 frame.operand_stack.push(JvmValue::Int(3));
324 frame.pc += 1;
325 }
326 JvmInstruction::Iconst4 => {
327 frame.operand_stack.push(JvmValue::Int(4));
328 frame.pc += 1;
329 }
330 JvmInstruction::Iconst5 => {
331 frame.operand_stack.push(JvmValue::Int(5));
332 frame.pc += 1;
333 }
334 JvmInstruction::Lconst0 => {
335 frame.operand_stack.push(JvmValue::Long(0));
336 frame.pc += 1;
337 }
338 JvmInstruction::Lconst1 => {
339 frame.operand_stack.push(JvmValue::Long(1));
340 frame.pc += 1;
341 }
342 JvmInstruction::Bipush(value) => {
343 frame.operand_stack.push(JvmValue::Int(value as i32));
344 frame.pc += 1;
345 }
346 JvmInstruction::Sipush(value) => {
347 frame.operand_stack.push(JvmValue::Int(value as i32));
348 frame.pc += 1;
349 }
350 JvmInstruction::Ldc(index) => {
351 let value = self.load_constant_from_pool(index)?;
352 let frame = self
353 .frames
354 .last_mut()
355 .ok_or(RuntimeError::CallStackUnderflow)?;
356 frame.operand_stack.push(value);
357 frame.pc += 1;
358 }
359 JvmInstruction::Ldc2W(index) => {
360 let value = self.load_constant_from_pool(index)?;
361 let frame = self
362 .frames
363 .last_mut()
364 .ok_or(RuntimeError::CallStackUnderflow)?;
365 frame.operand_stack.push(value);
366 frame.pc += 1;
367 }
368
369 JvmInstruction::Pop => {
370 frame
371 .operand_stack
372 .pop()
373 .ok_or(RuntimeError::StackUnderflow)?;
374 frame.pc += 1;
375 }
376 JvmInstruction::Dup => {
377 let value = frame
378 .operand_stack
379 .last()
380 .ok_or(RuntimeError::StackUnderflow)?
381 .clone();
382 frame.operand_stack.push(value);
383 frame.pc += 1;
384 }
385 JvmInstruction::Swap => {
386 let len = frame.operand_stack.len();
387 if len < 2 {
388 return Err(RuntimeError::StackUnderflow);
389 }
390 frame.operand_stack.swap(len - 1, len - 2);
391 frame.pc += 1;
392 }
393
394 JvmInstruction::Iadd => {
395 let b = frame
396 .operand_stack
397 .pop()
398 .ok_or(RuntimeError::StackUnderflow)?
399 .as_int()?;
400 let a = frame
401 .operand_stack
402 .pop()
403 .ok_or(RuntimeError::StackUnderflow)?
404 .as_int()?;
405 frame.operand_stack.push(JvmValue::Int(a + b));
406 frame.pc += 1;
407 }
408 JvmInstruction::Isub => {
409 let b = frame
410 .operand_stack
411 .pop()
412 .ok_or(RuntimeError::StackUnderflow)?
413 .as_int()?;
414 let a = frame
415 .operand_stack
416 .pop()
417 .ok_or(RuntimeError::StackUnderflow)?
418 .as_int()?;
419 frame.operand_stack.push(JvmValue::Int(a - b));
420 frame.pc += 1;
421 }
422 JvmInstruction::Imul => {
423 let b = frame
424 .operand_stack
425 .pop()
426 .ok_or(RuntimeError::StackUnderflow)?
427 .as_int()?;
428 let a = frame
429 .operand_stack
430 .pop()
431 .ok_or(RuntimeError::StackUnderflow)?
432 .as_int()?;
433 frame.operand_stack.push(JvmValue::Int(a * b));
434 frame.pc += 1;
435 }
436 JvmInstruction::Idiv => {
437 let b = frame
438 .operand_stack
439 .pop()
440 .ok_or(RuntimeError::StackUnderflow)?
441 .as_int()?;
442 let a = frame
443 .operand_stack
444 .pop()
445 .ok_or(RuntimeError::StackUnderflow)?
446 .as_int()?;
447 if b == 0 {
448 return Err(RuntimeError::DivisionByZero);
449 }
450 frame.operand_stack.push(JvmValue::Int(a / b));
451 frame.pc += 1;
452 }
453 JvmInstruction::Irem => {
454 let b = frame
455 .operand_stack
456 .pop()
457 .ok_or(RuntimeError::StackUnderflow)?
458 .as_int()?;
459 let a = frame
460 .operand_stack
461 .pop()
462 .ok_or(RuntimeError::StackUnderflow)?
463 .as_int()?;
464 if b == 0 {
465 return Err(RuntimeError::DivisionByZero);
466 }
467 frame.operand_stack.push(JvmValue::Int(a % b));
468 frame.pc += 1;
469 }
470
471 JvmInstruction::Dadd => {
472 let b = frame
473 .operand_stack
474 .pop()
475 .ok_or(RuntimeError::StackUnderflow)?;
476 let a = frame
477 .operand_stack
478 .pop()
479 .ok_or(RuntimeError::StackUnderflow)?;
480
481 if let (JvmValue::Double(a_val), JvmValue::Double(b_val)) = (a, b) {
482 frame.operand_stack.push(JvmValue::Double(a_val + b_val));
483 } else {
484 return Err(RuntimeError::InvalidStackState);
485 }
486 frame.pc += 1;
487 }
488 JvmInstruction::Dsub => {
489 let b = frame
490 .operand_stack
491 .pop()
492 .ok_or(RuntimeError::StackUnderflow)?;
493 let a = frame
494 .operand_stack
495 .pop()
496 .ok_or(RuntimeError::StackUnderflow)?;
497
498 if let (JvmValue::Double(a_val), JvmValue::Double(b_val)) = (a, b) {
499 frame.operand_stack.push(JvmValue::Double(a_val - b_val));
500 } else {
501 return Err(RuntimeError::InvalidStackState);
502 }
503 frame.pc += 1;
504 }
505 JvmInstruction::Dmul => {
506 let b = frame
507 .operand_stack
508 .pop()
509 .ok_or(RuntimeError::StackUnderflow)?;
510 let a = frame
511 .operand_stack
512 .pop()
513 .ok_or(RuntimeError::StackUnderflow)?;
514
515 if let (JvmValue::Double(a_val), JvmValue::Double(b_val)) = (a, b) {
516 frame.operand_stack.push(JvmValue::Double(a_val * b_val));
517 } else {
518 return Err(RuntimeError::InvalidStackState);
519 }
520 frame.pc += 1;
521 }
522 JvmInstruction::Ddiv => {
523 let b = frame
524 .operand_stack
525 .pop()
526 .ok_or(RuntimeError::StackUnderflow)?;
527 let a = frame
528 .operand_stack
529 .pop()
530 .ok_or(RuntimeError::StackUnderflow)?;
531
532 if let (JvmValue::Double(a_val), JvmValue::Double(b_val)) = (a, b) {
533 if b_val == 0.0 {
534 return Err(RuntimeError::DivisionByZero);
535 }
536 frame.operand_stack.push(JvmValue::Double(a_val / b_val));
537 } else {
538 return Err(RuntimeError::InvalidStackState);
539 }
540 frame.pc += 1;
541 }
542
543 JvmInstruction::I2d => {
544 let value = frame
545 .operand_stack
546 .pop()
547 .ok_or(RuntimeError::StackUnderflow)?
548 .as_int()?;
549 frame.operand_stack.push(JvmValue::Double(value as f64));
550 frame.pc += 1;
551 }
552 JvmInstruction::D2i => {
553 let value = frame
554 .operand_stack
555 .pop()
556 .ok_or(RuntimeError::StackUnderflow)?;
557
558 if let JvmValue::Double(d_val) = value {
559 frame.operand_stack.push(JvmValue::Int(d_val as i32));
560 } else {
561 return Err(RuntimeError::InvalidStackState);
562 }
563 frame.pc += 1;
564 }
565
566 JvmInstruction::Goto(offset) => {
567 frame.pc = offset as usize;
568 }
569 JvmInstruction::Ifeq(offset) => {
570 let value = frame
571 .operand_stack
572 .pop()
573 .ok_or(RuntimeError::StackUnderflow)?
574 .as_int()?;
575 if value == 0 {
576 frame.pc = offset as usize;
577 } else {
578 frame.pc += 1;
579 }
580 }
581 JvmInstruction::Ifne(offset) => {
582 let value = frame
583 .operand_stack
584 .pop()
585 .ok_or(RuntimeError::StackUnderflow)?
586 .as_int()?;
587 if value != 0 {
588 frame.pc = offset as usize;
589 } else {
590 frame.pc += 1;
591 }
592 }
593 JvmInstruction::Iflt(offset) => {
594 let value = frame
595 .operand_stack
596 .pop()
597 .ok_or(RuntimeError::StackUnderflow)?
598 .as_int()?;
599 if value < 0 {
600 frame.pc = offset as usize;
601 } else {
602 frame.pc += 1;
603 }
604 }
605 JvmInstruction::Ifge(offset) => {
606 let value = frame
607 .operand_stack
608 .pop()
609 .ok_or(RuntimeError::StackUnderflow)?
610 .as_int()?;
611 if value >= 0 {
612 frame.pc = offset as usize;
613 } else {
614 frame.pc += 1;
615 }
616 }
617 JvmInstruction::Ifgt(offset) => {
618 let value = frame
619 .operand_stack
620 .pop()
621 .ok_or(RuntimeError::StackUnderflow)?
622 .as_int()?;
623 if value > 0 {
624 frame.pc = offset as usize;
625 } else {
626 frame.pc += 1;
627 }
628 }
629 JvmInstruction::Ifle(offset) => {
630 let value = frame
631 .operand_stack
632 .pop()
633 .ok_or(RuntimeError::StackUnderflow)?
634 .as_int()?;
635 if value <= 0 {
636 frame.pc = offset as usize;
637 } else {
638 frame.pc += 1;
639 }
640 }
641
642 JvmInstruction::Return => {
643 self.frames.pop();
644 }
645 JvmInstruction::Ireturn => {
646 let return_value = frame
647 .operand_stack
648 .pop()
649 .ok_or(RuntimeError::StackUnderflow)?;
650 self.frames.pop();
651 return Ok(Some(return_value));
652 }
653
654 JvmInstruction::New(_class_ref) => {
655 frame.operand_stack.push(JvmValue::Reference(Some(0)));
658 frame.pc += 1;
659 }
660
661 JvmInstruction::Getstatic(field_ref) => {
662 let field_value = self.resolve_static_field(field_ref)?;
664 let frame = self
665 .frames
666 .last_mut()
667 .ok_or(RuntimeError::CallStackUnderflow)?;
668 frame.operand_stack.push(field_value);
669 frame.pc += 1;
670 }
671
672 JvmInstruction::Invokevirtual(method_ref) => {
673 self.invoke_virtual_method(method_ref)?;
675 let frame = self
676 .frames
677 .last_mut()
678 .ok_or(RuntimeError::CallStackUnderflow)?;
679 frame.pc += 1;
680 }
681
682 JvmInstruction::Invokespecial(method_ref) => {
683 self.invoke_special_method(method_ref)?;
685 let frame = self
686 .frames
687 .last_mut()
688 .ok_or(RuntimeError::CallStackUnderflow)?;
689 frame.pc += 1;
690 }
691
692 JvmInstruction::Invokestatic(method_ref) => {
693 self.invoke_static_method(method_ref)?;
695 let frame = self
696 .frames
697 .last_mut()
698 .ok_or(RuntimeError::CallStackUnderflow)?;
699 frame.pc += 1;
700 }
701
702 JvmInstruction::Invokedynamic(bootstrap_method_attr_index) => {
703 self.invoke_dynamic_method(bootstrap_method_attr_index)?;
705 let frame = self
706 .frames
707 .last_mut()
708 .ok_or(RuntimeError::CallStackUnderflow)?;
709 frame.pc += 1;
710 }
711
712 JvmInstruction::Dconst0 => {
713 frame.operand_stack.push(JvmValue::Double(0.0));
714 frame.pc += 1;
715 }
716 JvmInstruction::Dconst1 => {
717 frame.operand_stack.push(JvmValue::Double(1.0));
718 frame.pc += 1;
719 }
720
721 JvmInstruction::Iload(index) => {
723 let value = frame
724 .locals
725 .get(index as usize)
726 .ok_or(RuntimeError::InvalidStackState)?
727 .clone();
728 frame.operand_stack.push(value);
729 frame.pc += 1;
730 }
731 JvmInstruction::Iload0 => {
732 let value = frame
733 .locals
734 .first()
735 .ok_or(RuntimeError::InvalidStackState)?
736 .clone();
737 frame.operand_stack.push(value);
738 frame.pc += 1;
739 }
740 JvmInstruction::Iload1 => {
741 let value = frame
742 .locals
743 .get(1)
744 .ok_or(RuntimeError::InvalidStackState)?
745 .clone();
746 frame.operand_stack.push(value);
747 frame.pc += 1;
748 }
749 JvmInstruction::Iload2 => {
750 let value = frame
751 .locals
752 .get(2)
753 .ok_or(RuntimeError::InvalidStackState)?
754 .clone();
755 frame.operand_stack.push(value);
756 frame.pc += 1;
757 }
758 JvmInstruction::Iload3 => {
759 let value = frame
760 .locals
761 .get(3)
762 .ok_or(RuntimeError::InvalidStackState)?
763 .clone();
764 frame.operand_stack.push(value);
765 frame.pc += 1;
766 }
767 JvmInstruction::Istore(index) => {
768 let value = frame
769 .operand_stack
770 .pop()
771 .ok_or(RuntimeError::StackUnderflow)?;
772 if (index as usize) >= frame.locals.len() {
773 frame.locals.resize(index as usize + 1, JvmValue::Int(0));
774 }
775 frame.locals[index as usize] = value;
776 frame.pc += 1;
777 }
778 JvmInstruction::Istore0 => {
779 let value = frame
780 .operand_stack
781 .pop()
782 .ok_or(RuntimeError::StackUnderflow)?;
783 if frame.locals.is_empty() {
784 frame.locals.resize(1, JvmValue::Int(0));
785 }
786 frame.locals[0] = value;
787 frame.pc += 1;
788 }
789 JvmInstruction::Istore1 => {
790 let value = frame
791 .operand_stack
792 .pop()
793 .ok_or(RuntimeError::StackUnderflow)?;
794 if frame.locals.len() <= 1 {
795 frame.locals.resize(2, JvmValue::Int(0));
796 }
797 frame.locals[1] = value;
798 frame.pc += 1;
799 }
800 JvmInstruction::Istore2 => {
801 let value = frame
802 .operand_stack
803 .pop()
804 .ok_or(RuntimeError::StackUnderflow)?;
805 if frame.locals.len() <= 2 {
806 frame.locals.resize(3, JvmValue::Int(0));
807 }
808 frame.locals[2] = value;
809 frame.pc += 1;
810 }
811 JvmInstruction::Istore3 => {
812 let value = frame
813 .operand_stack
814 .pop()
815 .ok_or(RuntimeError::StackUnderflow)?;
816 if frame.locals.len() <= 3 {
817 frame.locals.resize(4, JvmValue::Int(0));
818 }
819 frame.locals[3] = value;
820 frame.pc += 1;
821 }
822
823 JvmInstruction::Aload(index) => {
825 let value = frame
826 .locals
827 .get(index as usize)
828 .ok_or(RuntimeError::InvalidStackState)?
829 .clone();
830 frame.operand_stack.push(value);
831 frame.pc += 1;
832 }
833 JvmInstruction::Aload0 => {
834 let value = frame
835 .locals
836 .first()
837 .ok_or(RuntimeError::InvalidStackState)?
838 .clone();
839 frame.operand_stack.push(value);
840 frame.pc += 1;
841 }
842 JvmInstruction::Aload1 => {
843 let value = frame
844 .locals
845 .get(1)
846 .ok_or(RuntimeError::InvalidStackState)?
847 .clone();
848 frame.operand_stack.push(value);
849 frame.pc += 1;
850 }
851 JvmInstruction::Aload2 => {
852 let value = frame
853 .locals
854 .get(2)
855 .ok_or(RuntimeError::InvalidStackState)?
856 .clone();
857 frame.operand_stack.push(value);
858 frame.pc += 1;
859 }
860 JvmInstruction::Aload3 => {
861 let value = frame
862 .locals
863 .get(3)
864 .ok_or(RuntimeError::InvalidStackState)?
865 .clone();
866 frame.operand_stack.push(value);
867 frame.pc += 1;
868 }
869 JvmInstruction::Astore(index) => {
870 let value = frame
871 .operand_stack
872 .pop()
873 .ok_or(RuntimeError::StackUnderflow)?;
874 if (index as usize) >= frame.locals.len() {
875 frame
876 .locals
877 .resize(index as usize + 1, JvmValue::Reference(None));
878 }
879 frame.locals[index as usize] = value;
880 frame.pc += 1;
881 }
882 JvmInstruction::Astore0 => {
883 let value = frame
884 .operand_stack
885 .pop()
886 .ok_or(RuntimeError::StackUnderflow)?;
887 if frame.locals.is_empty() {
888 frame.locals.resize(1, JvmValue::Reference(None));
889 }
890 frame.locals[0] = value;
891 frame.pc += 1;
892 }
893 JvmInstruction::Astore1 => {
894 let value = frame
895 .operand_stack
896 .pop()
897 .ok_or(RuntimeError::StackUnderflow)?;
898 if frame.locals.len() <= 1 {
899 frame.locals.resize(2, JvmValue::Reference(None));
900 }
901 frame.locals[1] = value;
902 frame.pc += 1;
903 }
904 JvmInstruction::Astore2 => {
905 let value = frame
906 .operand_stack
907 .pop()
908 .ok_or(RuntimeError::StackUnderflow)?;
909 if frame.locals.len() <= 2 {
910 frame.locals.resize(3, JvmValue::Reference(None));
911 }
912 frame.locals[2] = value;
913 frame.pc += 1;
914 }
915 JvmInstruction::Astore3 => {
916 let value = frame
917 .operand_stack
918 .pop()
919 .ok_or(RuntimeError::StackUnderflow)?;
920 if frame.locals.len() <= 3 {
921 frame.locals.resize(4, JvmValue::Reference(None));
922 }
923 frame.locals[3] = value;
924 frame.pc += 1;
925 }
926
927 JvmInstruction::Dload(index) => {
929 let value = frame
930 .locals
931 .get(index as usize)
932 .ok_or(RuntimeError::InvalidStackState)?
933 .clone();
934 frame.operand_stack.push(value);
935 frame.pc += 1;
936 }
937 JvmInstruction::Dload0 => {
938 let value = frame
939 .locals
940 .first()
941 .ok_or(RuntimeError::InvalidStackState)?
942 .clone();
943 frame.operand_stack.push(value);
944 frame.pc += 1;
945 }
946 JvmInstruction::Dload1 => {
947 let value = frame
948 .locals
949 .get(1)
950 .ok_or(RuntimeError::InvalidStackState)?
951 .clone();
952 frame.operand_stack.push(value);
953 frame.pc += 1;
954 }
955 JvmInstruction::Dload2 => {
956 let value = frame
957 .locals
958 .get(2)
959 .ok_or(RuntimeError::InvalidStackState)?
960 .clone();
961 frame.operand_stack.push(value);
962 frame.pc += 1;
963 }
964 JvmInstruction::Dload3 => {
965 let value = frame
966 .locals
967 .get(3)
968 .ok_or(RuntimeError::InvalidStackState)?
969 .clone();
970 frame.operand_stack.push(value);
971 frame.pc += 1;
972 }
973 JvmInstruction::Dstore(index) => {
974 let value = frame
975 .operand_stack
976 .pop()
977 .ok_or(RuntimeError::StackUnderflow)?;
978 if (index as usize) >= frame.locals.len() {
979 frame
980 .locals
981 .resize(index as usize + 1, JvmValue::Double(0.0));
982 }
983 frame.locals[index as usize] = value;
984 frame.pc += 1;
985 }
986 JvmInstruction::Dstore0 => {
987 let value = frame
988 .operand_stack
989 .pop()
990 .ok_or(RuntimeError::StackUnderflow)?;
991 if frame.locals.is_empty() {
992 frame.locals.resize(1, JvmValue::Double(0.0));
993 }
994 frame.locals[0] = value;
995 frame.pc += 1;
996 }
997 JvmInstruction::Dstore1 => {
998 let value = frame
999 .operand_stack
1000 .pop()
1001 .ok_or(RuntimeError::StackUnderflow)?;
1002 if frame.locals.len() <= 1 {
1003 frame.locals.resize(2, JvmValue::Double(0.0));
1004 }
1005 frame.locals[1] = value;
1006 frame.pc += 1;
1007 }
1008 JvmInstruction::Dstore2 => {
1009 let value = frame
1010 .operand_stack
1011 .pop()
1012 .ok_or(RuntimeError::StackUnderflow)?;
1013 if frame.locals.len() <= 2 {
1014 frame.locals.resize(3, JvmValue::Double(0.0));
1015 }
1016 frame.locals[2] = value;
1017 frame.pc += 1;
1018 }
1019 JvmInstruction::Dstore3 => {
1020 let value = frame
1021 .operand_stack
1022 .pop()
1023 .ok_or(RuntimeError::StackUnderflow)?;
1024 if frame.locals.len() <= 3 {
1025 frame.locals.resize(4, JvmValue::Double(0.0));
1026 }
1027 frame.locals[3] = value;
1028 frame.pc += 1;
1029 }
1030
1031 JvmInstruction::Lload(index) => {
1033 let value = frame
1034 .locals
1035 .get(index as usize)
1036 .ok_or(RuntimeError::InvalidStackState)?
1037 .clone();
1038 frame.operand_stack.push(value);
1039 frame.pc += 1;
1040 }
1041 JvmInstruction::Lload0 => {
1042 let value = frame
1043 .locals
1044 .first()
1045 .ok_or(RuntimeError::InvalidStackState)?
1046 .clone();
1047 frame.operand_stack.push(value);
1048 frame.pc += 1;
1049 }
1050 JvmInstruction::Lload1 => {
1051 let value = frame
1052 .locals
1053 .get(1)
1054 .ok_or(RuntimeError::InvalidStackState)?
1055 .clone();
1056 frame.operand_stack.push(value);
1057 frame.pc += 1;
1058 }
1059 JvmInstruction::Lload2 => {
1060 let value = frame
1061 .locals
1062 .get(2)
1063 .ok_or(RuntimeError::InvalidStackState)?
1064 .clone();
1065 frame.operand_stack.push(value);
1066 frame.pc += 1;
1067 }
1068 JvmInstruction::Lload3 => {
1069 let value = frame
1070 .locals
1071 .get(3)
1072 .ok_or(RuntimeError::InvalidStackState)?
1073 .clone();
1074 frame.operand_stack.push(value);
1075 frame.pc += 1;
1076 }
1077 JvmInstruction::Lstore(index) => {
1078 let value = frame
1079 .operand_stack
1080 .pop()
1081 .ok_or(RuntimeError::StackUnderflow)?;
1082 if (index as usize) >= frame.locals.len() {
1083 frame.locals.resize(index as usize + 1, JvmValue::Long(0));
1084 }
1085 frame.locals[index as usize] = value;
1086 frame.pc += 1;
1087 }
1088 JvmInstruction::Lstore0 => {
1089 let value = frame
1090 .operand_stack
1091 .pop()
1092 .ok_or(RuntimeError::StackUnderflow)?;
1093 if frame.locals.is_empty() {
1094 frame.locals.resize(1, JvmValue::Long(0));
1095 }
1096 frame.locals[0] = value;
1097 frame.pc += 1;
1098 }
1099 JvmInstruction::Lstore1 => {
1100 let value = frame
1101 .operand_stack
1102 .pop()
1103 .ok_or(RuntimeError::StackUnderflow)?;
1104 if frame.locals.len() <= 1 {
1105 frame.locals.resize(2, JvmValue::Long(0));
1106 }
1107 frame.locals[1] = value;
1108 frame.pc += 1;
1109 }
1110 JvmInstruction::Lstore2 => {
1111 let value = frame
1112 .operand_stack
1113 .pop()
1114 .ok_or(RuntimeError::StackUnderflow)?;
1115 if frame.locals.len() <= 2 {
1116 frame.locals.resize(3, JvmValue::Long(0));
1117 }
1118 frame.locals[2] = value;
1119 frame.pc += 1;
1120 }
1121 JvmInstruction::Lstore3 => {
1122 let value = frame
1123 .operand_stack
1124 .pop()
1125 .ok_or(RuntimeError::StackUnderflow)?;
1126 if frame.locals.len() <= 3 {
1127 frame.locals.resize(4, JvmValue::Long(0));
1128 }
1129 frame.locals[3] = value;
1130 frame.pc += 1;
1131 }
1132
1133 JvmInstruction::Nop => {
1134 frame.pc += 1;
1136 }
1137 }
1138
1139 Ok(None)
1140 }
1141
1142 fn resolve_method_reference(&self, method_ref: u16) -> Result<ResolvedMethod, RuntimeError> {
1143 let frame = self.frames.last().ok_or(RuntimeError::CallStackUnderflow)?;
1144 let entries = frame.constant_pool.entries();
1145
1146 let actual_index = (method_ref - 1) as usize;
1148 if actual_index >= entries.len() {
1149 return Ok(ResolvedMethod::Unknown);
1150 }
1151
1152 match &entries[actual_index] {
1153 ConstantPoolEntry::Methodref(class_index, name_and_type_index) => {
1154 let class_actual_index = (*class_index - 1) as usize;
1156 let class_name =
1157 if let ConstantPoolEntry::Class(name_index) = &entries[class_actual_index] {
1158 let name_actual_index = (*name_index - 1) as usize;
1159 if let ConstantPoolEntry::Utf8(name) = &entries[name_actual_index] {
1160 name
1161 } else {
1162 return Ok(ResolvedMethod::Unknown);
1163 }
1164 } else {
1165 return Ok(ResolvedMethod::Unknown);
1166 };
1167
1168 let name_and_type_actual_index = (*name_and_type_index - 1) as usize;
1170 let (method_name, descriptor) =
1171 if let ConstantPoolEntry::NameAndType(name_index, desc_index) =
1172 &entries[name_and_type_actual_index]
1173 {
1174 let name_actual_index = (*name_index - 1) as usize;
1175 let desc_actual_index = (*desc_index - 1) as usize;
1176 let name =
1177 if let ConstantPoolEntry::Utf8(name) = &entries[name_actual_index] {
1178 name
1179 } else {
1180 return Ok(ResolvedMethod::Unknown);
1181 };
1182 let desc =
1183 if let ConstantPoolEntry::Utf8(desc) = &entries[desc_actual_index] {
1184 desc
1185 } else {
1186 return Ok(ResolvedMethod::Unknown);
1187 };
1188 (name, desc)
1189 } else {
1190 return Ok(ResolvedMethod::Unknown);
1191 };
1192
1193 match (
1195 class_name.as_str(),
1196 method_name.as_str(),
1197 descriptor.as_str(),
1198 ) {
1199 ("java/io/PrintStream", "println", "(I)V") => {
1200 Ok(ResolvedMethod::PrintStreamPrintln)
1201 }
1202 ("java/io/PrintStream", "print", "(Ljava/lang/String;)V") => {
1203 Ok(ResolvedMethod::PrintStreamPrint)
1204 }
1205 ("java/io/PrintStream", "println", "(Ljava/lang/String;)V") => {
1206 Ok(ResolvedMethod::PrintStreamPrintlnString)
1207 }
1208 ("java/io/PrintStream", "println", "(Ljava/lang/Object;)V") => {
1209 Ok(ResolvedMethod::PrintStreamPrintlnString) }
1211 ("java/io/PrintStream", "println", "(F)V") => {
1212 Ok(ResolvedMethod::PrintStreamPrintlnFloat)
1213 }
1214 ("java/io/PrintStream", "println", "(D)V") => {
1215 Ok(ResolvedMethod::PrintStreamPrintlnDouble)
1216 }
1217 ("java/io/PrintStream", "println", "(Z)V") => {
1218 Ok(ResolvedMethod::PrintStreamPrintlnBoolean)
1219 }
1220 ("java/io/PrintStream", "println", "(C)V") => {
1221 Ok(ResolvedMethod::PrintStreamPrintlnChar)
1222 }
1223 ("java/lang/Math", "random", "()D") => Ok(ResolvedMethod::MathRandom),
1224 ("java/lang/Math", "max", "(II)I") => Ok(ResolvedMethod::MathMaxInt),
1225 ("java/lang/Math", "min", "(II)I") => Ok(ResolvedMethod::MathMinInt),
1226 ("java/lang/Math", "max", "(DD)D") => Ok(ResolvedMethod::MathMaxDouble),
1227 ("java/lang/Math", "min", "(DD)D") => Ok(ResolvedMethod::MathMinDouble),
1228 ("java/lang/Math", "abs", "(I)I") => Ok(ResolvedMethod::MathAbs),
1229 ("java/lang/Math", "abs", "(D)D") => Ok(ResolvedMethod::MathAbsDouble),
1230 ("java/lang/Math", "pow", "(DD)D") => Ok(ResolvedMethod::MathPow),
1231 ("java/lang/Math", "sqrt", "(D)D") => Ok(ResolvedMethod::MathSqrt),
1232 ("java/lang/Math", "floor", "(D)D") => Ok(ResolvedMethod::MathFloor),
1233 ("java/lang/Math", "ceil", "(D)D") => Ok(ResolvedMethod::MathCeil),
1234 ("java/lang/Math", "round", "(D)J") => Ok(ResolvedMethod::MathRound),
1235 ("java/lang/Math", "sin", "(D)D") => Ok(ResolvedMethod::MathSin),
1236 ("java/lang/Math", "cos", "(D)D") => Ok(ResolvedMethod::MathCos),
1237 ("java/lang/Math", "tan", "(D)D") => Ok(ResolvedMethod::MathTan),
1238 ("java/lang/Math", "log", "(D)D") => Ok(ResolvedMethod::MathLog),
1239 ("java/lang/Math", "exp", "(D)D") => Ok(ResolvedMethod::MathExp),
1240
1241 ("java/lang/String", "length", "()I") => Ok(ResolvedMethod::StringLength),
1243 ("java/lang/String", "charAt", "(I)C") => Ok(ResolvedMethod::StringCharAt),
1244 ("java/lang/String", "substring", "(II)Ljava/lang/String;") => {
1245 Ok(ResolvedMethod::StringSubstring)
1246 }
1247 ("java/lang/String", "indexOf", "(I)I") => Ok(ResolvedMethod::StringIndexOf),
1248 ("java/lang/String", "toUpperCase", "()Ljava/lang/String;") => {
1249 Ok(ResolvedMethod::StringToUpperCase)
1250 }
1251 ("java/lang/String", "toLowerCase", "()Ljava/lang/String;") => {
1252 Ok(ResolvedMethod::StringToLowerCase)
1253 }
1254 ("java/lang/String", "trim", "()Ljava/lang/String;") => {
1255 Ok(ResolvedMethod::StringTrim)
1256 }
1257 ("java/lang/String", "equals", "(Ljava/lang/Object;)Z") => {
1258 Ok(ResolvedMethod::StringEquals)
1259 }
1260 ("java/lang/String", "concat", "(Ljava/lang/String;)Ljava/lang/String;") => {
1261 Ok(ResolvedMethod::StringConcat)
1262 }
1263
1264 (
1266 "java/lang/StringBuilder",
1267 "append",
1268 "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
1269 ) => Ok(ResolvedMethod::StringBuilderAppendString),
1270 ("java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;") => {
1271 Ok(ResolvedMethod::StringBuilderAppendInt)
1272 }
1273 ("java/lang/StringBuilder", "append", "(D)Ljava/lang/StringBuilder;") => {
1274 Ok(ResolvedMethod::StringBuilderAppendDouble)
1275 }
1276 ("java/lang/StringBuilder", "toString", "()Ljava/lang/String;") => {
1277 Ok(ResolvedMethod::StringBuilderToString)
1278 }
1279
1280 ("java/lang/Integer", "parseInt", "(Ljava/lang/String;)I") => {
1282 Ok(ResolvedMethod::IntegerParseInt)
1283 }
1284 ("java/lang/Integer", "toString", "(I)Ljava/lang/String;") => {
1285 Ok(ResolvedMethod::IntegerToString)
1286 }
1287 ("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;") => {
1288 Ok(ResolvedMethod::IntegerValueOf)
1289 }
1290
1291 ("java/lang/Double", "parseDouble", "(Ljava/lang/String;)D") => {
1293 Ok(ResolvedMethod::DoubleParseDouble)
1294 }
1295 ("java/lang/Double", "toString", "(D)Ljava/lang/String;") => {
1296 Ok(ResolvedMethod::DoubleToString)
1297 }
1298 ("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;") => {
1299 Ok(ResolvedMethod::DoubleValueOf)
1300 }
1301
1302 ("java/lang/Boolean", "parseBoolean", "(Ljava/lang/String;)Z") => {
1304 Ok(ResolvedMethod::BooleanParseBoolean)
1305 }
1306 ("java/lang/Boolean", "toString", "(Z)Ljava/lang/String;") => {
1307 Ok(ResolvedMethod::BooleanToString)
1308 }
1309 ("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;") => {
1310 Ok(ResolvedMethod::BooleanValueOf)
1311 }
1312
1313 ("java/lang/Character", "isDigit", "(C)Z") => {
1315 Ok(ResolvedMethod::CharacterIsDigit)
1316 }
1317 ("java/lang/Character", "isLetter", "(C)Z") => {
1318 Ok(ResolvedMethod::CharacterIsLetter)
1319 }
1320 ("java/lang/Character", "toUpperCase", "(C)C") => {
1321 Ok(ResolvedMethod::CharacterToUpperCase)
1322 }
1323 ("java/lang/Character", "toLowerCase", "(C)C") => {
1324 Ok(ResolvedMethod::CharacterToLowerCase)
1325 }
1326 _ => Ok(ResolvedMethod::Unknown),
1327 }
1328 }
1329 _ => Ok(ResolvedMethod::Unknown),
1330 }
1331 }
1332
1333 fn load_constant_from_pool(&mut self, index: u16) -> Result<JvmValue, RuntimeError> {
1334 let frame = self.frames.last().ok_or(RuntimeError::CallStackUnderflow)?;
1335 let entries = frame.constant_pool.entries();
1336
1337 let actual_index = (index - 1) as usize;
1339 if actual_index >= entries.len() {
1340 return Err(RuntimeError::InvalidStackState);
1341 }
1342
1343 match &entries[actual_index] {
1344 ConstantPoolEntry::Integer(i) => Ok(JvmValue::Int(*i)),
1345 ConstantPoolEntry::Float(f) => Ok(JvmValue::Float(*f)),
1346 ConstantPoolEntry::Long(l) => Ok(JvmValue::Long(*l)),
1347 ConstantPoolEntry::Double(d) => Ok(JvmValue::Double(*d)),
1348 ConstantPoolEntry::String(utf8_index) => {
1349 let utf8_actual_index = (*utf8_index - 1) as usize;
1350 if let ConstantPoolEntry::Utf8(s) = &entries[utf8_actual_index] {
1351 let object_id = self.create_string_object(s.clone());
1352 Ok(JvmValue::Reference(Some(object_id)))
1353 } else {
1354 Err(RuntimeError::InvalidStackState)
1355 }
1356 }
1357 _ => Err(RuntimeError::InvalidStackState),
1358 }
1359 }
1360
1361 pub fn debug_state(&self) {
1362 if self.verbose {
1363 eprintln!("=== JVM Compatible VM State ===");
1364 eprintln!("Steps: {}", self.steps);
1365 eprintln!("Frames: {}", self.frames.len());
1366
1367 if let Some(frame) = self.frames.last() {
1368 eprintln!("Current Frame:");
1369 eprintln!(" PC: {}", frame.pc);
1370 eprintln!(" Operand Stack: {:?}", frame.operand_stack);
1371 eprintln!(" Locals: {:?}", frame.locals);
1372 }
1373
1374 eprintln!("Heap Objects: {}", self.heap.len());
1375 eprintln!("==============================");
1376 }
1377 }
1378
1379 fn resolve_static_field(&mut self, field_ref: u16) -> Result<JvmValue, RuntimeError> {
1380 let frame = self.frames.last().ok_or(RuntimeError::CallStackUnderflow)?;
1381 let entries = frame.constant_pool.entries();
1382
1383 let actual_index = (field_ref - 1) as usize;
1385 if actual_index >= entries.len() {
1386 return self.resolve_static_field_numeric(field_ref);
1388 }
1389
1390 match &entries[actual_index] {
1391 ConstantPoolEntry::Fieldref(class_index, name_and_type_index) => {
1392 let class_actual_index = (*class_index - 1) as usize;
1394 let class_name =
1395 if let ConstantPoolEntry::Class(name_index) = &entries[class_actual_index] {
1396 let name_actual_index = (*name_index - 1) as usize;
1397 if let ConstantPoolEntry::Utf8(name) = &entries[name_actual_index] {
1398 name
1399 } else {
1400 return self.resolve_static_field_numeric(field_ref);
1401 }
1402 } else {
1403 return self.resolve_static_field_numeric(field_ref);
1404 };
1405
1406 let name_and_type_actual_index = (*name_and_type_index - 1) as usize;
1408 let field_name = if let ConstantPoolEntry::NameAndType(name_index, _desc_index) =
1409 &entries[name_and_type_actual_index]
1410 {
1411 let name_actual_index = (*name_index - 1) as usize;
1412 if let ConstantPoolEntry::Utf8(name) = &entries[name_actual_index] {
1413 name
1414 } else {
1415 return self.resolve_static_field_numeric(field_ref);
1416 }
1417 } else {
1418 return self.resolve_static_field_numeric(field_ref);
1419 };
1420
1421 match (class_name.as_str(), field_name.as_str()) {
1423 ("java/lang/System", "out") => {
1424 let stdout_id = self.create_printstream_object("stdout".to_string());
1425 Ok(JvmValue::Reference(Some(stdout_id)))
1426 }
1427 ("java/lang/System", "err") => {
1428 let stderr_id = self.create_printstream_object("stderr".to_string());
1429 Ok(JvmValue::Reference(Some(stderr_id)))
1430 }
1431 _ => self.resolve_static_field_numeric(field_ref),
1432 }
1433 }
1434 _ => self.resolve_static_field_numeric(field_ref),
1435 }
1436 }
1437
1438 fn resolve_static_field_numeric(&mut self, field_ref: u16) -> Result<JvmValue, RuntimeError> {
1439 match field_ref {
1441 31 => {
1442 let stdout_id = self.create_printstream_object("stdout".to_string());
1444 Ok(JvmValue::Reference(Some(stdout_id)))
1445 }
1446 32 => {
1447 let stderr_id = self.create_printstream_object("stderr".to_string());
1449 Ok(JvmValue::Reference(Some(stderr_id)))
1450 }
1451 _ => Err(RuntimeError::InvalidStackState),
1452 }
1453 }
1454
1455 fn create_printstream_object(&mut self, stream_type: String) -> usize {
1456 let object_id = self.next_object_id;
1457 self.next_object_id += 1;
1458
1459 let mut fields = HashMap::new();
1460 fields.insert("type".to_string(), JvmValue::Reference(None));
1461
1462 let printstream_object = JvmObject {
1463 class_name: "java/io/PrintStream".to_string(),
1464 fields,
1465 };
1466
1467 self.heap.insert(object_id, printstream_object);
1468
1469 if stream_type == "stderr" {
1471 self.heap
1472 .get_mut(&object_id)
1473 .unwrap()
1474 .fields
1475 .insert("is_stderr".to_string(), JvmValue::Int(1));
1476 } else {
1477 self.heap
1478 .get_mut(&object_id)
1479 .unwrap()
1480 .fields
1481 .insert("is_stderr".to_string(), JvmValue::Int(0));
1482 }
1483
1484 object_id
1485 }
1486
1487 fn invoke_virtual_method(&mut self, method_ref: u16) -> Result<(), RuntimeError> {
1488 let method_info = self.resolve_method_reference(method_ref)?;
1490
1491 let frame = self
1492 .frames
1493 .last_mut()
1494 .ok_or(RuntimeError::CallStackUnderflow)?;
1495
1496 match method_info {
1497 ResolvedMethod::PrintStreamPrintln => {
1498 let value = frame
1500 .operand_stack
1501 .pop()
1502 .ok_or(RuntimeError::StackUnderflow)?;
1503 let printstream_ref = frame
1504 .operand_stack
1505 .pop()
1506 .ok_or(RuntimeError::StackUnderflow)?;
1507
1508 let output = match value {
1509 JvmValue::Int(i) => i.to_string(),
1510 JvmValue::Long(l) => l.to_string(),
1511 JvmValue::Double(d) => d.to_string(),
1512 JvmValue::Float(f) => f.to_string(),
1513 JvmValue::Boolean(b) => b.to_string(),
1514 JvmValue::Char(c) => (c as u8 as char).to_string(),
1515 _ => "null".to_string(),
1516 };
1517
1518 if let JvmValue::Reference(Some(obj_id)) = printstream_ref {
1519 if let Some(obj) = self.heap.get(&obj_id) {
1520 if let Some(JvmValue::Int(is_stderr)) = obj.fields.get("is_stderr") {
1521 if *is_stderr == 1 {
1522 eprintln!("{output}");
1523 } else {
1524 println!("{output}");
1525 }
1526 }
1527 }
1528 }
1529 }
1530 ResolvedMethod::PrintStreamPrint => {
1531 let string_ref = frame
1533 .operand_stack
1534 .pop()
1535 .ok_or(RuntimeError::StackUnderflow)?;
1536 let printstream_ref = frame
1537 .operand_stack
1538 .pop()
1539 .ok_or(RuntimeError::StackUnderflow)?;
1540
1541 if let (
1542 JvmValue::Reference(Some(string_id)),
1543 JvmValue::Reference(Some(stream_id)),
1544 ) = (string_ref, printstream_ref)
1545 {
1546 if let Some(string_value) = self.string_data.get(&string_id) {
1548 if let Some(stream_obj) = self.heap.get(&stream_id) {
1549 if let Some(JvmValue::Int(is_stderr)) =
1550 stream_obj.fields.get("is_stderr")
1551 {
1552 if *is_stderr == 1 {
1553 eprint!("{string_value}");
1554 } else {
1555 print!("{string_value}");
1556 }
1557 }
1558 }
1559 }
1560 }
1561 }
1562 ResolvedMethod::PrintStreamPrintlnString => {
1563 let string_ref = frame
1565 .operand_stack
1566 .pop()
1567 .ok_or(RuntimeError::StackUnderflow)?;
1568 let printstream_ref = frame
1569 .operand_stack
1570 .pop()
1571 .ok_or(RuntimeError::StackUnderflow)?;
1572
1573 if let (
1574 JvmValue::Reference(Some(string_id)),
1575 JvmValue::Reference(Some(stream_id)),
1576 ) = (string_ref, printstream_ref)
1577 {
1578 if let Some(string_value) = self.string_data.get(&string_id) {
1580 if let Some(stream_obj) = self.heap.get(&stream_id) {
1581 if let Some(JvmValue::Int(is_stderr)) =
1582 stream_obj.fields.get("is_stderr")
1583 {
1584 if *is_stderr == 1 {
1585 eprintln!("{string_value}");
1586 } else {
1587 println!("{string_value}");
1588 }
1589 }
1590 }
1591 }
1592 }
1593 }
1594 ResolvedMethod::PrintStreamPrintlnFloat => {
1595 let value = frame
1597 .operand_stack
1598 .pop()
1599 .ok_or(RuntimeError::StackUnderflow)?;
1600 let printstream_ref = frame
1601 .operand_stack
1602 .pop()
1603 .ok_or(RuntimeError::StackUnderflow)?;
1604
1605 if let JvmValue::Reference(Some(obj_id)) = printstream_ref {
1606 if let Some(obj) = self.heap.get(&obj_id) {
1607 if let Some(JvmValue::Int(is_stderr)) = obj.fields.get("is_stderr") {
1608 let float_value = match value {
1610 JvmValue::Float(f) => f,
1611 JvmValue::Int(i) => i as f32,
1612 JvmValue::Double(d) => d as f32,
1613 _ => return Err(RuntimeError::InvalidStackState),
1614 };
1615
1616 if *is_stderr == 1 {
1617 eprintln!("{float_value}");
1618 } else {
1619 println!("{float_value}");
1620 }
1621 }
1622 }
1623 }
1624 }
1625 ResolvedMethod::PrintStreamPrintlnDouble => {
1626 let value = frame
1628 .operand_stack
1629 .pop()
1630 .ok_or(RuntimeError::StackUnderflow)?;
1631 let printstream_ref = frame
1632 .operand_stack
1633 .pop()
1634 .ok_or(RuntimeError::StackUnderflow)?;
1635
1636 if let JvmValue::Reference(Some(obj_id)) = printstream_ref {
1637 if let Some(obj) = self.heap.get(&obj_id) {
1638 if let Some(JvmValue::Int(is_stderr)) = obj.fields.get("is_stderr") {
1639 let double_value = match value {
1641 JvmValue::Double(d) => d,
1642 JvmValue::Float(f) => f as f64,
1643 JvmValue::Int(i) => i as f64,
1644 _ => return Err(RuntimeError::InvalidStackState),
1645 };
1646
1647 if *is_stderr == 1 {
1648 eprintln!("{double_value}");
1649 } else {
1650 println!("{double_value}");
1651 }
1652 }
1653 }
1654 }
1655 }
1656 ResolvedMethod::PrintStreamPrintlnBoolean => {
1657 let value = frame
1659 .operand_stack
1660 .pop()
1661 .ok_or(RuntimeError::StackUnderflow)?;
1662 let printstream_ref = frame
1663 .operand_stack
1664 .pop()
1665 .ok_or(RuntimeError::StackUnderflow)?;
1666
1667 if let JvmValue::Reference(Some(obj_id)) = printstream_ref {
1668 if let Some(obj) = self.heap.get(&obj_id) {
1669 if let Some(JvmValue::Int(is_stderr)) = obj.fields.get("is_stderr") {
1670 let bool_value = match value {
1671 JvmValue::Boolean(b) => b,
1672 JvmValue::Int(i) => i != 0,
1673 _ => return Err(RuntimeError::InvalidStackState),
1674 };
1675
1676 if *is_stderr == 1 {
1677 eprintln!("{bool_value}");
1678 } else {
1679 println!("{bool_value}");
1680 }
1681 }
1682 }
1683 }
1684 }
1685 ResolvedMethod::PrintStreamPrintlnChar => {
1686 let value = frame
1688 .operand_stack
1689 .pop()
1690 .ok_or(RuntimeError::StackUnderflow)?;
1691 let printstream_ref = frame
1692 .operand_stack
1693 .pop()
1694 .ok_or(RuntimeError::StackUnderflow)?;
1695
1696 if let JvmValue::Reference(Some(obj_id)) = printstream_ref {
1697 if let Some(obj) = self.heap.get(&obj_id) {
1698 if let Some(JvmValue::Int(is_stderr)) = obj.fields.get("is_stderr") {
1699 let char_value = match value {
1700 JvmValue::Char(c) => c as u8 as char,
1701 JvmValue::Int(i) => i as u8 as char,
1702 _ => return Err(RuntimeError::InvalidStackState),
1703 };
1704
1705 if *is_stderr == 1 {
1706 eprintln!("{char_value}");
1707 } else {
1708 println!("{char_value}");
1709 }
1710 }
1711 }
1712 }
1713 }
1714 ResolvedMethod::MathRandom => {
1715 return Err(RuntimeError::InvalidStackState);
1718 }
1719 ResolvedMethod::MathMaxInt => {
1720 return Err(RuntimeError::InvalidStackState);
1723 }
1724 ResolvedMethod::MathMinInt => {
1725 return Err(RuntimeError::InvalidStackState);
1728 }
1729 ResolvedMethod::MathMaxDouble => {
1730 return Err(RuntimeError::InvalidStackState);
1732 }
1733 ResolvedMethod::MathMinDouble => {
1734 return Err(RuntimeError::InvalidStackState);
1736 }
1737 ResolvedMethod::MathAbs => {
1738 return Err(RuntimeError::InvalidStackState);
1740 }
1741 ResolvedMethod::MathAbsDouble => {
1742 return Err(RuntimeError::InvalidStackState);
1744 }
1745 ResolvedMethod::MathPow => {
1746 return Err(RuntimeError::InvalidStackState);
1748 }
1749 ResolvedMethod::MathSqrt => {
1750 return Err(RuntimeError::InvalidStackState);
1752 }
1753 ResolvedMethod::MathFloor => {
1754 return Err(RuntimeError::InvalidStackState);
1756 }
1757 ResolvedMethod::MathCeil => {
1758 return Err(RuntimeError::InvalidStackState);
1760 }
1761 ResolvedMethod::MathRound => {
1762 return Err(RuntimeError::InvalidStackState);
1764 }
1765 ResolvedMethod::MathSin => {
1766 return Err(RuntimeError::InvalidStackState);
1768 }
1769 ResolvedMethod::MathCos => {
1770 return Err(RuntimeError::InvalidStackState);
1772 }
1773 ResolvedMethod::MathTan => {
1774 return Err(RuntimeError::InvalidStackState);
1776 }
1777 ResolvedMethod::MathLog => {
1778 return Err(RuntimeError::InvalidStackState);
1780 }
1781 ResolvedMethod::MathExp => {
1782 return Err(RuntimeError::InvalidStackState);
1784 }
1785
1786 ResolvedMethod::StringLength => {
1788 let string_ref = frame
1790 .operand_stack
1791 .pop()
1792 .ok_or(RuntimeError::StackUnderflow)?;
1793
1794 if let JvmValue::Reference(Some(string_id)) = string_ref {
1795 if let Some(string_value) = self.string_data.get(&string_id) {
1796 frame
1797 .operand_stack
1798 .push(JvmValue::Int(string_value.len() as i32));
1799 } else {
1800 return Err(RuntimeError::InvalidStackState);
1801 }
1802 } else {
1803 return Err(RuntimeError::InvalidStackState);
1804 }
1805 }
1806
1807 ResolvedMethod::IntegerParseInt
1809 | ResolvedMethod::IntegerToString
1810 | ResolvedMethod::IntegerValueOf
1811 | ResolvedMethod::DoubleParseDouble
1812 | ResolvedMethod::DoubleToString
1813 | ResolvedMethod::DoubleValueOf
1814 | ResolvedMethod::BooleanParseBoolean
1815 | ResolvedMethod::BooleanToString
1816 | ResolvedMethod::BooleanValueOf
1817 | ResolvedMethod::CharacterIsDigit
1818 | ResolvedMethod::CharacterIsLetter
1819 | ResolvedMethod::CharacterToUpperCase
1820 | ResolvedMethod::CharacterToLowerCase => {
1821 return Err(RuntimeError::InvalidStackState);
1823 }
1824
1825 ResolvedMethod::StringCharAt
1827 | ResolvedMethod::StringSubstring
1828 | ResolvedMethod::StringIndexOf
1829 | ResolvedMethod::StringToUpperCase
1830 | ResolvedMethod::StringToLowerCase
1831 | ResolvedMethod::StringTrim
1832 | ResolvedMethod::StringEquals
1833 | ResolvedMethod::StringConcat => {
1834 return Err(RuntimeError::InvalidStackState);
1836 }
1837
1838 ResolvedMethod::StringBuilderAppendString => {
1839 let _string_value = frame
1841 .operand_stack
1842 .pop()
1843 .ok_or(RuntimeError::StackUnderflow)?;
1844 let sb_ref = frame
1845 .operand_stack
1846 .pop()
1847 .ok_or(RuntimeError::StackUnderflow)?;
1848
1849 frame.operand_stack.push(sb_ref);
1851 }
1852
1853 ResolvedMethod::StringBuilderAppendInt => {
1854 let _int_value = frame
1856 .operand_stack
1857 .pop()
1858 .ok_or(RuntimeError::StackUnderflow)?;
1859 let sb_ref = frame
1860 .operand_stack
1861 .pop()
1862 .ok_or(RuntimeError::StackUnderflow)?;
1863
1864 frame.operand_stack.push(sb_ref);
1865 }
1866
1867 ResolvedMethod::StringBuilderAppendDouble => {
1868 let _double_value = frame
1870 .operand_stack
1871 .pop()
1872 .ok_or(RuntimeError::StackUnderflow)?;
1873 let sb_ref = frame
1874 .operand_stack
1875 .pop()
1876 .ok_or(RuntimeError::StackUnderflow)?;
1877
1878 frame.operand_stack.push(sb_ref);
1879 }
1880
1881 ResolvedMethod::StringBuilderToString => {
1882 let _sb_ref = frame
1884 .operand_stack
1885 .pop()
1886 .ok_or(RuntimeError::StackUnderflow)?;
1887
1888 frame.operand_stack.push(JvmValue::Reference(Some(1)));
1890 }
1891
1892 ResolvedMethod::Unknown => {
1893 match method_ref {
1895 33 => {
1896 let value = frame
1898 .operand_stack
1899 .pop()
1900 .ok_or(RuntimeError::StackUnderflow)?
1901 .as_int()?;
1902 let printstream_ref = frame
1903 .operand_stack
1904 .pop()
1905 .ok_or(RuntimeError::StackUnderflow)?;
1906
1907 if let JvmValue::Reference(Some(obj_id)) = printstream_ref {
1908 if let Some(obj) = self.heap.get(&obj_id) {
1909 if let Some(JvmValue::Int(is_stderr)) = obj.fields.get("is_stderr")
1910 {
1911 if *is_stderr == 1 {
1912 eprintln!("{value}");
1913 } else {
1914 println!("{value}");
1915 }
1916 }
1917 }
1918 }
1919 }
1920 34 => {
1921 let string_ref = frame
1923 .operand_stack
1924 .pop()
1925 .ok_or(RuntimeError::StackUnderflow)?;
1926 let printstream_ref = frame
1927 .operand_stack
1928 .pop()
1929 .ok_or(RuntimeError::StackUnderflow)?;
1930
1931 if let (
1932 JvmValue::Reference(Some(string_id)),
1933 JvmValue::Reference(Some(stream_id)),
1934 ) = (string_ref, printstream_ref)
1935 {
1936 if let Some(string_value) = self.string_data.get(&string_id) {
1937 if let Some(stream_obj) = self.heap.get(&stream_id) {
1938 if let Some(JvmValue::Int(is_stderr)) =
1939 stream_obj.fields.get("is_stderr")
1940 {
1941 if *is_stderr == 1 {
1942 eprint!("{string_value}");
1943 } else {
1944 print!("{string_value}");
1945 }
1946 }
1947 }
1948 }
1949 }
1950 }
1951 35 => {
1952 let string_ref = frame
1954 .operand_stack
1955 .pop()
1956 .ok_or(RuntimeError::StackUnderflow)?;
1957 let printstream_ref = frame
1958 .operand_stack
1959 .pop()
1960 .ok_or(RuntimeError::StackUnderflow)?;
1961
1962 if let (
1963 JvmValue::Reference(Some(string_id)),
1964 JvmValue::Reference(Some(stream_id)),
1965 ) = (string_ref, printstream_ref)
1966 {
1967 if let Some(string_value) = self.string_data.get(&string_id) {
1968 if let Some(stream_obj) = self.heap.get(&stream_id) {
1969 if let Some(JvmValue::Int(is_stderr)) =
1970 stream_obj.fields.get("is_stderr")
1971 {
1972 if *is_stderr == 1 {
1973 eprintln!("{string_value}");
1974 } else {
1975 println!("{string_value}");
1976 }
1977 }
1978 }
1979 }
1980 }
1981 }
1982 _ => return Err(RuntimeError::InvalidStackState),
1983 }
1984 }
1985 }
1986
1987 Ok(())
1988 }
1989
1990 fn invoke_special_method(&mut self, _method_ref: u16) -> Result<(), RuntimeError> {
1991 let frame = self
1994 .frames
1995 .last_mut()
1996 .ok_or(RuntimeError::CallStackUnderflow)?;
1997
1998 if !frame.operand_stack.is_empty() {
2001 frame.operand_stack.pop(); }
2003
2004 Ok(())
2005 }
2006
2007 fn invoke_static_method(&mut self, method_ref: u16) -> Result<(), RuntimeError> {
2008 if let Some(method_info) = self.resolve_user_method(method_ref)? {
2010 return self.invoke_user_defined_method(&method_info);
2011 }
2012
2013 let method_info = self.resolve_method_reference(method_ref)?;
2015
2016 match method_info {
2017 ResolvedMethod::MathRandom => {
2018 use rand::Rng;
2020 let mut rng = rand::rng();
2021 let random_value = rng.random::<f64>();
2022 let frame = self
2023 .frames
2024 .last_mut()
2025 .ok_or(RuntimeError::CallStackUnderflow)?;
2026 frame.operand_stack.push(JvmValue::Double(random_value));
2027 }
2028 ResolvedMethod::MathMaxInt => {
2029 let frame = self
2031 .frames
2032 .last_mut()
2033 .ok_or(RuntimeError::CallStackUnderflow)?;
2034 let b = frame
2035 .operand_stack
2036 .pop()
2037 .ok_or(RuntimeError::StackUnderflow)?
2038 .as_int()?;
2039 let a = frame
2040 .operand_stack
2041 .pop()
2042 .ok_or(RuntimeError::StackUnderflow)?
2043 .as_int()?;
2044 let result = if a > b { a } else { b };
2045 frame.operand_stack.push(JvmValue::Int(result));
2046 }
2047 ResolvedMethod::MathMinInt => {
2048 let frame = self
2050 .frames
2051 .last_mut()
2052 .ok_or(RuntimeError::CallStackUnderflow)?;
2053 let b = frame
2054 .operand_stack
2055 .pop()
2056 .ok_or(RuntimeError::StackUnderflow)?
2057 .as_int()?;
2058 let a = frame
2059 .operand_stack
2060 .pop()
2061 .ok_or(RuntimeError::StackUnderflow)?
2062 .as_int()?;
2063 let result = if a < b { a } else { b };
2064 frame.operand_stack.push(JvmValue::Int(result));
2065 }
2066 ResolvedMethod::MathMaxDouble => {
2067 let frame = self
2069 .frames
2070 .last_mut()
2071 .ok_or(RuntimeError::CallStackUnderflow)?;
2072 let b = frame
2073 .operand_stack
2074 .pop()
2075 .ok_or(RuntimeError::StackUnderflow)?;
2076 let a = frame
2077 .operand_stack
2078 .pop()
2079 .ok_or(RuntimeError::StackUnderflow)?;
2080 if let (JvmValue::Double(a_val), JvmValue::Double(b_val)) = (a, b) {
2081 let result = if a_val > b_val { a_val } else { b_val };
2082 frame.operand_stack.push(JvmValue::Double(result));
2083 } else {
2084 return Err(RuntimeError::InvalidStackState);
2085 }
2086 }
2087 ResolvedMethod::MathMinDouble => {
2088 let frame = self
2090 .frames
2091 .last_mut()
2092 .ok_or(RuntimeError::CallStackUnderflow)?;
2093 let b = frame
2094 .operand_stack
2095 .pop()
2096 .ok_or(RuntimeError::StackUnderflow)?;
2097 let a = frame
2098 .operand_stack
2099 .pop()
2100 .ok_or(RuntimeError::StackUnderflow)?;
2101 if let (JvmValue::Double(a_val), JvmValue::Double(b_val)) = (a, b) {
2102 let result = if a_val < b_val { a_val } else { b_val };
2103 frame.operand_stack.push(JvmValue::Double(result));
2104 } else {
2105 return Err(RuntimeError::InvalidStackState);
2106 }
2107 }
2108 ResolvedMethod::MathAbs => {
2109 let frame = self
2111 .frames
2112 .last_mut()
2113 .ok_or(RuntimeError::CallStackUnderflow)?;
2114 let value = frame
2115 .operand_stack
2116 .pop()
2117 .ok_or(RuntimeError::StackUnderflow)?
2118 .as_int()?;
2119 frame.operand_stack.push(JvmValue::Int(value.abs()));
2120 }
2121 ResolvedMethod::MathAbsDouble => {
2122 let frame = self
2124 .frames
2125 .last_mut()
2126 .ok_or(RuntimeError::CallStackUnderflow)?;
2127 let value = frame
2128 .operand_stack
2129 .pop()
2130 .ok_or(RuntimeError::StackUnderflow)?;
2131 if let JvmValue::Double(d_val) = value {
2132 frame.operand_stack.push(JvmValue::Double(d_val.abs()));
2133 } else {
2134 return Err(RuntimeError::InvalidStackState);
2135 }
2136 }
2137 ResolvedMethod::MathPow => {
2138 let frame = self
2140 .frames
2141 .last_mut()
2142 .ok_or(RuntimeError::CallStackUnderflow)?;
2143 let exponent = frame
2144 .operand_stack
2145 .pop()
2146 .ok_or(RuntimeError::StackUnderflow)?;
2147 let base = frame
2148 .operand_stack
2149 .pop()
2150 .ok_or(RuntimeError::StackUnderflow)?;
2151 if let (JvmValue::Double(base_val), JvmValue::Double(exp_val)) = (base, exponent) {
2152 frame
2153 .operand_stack
2154 .push(JvmValue::Double(base_val.powf(exp_val)));
2155 } else {
2156 return Err(RuntimeError::InvalidStackState);
2157 }
2158 }
2159 ResolvedMethod::MathSqrt => {
2160 let frame = self
2162 .frames
2163 .last_mut()
2164 .ok_or(RuntimeError::CallStackUnderflow)?;
2165 let value = frame
2166 .operand_stack
2167 .pop()
2168 .ok_or(RuntimeError::StackUnderflow)?;
2169 if let JvmValue::Double(d_val) = value {
2170 frame.operand_stack.push(JvmValue::Double(d_val.sqrt()));
2171 } else {
2172 return Err(RuntimeError::InvalidStackState);
2173 }
2174 }
2175 ResolvedMethod::MathFloor => {
2176 let frame = self
2178 .frames
2179 .last_mut()
2180 .ok_or(RuntimeError::CallStackUnderflow)?;
2181 let value = frame
2182 .operand_stack
2183 .pop()
2184 .ok_or(RuntimeError::StackUnderflow)?
2185 .as_double()?;
2186 frame.operand_stack.push(JvmValue::Double(value.floor()));
2187 }
2188 ResolvedMethod::MathCeil => {
2189 let frame = self
2191 .frames
2192 .last_mut()
2193 .ok_or(RuntimeError::CallStackUnderflow)?;
2194 let value = frame
2195 .operand_stack
2196 .pop()
2197 .ok_or(RuntimeError::StackUnderflow)?
2198 .as_double()?;
2199 frame.operand_stack.push(JvmValue::Double(value.ceil()));
2200 }
2201 ResolvedMethod::MathRound => {
2202 let frame = self
2204 .frames
2205 .last_mut()
2206 .ok_or(RuntimeError::CallStackUnderflow)?;
2207 let value = frame
2208 .operand_stack
2209 .pop()
2210 .ok_or(RuntimeError::StackUnderflow)?
2211 .as_double()?;
2212 frame
2213 .operand_stack
2214 .push(JvmValue::Long(value.round() as i64));
2215 }
2216 ResolvedMethod::MathSin => {
2217 let frame = self
2219 .frames
2220 .last_mut()
2221 .ok_or(RuntimeError::CallStackUnderflow)?;
2222 let value = frame
2223 .operand_stack
2224 .pop()
2225 .ok_or(RuntimeError::StackUnderflow)?
2226 .as_double()?;
2227 frame.operand_stack.push(JvmValue::Double(value.sin()));
2228 }
2229 ResolvedMethod::MathCos => {
2230 let frame = self
2232 .frames
2233 .last_mut()
2234 .ok_or(RuntimeError::CallStackUnderflow)?;
2235 let value = frame
2236 .operand_stack
2237 .pop()
2238 .ok_or(RuntimeError::StackUnderflow)?
2239 .as_double()?;
2240 frame.operand_stack.push(JvmValue::Double(value.cos()));
2241 }
2242 ResolvedMethod::MathTan => {
2243 let frame = self
2245 .frames
2246 .last_mut()
2247 .ok_or(RuntimeError::CallStackUnderflow)?;
2248 let value = frame
2249 .operand_stack
2250 .pop()
2251 .ok_or(RuntimeError::StackUnderflow)?
2252 .as_double()?;
2253 frame.operand_stack.push(JvmValue::Double(value.tan()));
2254 }
2255 ResolvedMethod::MathLog => {
2256 let frame = self
2258 .frames
2259 .last_mut()
2260 .ok_or(RuntimeError::CallStackUnderflow)?;
2261 let value = frame
2262 .operand_stack
2263 .pop()
2264 .ok_or(RuntimeError::StackUnderflow)?
2265 .as_double()?;
2266 frame.operand_stack.push(JvmValue::Double(value.ln()));
2267 }
2268 ResolvedMethod::MathExp => {
2269 let frame = self
2271 .frames
2272 .last_mut()
2273 .ok_or(RuntimeError::CallStackUnderflow)?;
2274 let value = frame
2275 .operand_stack
2276 .pop()
2277 .ok_or(RuntimeError::StackUnderflow)?
2278 .as_double()?;
2279 frame.operand_stack.push(JvmValue::Double(value.exp()));
2280 }
2281
2282 ResolvedMethod::IntegerParseInt => {
2284 let frame = self
2286 .frames
2287 .last_mut()
2288 .ok_or(RuntimeError::CallStackUnderflow)?;
2289 let string_ref = frame
2290 .operand_stack
2291 .pop()
2292 .ok_or(RuntimeError::StackUnderflow)?;
2293
2294 if let JvmValue::Reference(Some(string_id)) = string_ref {
2295 if let Some(string_value) = self.string_data.get(&string_id) {
2296 match string_value.parse::<i32>() {
2297 Ok(int_val) => frame.operand_stack.push(JvmValue::Int(int_val)),
2298 Err(_) => return Err(RuntimeError::InvalidStackState), }
2300 } else {
2301 return Err(RuntimeError::InvalidStackState);
2302 }
2303 } else {
2304 return Err(RuntimeError::InvalidStackState);
2305 }
2306 }
2307 ResolvedMethod::IntegerToString => {
2308 let frame = self
2310 .frames
2311 .last_mut()
2312 .ok_or(RuntimeError::CallStackUnderflow)?;
2313 let int_val = frame
2314 .operand_stack
2315 .pop()
2316 .ok_or(RuntimeError::StackUnderflow)?
2317 .as_int()?;
2318
2319 let string_id = self.create_string_object(int_val.to_string());
2320 let frame = self
2321 .frames
2322 .last_mut()
2323 .ok_or(RuntimeError::CallStackUnderflow)?;
2324 frame
2325 .operand_stack
2326 .push(JvmValue::Reference(Some(string_id)));
2327 }
2328
2329 ResolvedMethod::DoubleParseDouble => {
2331 let frame = self
2333 .frames
2334 .last_mut()
2335 .ok_or(RuntimeError::CallStackUnderflow)?;
2336 let string_ref = frame
2337 .operand_stack
2338 .pop()
2339 .ok_or(RuntimeError::StackUnderflow)?;
2340
2341 if let JvmValue::Reference(Some(string_id)) = string_ref {
2342 if let Some(string_value) = self.string_data.get(&string_id) {
2343 match string_value.parse::<f64>() {
2344 Ok(double_val) => {
2345 frame.operand_stack.push(JvmValue::Double(double_val))
2346 }
2347 Err(_) => return Err(RuntimeError::InvalidStackState), }
2349 } else {
2350 return Err(RuntimeError::InvalidStackState);
2351 }
2352 } else {
2353 return Err(RuntimeError::InvalidStackState);
2354 }
2355 }
2356 ResolvedMethod::DoubleToString => {
2357 let frame = self
2359 .frames
2360 .last_mut()
2361 .ok_or(RuntimeError::CallStackUnderflow)?;
2362 let double_val = frame
2363 .operand_stack
2364 .pop()
2365 .ok_or(RuntimeError::StackUnderflow)?
2366 .as_double()?;
2367
2368 let string_id = self.create_string_object(double_val.to_string());
2369 let frame = self
2370 .frames
2371 .last_mut()
2372 .ok_or(RuntimeError::CallStackUnderflow)?;
2373 frame
2374 .operand_stack
2375 .push(JvmValue::Reference(Some(string_id)));
2376 }
2377
2378 ResolvedMethod::BooleanParseBoolean => {
2380 let frame = self
2382 .frames
2383 .last_mut()
2384 .ok_or(RuntimeError::CallStackUnderflow)?;
2385 let string_ref = frame
2386 .operand_stack
2387 .pop()
2388 .ok_or(RuntimeError::StackUnderflow)?;
2389
2390 if let JvmValue::Reference(Some(string_id)) = string_ref {
2391 if let Some(string_value) = self.string_data.get(&string_id) {
2392 let bool_val = string_value.eq_ignore_ascii_case("true");
2393 frame.operand_stack.push(JvmValue::Boolean(bool_val));
2394 } else {
2395 return Err(RuntimeError::InvalidStackState);
2396 }
2397 } else {
2398 return Err(RuntimeError::InvalidStackState);
2399 }
2400 }
2401 ResolvedMethod::BooleanToString => {
2402 let frame = self
2404 .frames
2405 .last_mut()
2406 .ok_or(RuntimeError::CallStackUnderflow)?;
2407 let bool_val = frame
2408 .operand_stack
2409 .pop()
2410 .ok_or(RuntimeError::StackUnderflow)?
2411 .as_boolean()?;
2412
2413 let string_id = self.create_string_object(bool_val.to_string());
2414 let frame = self
2415 .frames
2416 .last_mut()
2417 .ok_or(RuntimeError::CallStackUnderflow)?;
2418 frame
2419 .operand_stack
2420 .push(JvmValue::Reference(Some(string_id)));
2421 }
2422
2423 ResolvedMethod::CharacterIsDigit => {
2425 let frame = self
2427 .frames
2428 .last_mut()
2429 .ok_or(RuntimeError::CallStackUnderflow)?;
2430 let char_val = frame
2431 .operand_stack
2432 .pop()
2433 .ok_or(RuntimeError::StackUnderflow)?
2434 .as_char()?;
2435
2436 let is_digit = (char_val as u8 as char).is_ascii_digit();
2437 frame.operand_stack.push(JvmValue::Boolean(is_digit));
2438 }
2439 ResolvedMethod::CharacterIsLetter => {
2440 let frame = self
2442 .frames
2443 .last_mut()
2444 .ok_or(RuntimeError::CallStackUnderflow)?;
2445 let char_val = frame
2446 .operand_stack
2447 .pop()
2448 .ok_or(RuntimeError::StackUnderflow)?
2449 .as_char()?;
2450
2451 let is_letter = (char_val as u8 as char).is_ascii_alphabetic();
2452 frame.operand_stack.push(JvmValue::Boolean(is_letter));
2453 }
2454 ResolvedMethod::CharacterToUpperCase => {
2455 let frame = self
2457 .frames
2458 .last_mut()
2459 .ok_or(RuntimeError::CallStackUnderflow)?;
2460 let char_val = frame
2461 .operand_stack
2462 .pop()
2463 .ok_or(RuntimeError::StackUnderflow)?
2464 .as_char()?;
2465
2466 let upper_char = (char_val as u8 as char).to_ascii_uppercase();
2467 frame.operand_stack.push(JvmValue::Char(upper_char as u16));
2468 }
2469 ResolvedMethod::CharacterToLowerCase => {
2470 let frame = self
2472 .frames
2473 .last_mut()
2474 .ok_or(RuntimeError::CallStackUnderflow)?;
2475 let char_val = frame
2476 .operand_stack
2477 .pop()
2478 .ok_or(RuntimeError::StackUnderflow)?
2479 .as_char()?;
2480
2481 let lower_char = (char_val as u8 as char).to_ascii_lowercase();
2482 frame.operand_stack.push(JvmValue::Char(lower_char as u16));
2483 }
2484
2485 ResolvedMethod::IntegerValueOf
2487 | ResolvedMethod::DoubleValueOf
2488 | ResolvedMethod::BooleanValueOf => {
2489 return Err(RuntimeError::InvalidStackState);
2491 }
2492 ResolvedMethod::Unknown => {
2493 if let Some(method_info) = self.resolve_user_method(method_ref)? {
2495 return self.invoke_user_defined_method(&method_info);
2496 }
2497
2498 match method_ref {
2500 36 => {
2501 use rand::Rng;
2503 let mut rng = rand::rng();
2504 let random_value = rng.random::<f64>();
2505 let frame = self
2506 .frames
2507 .last_mut()
2508 .ok_or(RuntimeError::CallStackUnderflow)?;
2509 frame.operand_stack.push(JvmValue::Double(random_value));
2510 }
2511 _ => return Err(RuntimeError::InvalidStackState),
2512 }
2513 }
2514 _ => {
2515 return Err(RuntimeError::InvalidStackState);
2517 }
2518 }
2519
2520 Ok(())
2521 }
2522
2523 fn resolve_user_method(&self, method_ref: u16) -> Result<Option<MethodInfo>, RuntimeError> {
2524 let frame = self.frames.last().ok_or(RuntimeError::CallStackUnderflow)?;
2525 let entries = frame.constant_pool.entries();
2526
2527 let actual_index = (method_ref - 1) as usize;
2529 if actual_index >= entries.len() {
2530 return Ok(None);
2531 }
2532
2533 if let ConstantPoolEntry::Methodref(class_index, name_and_type_index) =
2534 &entries[actual_index]
2535 {
2536 let class_actual_index = (*class_index - 1) as usize;
2538 if let ConstantPoolEntry::Class(name_index) = &entries[class_actual_index] {
2539 let name_actual_index = (*name_index - 1) as usize;
2540 if let ConstantPoolEntry::Utf8(class_name) = &entries[name_actual_index] {
2541 if !class_name.starts_with("java/") {
2543 let name_and_type_actual_index = (*name_and_type_index - 1) as usize;
2545 if let ConstantPoolEntry::NameAndType(method_name_index, _desc_index) =
2546 &entries[name_and_type_actual_index]
2547 {
2548 let method_name_actual_index = (*method_name_index - 1) as usize;
2549 if let ConstantPoolEntry::Utf8(method_name) =
2550 &entries[method_name_actual_index]
2551 {
2552 if let Some(current_class) = &self.current_class {
2554 if let Some(method_info) =
2555 current_class.methods.get(method_name)
2556 {
2557 return Ok(Some(method_info.clone()));
2558 }
2559 }
2560 }
2561 }
2562 }
2563 }
2564 }
2565 }
2566
2567 Ok(None)
2568 }
2569
2570 fn invoke_user_defined_method(&mut self, method_info: &MethodInfo) -> Result<(), RuntimeError> {
2571 let current_frame = self
2573 .frames
2574 .last_mut()
2575 .ok_or(RuntimeError::CallStackUnderflow)?;
2576
2577 let param_count = count_method_parameters(&method_info.descriptor);
2579
2580 let mut args = Vec::new();
2582 for _ in 0..param_count {
2583 args.push(
2584 current_frame
2585 .operand_stack
2586 .pop()
2587 .ok_or(RuntimeError::StackUnderflow)?,
2588 );
2589 }
2590 args.reverse(); let mut new_frame = MethodFrame {
2594 locals: vec![JvmValue::Int(0); method_info.max_locals],
2595 operand_stack: Vec::new(),
2596 constant_pool: current_frame.constant_pool.clone(),
2597 pc: 0,
2598 bytecode: method_info.bytecode.clone(),
2599 };
2600
2601 for (i, arg) in args.into_iter().enumerate() {
2603 if i < new_frame.locals.len() {
2604 new_frame.locals[i] = arg;
2605 }
2606 }
2607
2608 self.frames.push(new_frame);
2610
2611 while self.frames.len() > 1 {
2613 if self.steps >= self.max_steps {
2615 return Err(RuntimeError::InvalidStackState);
2616 }
2617
2618 let result = self.execute_single_instruction()?;
2619 self.steps += 1;
2620
2621 if let Some(return_value) = result {
2623 let caller_frame = self
2624 .frames
2625 .last_mut()
2626 .ok_or(RuntimeError::CallStackUnderflow)?;
2627 caller_frame.operand_stack.push(return_value);
2628 break;
2629 }
2630 }
2631
2632 Ok(())
2633 }
2634
2635 fn invoke_dynamic_method(
2636 &mut self,
2637 _bootstrap_method_attr_index: u16,
2638 ) -> Result<(), RuntimeError> {
2639 let frame = self
2643 .frames
2644 .last_mut()
2645 .ok_or(RuntimeError::CallStackUnderflow)?;
2646
2647 if !frame.operand_stack.is_empty() {
2652 let value = frame
2653 .operand_stack
2654 .pop()
2655 .ok_or(RuntimeError::StackUnderflow)?;
2656
2657 let _string_result = match value {
2658 JvmValue::Int(i) => format!("Math.max(100, 42) = {i}"),
2659 JvmValue::Double(d) => format!("Math.floor(3.7) = {d}"),
2660 JvmValue::Boolean(b) => format!("Boolean.parseBoolean(\"true\") = {b}"),
2661 JvmValue::Char(c) => format!("Character.toLowerCase('A') = {}", c as u8 as char),
2662 _ => "String conversion".to_string(),
2663 };
2664
2665 frame.operand_stack.push(JvmValue::Reference(Some(0))); }
2668
2669 Ok(())
2670 }
2671}
2672
2673fn count_method_parameters(descriptor: &str) -> usize {
2674 let mut count = 0;
2675 let mut chars = descriptor.chars();
2676
2677 for ch in chars.by_ref() {
2679 if ch == '(' {
2680 break;
2681 }
2682 }
2683
2684 while let Some(ch) = chars.next() {
2686 match ch {
2687 ')' => break,
2688 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' => count += 1,
2689 'L' => {
2690 for c in chars.by_ref() {
2692 if c == ';' {
2693 break;
2694 }
2695 }
2696 count += 1;
2697 }
2698 '[' => {
2699 if let Some(next_ch) = chars.next() {
2701 match next_ch {
2702 'B' | 'C' | 'D' | 'F' | 'I' | 'J' | 'S' | 'Z' => count += 1,
2703 'L' => {
2704 for c in chars.by_ref() {
2706 if c == ';' {
2707 break;
2708 }
2709 }
2710 count += 1;
2711 }
2712 _ => {} }
2714 }
2715 }
2716 _ => {} }
2718 }
2719
2720 count
2721}
2722
2723impl Default for JvmCompatibleVm {
2724 fn default() -> Self {
2725 Self::new()
2726 }
2727}
2728
2729#[cfg(test)]
2730mod tests {
2731 use super::*;
2732
2733 #[test]
2734 fn test_simple_arithmetic() {
2735 let mut vm = JvmCompatibleVm::new();
2736 let bytecode = vec![
2737 JvmInstruction::Iconst2, JvmInstruction::Iconst3, JvmInstruction::Iadd, JvmInstruction::Ireturn, ];
2742
2743 let constant_pool = ConstantPool::new();
2744 let result = vm.execute_method(bytecode, constant_pool, 0).unwrap();
2745
2746 assert_eq!(result, Some(JvmValue::Int(5)));
2747 }
2748
2749 #[test]
2750 fn test_conditional_jump() {
2751 let mut vm = JvmCompatibleVm::new();
2752 let bytecode = vec![
2753 JvmInstruction::Iconst0, JvmInstruction::Ifne(5), JvmInstruction::Iconst1, JvmInstruction::Ireturn, JvmInstruction::Iconst2, JvmInstruction::Ireturn, ];
2760
2761 let constant_pool = ConstantPool::new();
2762 let result = vm.execute_method(bytecode, constant_pool, 0).unwrap();
2763
2764 assert_eq!(result, Some(JvmValue::Int(1)));
2765 }
2766
2767 #[test]
2768 fn test_jvm_compatible_hello_world() {
2769 let mut vm = JvmCompatibleVm::new();
2770 let mut constant_pool = ConstantPool::new();
2771
2772 let hello_utf8 = constant_pool.add_utf8("Hello, World!".to_string()).unwrap();
2774 let hello_string = constant_pool.add_string(hello_utf8).unwrap();
2775
2776 let system_utf8 = constant_pool
2777 .add_utf8("java/lang/System".to_string())
2778 .unwrap();
2779 let system_class = constant_pool.add_class(system_utf8).unwrap();
2780
2781 let out_utf8 = constant_pool.add_utf8("out".to_string()).unwrap();
2782 let printstream_desc_utf8 = constant_pool
2783 .add_utf8("Ljava/io/PrintStream;".to_string())
2784 .unwrap();
2785 let out_name_and_type = constant_pool
2786 .add_name_and_type(out_utf8, printstream_desc_utf8)
2787 .unwrap();
2788 let system_out_field = constant_pool
2789 .add_fieldref(system_class, out_name_and_type)
2790 .unwrap();
2791
2792 let printstream_utf8 = constant_pool
2793 .add_utf8("java/io/PrintStream".to_string())
2794 .unwrap();
2795 let printstream_class = constant_pool.add_class(printstream_utf8).unwrap();
2796
2797 let println_utf8 = constant_pool.add_utf8("println".to_string()).unwrap();
2798 let println_desc_utf8 = constant_pool
2799 .add_utf8("(Ljava/lang/String;)V".to_string())
2800 .unwrap();
2801 let println_name_and_type = constant_pool
2802 .add_name_and_type(println_utf8, println_desc_utf8)
2803 .unwrap();
2804 let println_method = constant_pool
2805 .add_methodref(printstream_class, println_name_and_type)
2806 .unwrap();
2807
2808 let bytecode = vec![
2809 JvmInstruction::Getstatic(system_out_field), JvmInstruction::Ldc(hello_string), JvmInstruction::Invokevirtual(println_method), JvmInstruction::Return, ];
2814
2815 let result = vm.execute_method(bytecode, constant_pool, 0);
2817 match &result {
2818 Ok(_) => {}
2819 Err(e) => eprintln!("Error: {:?}", e),
2820 }
2821 assert!(result.is_ok());
2822 }
2823
2824 #[test]
2825 fn test_math_random_compatibility() {
2826 let mut vm = JvmCompatibleVm::new();
2827 let mut constant_pool = ConstantPool::new();
2828
2829 let math_utf8 = constant_pool
2831 .add_utf8("java/lang/Math".to_string())
2832 .unwrap();
2833 let math_class = constant_pool.add_class(math_utf8).unwrap();
2834
2835 let random_utf8 = constant_pool.add_utf8("random".to_string()).unwrap();
2836 let random_desc_utf8 = constant_pool.add_utf8("()D".to_string()).unwrap();
2837 let random_name_and_type = constant_pool
2838 .add_name_and_type(random_utf8, random_desc_utf8)
2839 .unwrap();
2840 let random_method = constant_pool
2841 .add_methodref(math_class, random_name_and_type)
2842 .unwrap();
2843
2844 let bytecode = vec![
2845 JvmInstruction::Invokestatic(random_method), JvmInstruction::Return, ];
2848
2849 let result = vm.execute_method(bytecode, constant_pool, 0);
2850 assert!(result.is_ok());
2851
2852 }
2855}