Skip to main content

jvm_assembler/validator/
mod.rs

1use super::program::{entities::{JvmMethod, JvmProgram}, instructions::JvmInstruction, types::JvmVerificationType};
2
3/// Bytecode validation error
4#[derive(Debug, Clone)]
5pub struct ValidationError {
6    /// Error message
7    pub message: String,
8    /// Instruction index where the error occurred
9    pub instruction_index: usize,
10    /// Optional error detail
11    pub detail: Option<String>,
12}
13
14impl ValidationError {
15    /// Creates a new validation error
16    pub fn new(message: String, instruction_index: usize, detail: Option<String>) -> Self {
17        Self { message, instruction_index, detail }
18    }
19}
20
21/// Bytecode validator
22pub struct BytecodeValidator<'a> {
23    /// Current stack state
24    stack: Vec<JvmVerificationType>,
25    /// Current local variables state
26    locals: Vec<Option<JvmVerificationType>>,
27    /// Method being validated
28    method: &'a JvmMethod,
29    /// Validation errors
30    errors: Vec<ValidationError>,
31    /// Instruction index
32    current_index: usize,
33}
34
35impl<'a> BytecodeValidator<'a> {
36    /// Creates a new bytecode validator
37    pub fn new(method: &'a JvmMethod) -> Self {
38        let max_locals = method.max_locals as usize;
39        Self {
40            stack: Vec::new(),
41            locals: vec![None; max_locals],
42            method,
43            errors: Vec::new(),
44            current_index: 0,
45        }
46    }
47
48    /// Validates the method bytecode
49    pub fn validate(&mut self) -> Vec<ValidationError> {
50        // Initialize locals for method parameters
51        self.initialize_locals();
52
53        // Validate each instruction
54        for (index, instruction) in self.method.instructions.iter().enumerate() {
55            self.current_index = index;
56            self.validate_instruction(instruction);
57        }
58
59        // Check that all paths end with a return instruction
60        self.check_return_instruction();
61
62        self.errors.clone()
63    }
64
65    /// Initializes local variables based on method descriptor
66    fn initialize_locals(&mut self) {
67        // Parse method descriptor to determine parameter types
68        let descriptor = &self.method.descriptor;
69        let param_start = descriptor.find('(').unwrap_or(0) + 1;
70        let param_end = descriptor.find(')').unwrap_or(descriptor.len());
71        let params_str = &descriptor[param_start..param_end];
72
73        let mut param_index = 0;
74        let mut i = 0;
75
76        while i < params_str.len() {
77            let ch = params_str.chars().nth(i).unwrap();
78            match ch {
79                'B' | 'C' | 'F' | 'I' | 'S' | 'Z' => {
80                    // 1-word type
81                    self.locals[param_index] = Some(JvmVerificationType::Integer);
82                    param_index += 1;
83                    i += 1;
84                }
85                'D' | 'J' => {
86                    // 2-word type
87                    self.locals[param_index] = Some(if ch == 'D' {
88                        JvmVerificationType::Double
89                    } else {
90                        JvmVerificationType::Long
91                    });
92                    param_index += 2;
93                    i += 1;
94                }
95                'L' => {
96                    // Object type
97                    let end = params_str.find(';').unwrap_or(i + 1);
98                    let class_name = &params_str[i + 1..end];
99                    self.locals[param_index] = Some(JvmVerificationType::Object {
100                        class_name: class_name.to_string(),
101                    });
102                    param_index += 1;
103                    i = end + 1;
104                }
105                '[' => {
106                    // Array type
107                    let mut array_depth = 1;
108                    let mut j = i + 1;
109                    while j < params_str.len() && array_depth > 0 {
110                        if params_str.chars().nth(j).unwrap() == '[' {
111                            array_depth += 1;
112                        } else if params_str.chars().nth(j).unwrap() == ';' {
113                            array_depth -= 1;
114                        } else if array_depth == 1 {
115                            array_depth = 0;
116                        }
117                        j += 1;
118                    }
119                    self.locals[param_index] = Some(JvmVerificationType::Object {
120                        class_name: params_str[i..j].to_string(),
121                    });
122                    param_index += 1;
123                    i = j;
124                }
125                _ => i += 1,
126            }
127        }
128
129        // If not static, add 'this' reference as first local variable
130        if !self.method.access_flags.is_static {
131            // Shift existing params right by 1
132            for i in (1..self.locals.len()).rev() {
133                if i + 1 < self.locals.len() {
134                    self.locals[i + 1] = self.locals[i].clone();
135                }
136            }
137            // Add 'this' reference
138            if !self.locals.is_empty() {
139                self.locals[0] = Some(JvmVerificationType::Object {
140                    class_name: self.method.name.split('.').last().unwrap_or("").to_string(),
141                });
142            }
143        }
144    }
145
146    /// Validates a single instruction
147    fn validate_instruction(&mut self, instruction: &JvmInstruction) {
148        match instruction {
149            JvmInstruction::Nop => {}
150            JvmInstruction::AconstNull => {
151                self.stack.push(JvmVerificationType::Null);
152            }
153            JvmInstruction::IconstM1 | JvmInstruction::Iconst0 | JvmInstruction::Iconst1 |
154            JvmInstruction::Iconst2 | JvmInstruction::Iconst3 | JvmInstruction::Iconst4 |
155            JvmInstruction::Iconst5 => {
156                self.stack.push(JvmVerificationType::Integer);
157            }
158            JvmInstruction::Lconst0 | JvmInstruction::Lconst1 => {
159                self.stack.push(JvmVerificationType::Long);
160            }
161            JvmInstruction::Fconst0 | JvmInstruction::Fconst1 | JvmInstruction::Fconst2 => {
162                self.stack.push(JvmVerificationType::Float);
163            }
164            JvmInstruction::Dconst0 | JvmInstruction::Dconst1 => {
165                self.stack.push(JvmVerificationType::Double);
166            }
167            JvmInstruction::Bipush { .. } | JvmInstruction::Sipush { .. } => {
168                self.stack.push(JvmVerificationType::Integer);
169            }
170            JvmInstruction::Ldc { .. } | JvmInstruction::LdcW { .. } => {
171                // Assume LDC pushes an integer, float, or reference
172                self.stack.push(JvmVerificationType::Integer);
173            }
174            JvmInstruction::Ldc2W { .. } => {
175                // LDC2_W pushes a long or double
176                self.stack.push(JvmVerificationType::Long);
177            }
178            JvmInstruction::Iload { index } => {
179                self.validate_load_instruction(*index, JvmVerificationType::Integer);
180            }
181            JvmInstruction::Iload0 => self.validate_load_instruction(0, JvmVerificationType::Integer),
182            JvmInstruction::Iload1 => self.validate_load_instruction(1, JvmVerificationType::Integer),
183            JvmInstruction::Iload2 => self.validate_load_instruction(2, JvmVerificationType::Integer),
184            JvmInstruction::Iload3 => self.validate_load_instruction(3, JvmVerificationType::Integer),
185            JvmInstruction::Lload { index } => {
186                self.validate_load_instruction(*index, JvmVerificationType::Long);
187            }
188            JvmInstruction::Lload0 => self.validate_load_instruction(0, JvmVerificationType::Long),
189            JvmInstruction::Lload1 => self.validate_load_instruction(1, JvmVerificationType::Long),
190            JvmInstruction::Lload2 => self.validate_load_instruction(2, JvmVerificationType::Long),
191            JvmInstruction::Lload3 => self.validate_load_instruction(3, JvmVerificationType::Long),
192            JvmInstruction::Fload { index } => {
193                self.validate_load_instruction(*index, JvmVerificationType::Float);
194            }
195            JvmInstruction::Fload0 => self.validate_load_instruction(0, JvmVerificationType::Float),
196            JvmInstruction::Fload1 => self.validate_load_instruction(1, JvmVerificationType::Float),
197            JvmInstruction::Fload2 => self.validate_load_instruction(2, JvmVerificationType::Float),
198            JvmInstruction::Fload3 => self.validate_load_instruction(3, JvmVerificationType::Float),
199            JvmInstruction::Dload { index } => {
200                self.validate_load_instruction(*index, JvmVerificationType::Double);
201            }
202            JvmInstruction::Dload0 => self.validate_load_instruction(0, JvmVerificationType::Double),
203            JvmInstruction::Dload1 => self.validate_load_instruction(1, JvmVerificationType::Double),
204            JvmInstruction::Dload2 => self.validate_load_instruction(2, JvmVerificationType::Double),
205            JvmInstruction::Dload3 => self.validate_load_instruction(3, JvmVerificationType::Double),
206            JvmInstruction::Aload { index } => {
207                self.validate_load_instruction(*index, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
208            }
209            JvmInstruction::Aload0 => self.validate_load_instruction(0, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
210            JvmInstruction::Aload1 => self.validate_load_instruction(1, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
211            JvmInstruction::Aload2 => self.validate_load_instruction(2, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
212            JvmInstruction::Aload3 => self.validate_load_instruction(3, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
213            JvmInstruction::Iaload => {
214                // Pop array reference and index, push int
215                self.validate_stack_size(2);
216                self.stack.pop(); // index
217                self.stack.pop(); // array reference
218                self.stack.push(JvmVerificationType::Integer);
219            }
220            JvmInstruction::Laload => {
221                // Pop array reference and index, push long
222                self.validate_stack_size(2);
223                self.stack.pop(); // index
224                self.stack.pop(); // array reference
225                self.stack.push(JvmVerificationType::Long);
226            }
227            JvmInstruction::Faload => {
228                // Pop array reference and index, push float
229                self.validate_stack_size(2);
230                self.stack.pop(); // index
231                self.stack.pop(); // array reference
232                self.stack.push(JvmVerificationType::Float);
233            }
234            JvmInstruction::Daload => {
235                // Pop array reference and index, push double
236                self.validate_stack_size(2);
237                self.stack.pop(); // index
238                self.stack.pop(); // array reference
239                self.stack.push(JvmVerificationType::Double);
240            }
241            JvmInstruction::Aaload => {
242                // Pop array reference and index, push reference
243                self.validate_stack_size(2);
244                self.stack.pop(); // index
245                self.stack.pop(); // array reference
246                self.stack.push(JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
247            }
248            JvmInstruction::Baload | JvmInstruction::Caload | JvmInstruction::Saload => {
249                // Pop array reference and index, push int
250                self.validate_stack_size(2);
251                self.stack.pop(); // index
252                self.stack.pop(); // array reference
253                self.stack.push(JvmVerificationType::Integer);
254            }
255            JvmInstruction::Istore { index } => {
256                self.validate_store_instruction(*index, JvmVerificationType::Integer);
257            }
258            JvmInstruction::Istore0 => self.validate_store_instruction(0, JvmVerificationType::Integer),
259            JvmInstruction::Istore1 => self.validate_store_instruction(1, JvmVerificationType::Integer),
260            JvmInstruction::Istore2 => self.validate_store_instruction(2, JvmVerificationType::Integer),
261            JvmInstruction::Istore3 => self.validate_store_instruction(3, JvmVerificationType::Integer),
262            JvmInstruction::Lstore { index } => {
263                self.validate_store_instruction(*index, JvmVerificationType::Long);
264            }
265            JvmInstruction::Lstore0 => self.validate_store_instruction(0, JvmVerificationType::Long),
266            JvmInstruction::Lstore1 => self.validate_store_instruction(1, JvmVerificationType::Long),
267            JvmInstruction::Lstore2 => self.validate_store_instruction(2, JvmVerificationType::Long),
268            JvmInstruction::Lstore3 => self.validate_store_instruction(3, JvmVerificationType::Long),
269            JvmInstruction::Fstore { index } => {
270                self.validate_store_instruction(*index, JvmVerificationType::Float);
271            }
272            JvmInstruction::Fstore0 => self.validate_store_instruction(0, JvmVerificationType::Float),
273            JvmInstruction::Fstore1 => self.validate_store_instruction(1, JvmVerificationType::Float),
274            JvmInstruction::Fstore2 => self.validate_store_instruction(2, JvmVerificationType::Float),
275            JvmInstruction::Fstore3 => self.validate_store_instruction(3, JvmVerificationType::Float),
276            JvmInstruction::Dstore { index } => {
277                self.validate_store_instruction(*index, JvmVerificationType::Double);
278            }
279            JvmInstruction::Dstore0 => self.validate_store_instruction(0, JvmVerificationType::Double),
280            JvmInstruction::Dstore1 => self.validate_store_instruction(1, JvmVerificationType::Double),
281            JvmInstruction::Dstore2 => self.validate_store_instruction(2, JvmVerificationType::Double),
282            JvmInstruction::Dstore3 => self.validate_store_instruction(3, JvmVerificationType::Double),
283            JvmInstruction::Astore { index } => {
284                self.validate_store_instruction(*index, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
285            }
286            JvmInstruction::Astore0 => self.validate_store_instruction(0, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
287            JvmInstruction::Astore1 => self.validate_store_instruction(1, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
288            JvmInstruction::Astore2 => self.validate_store_instruction(2, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
289            JvmInstruction::Astore3 => self.validate_store_instruction(3, JvmVerificationType::Object { class_name: "java/lang/Object".to_string() }),
290            JvmInstruction::Iastore => {
291                // Pop value, index, array reference
292                self.validate_stack_size(3);
293                self.stack.pop(); // value
294                self.stack.pop(); // index
295                self.stack.pop(); // array reference
296            }
297            JvmInstruction::Lastore => {
298                // Pop value, index, array reference
299                self.validate_stack_size(3);
300                self.stack.pop(); // value
301                self.stack.pop(); // index
302                self.stack.pop(); // array reference
303            }
304            JvmInstruction::Fastore => {
305                // Pop value, index, array reference
306                self.validate_stack_size(3);
307                self.stack.pop(); // value
308                self.stack.pop(); // index
309                self.stack.pop(); // array reference
310            }
311            JvmInstruction::Dastore => {
312                // Pop value, index, array reference
313                self.validate_stack_size(3);
314                self.stack.pop(); // value
315                self.stack.pop(); // index
316                self.stack.pop(); // array reference
317            }
318            JvmInstruction::Aastore => {
319                // Pop value, index, array reference
320                self.validate_stack_size(3);
321                self.stack.pop(); // value
322                self.stack.pop(); // index
323                self.stack.pop(); // array reference
324            }
325            JvmInstruction::Bastore | JvmInstruction::Castore | JvmInstruction::Sastore => {
326                // Pop value, index, array reference
327                self.validate_stack_size(3);
328                self.stack.pop(); // value
329                self.stack.pop(); // index
330                self.stack.pop(); // array reference
331            }
332            JvmInstruction::Pop => {
333                self.validate_stack_size(1);
334                self.stack.pop();
335            }
336            JvmInstruction::Pop2 => {
337                self.validate_stack_size(2);
338                self.stack.pop();
339                self.stack.pop();
340            }
341            JvmInstruction::Dup => {
342                self.validate_stack_size(1);
343                if let Some(top) = self.stack.last().cloned() {
344                    self.stack.push(top);
345                }
346            }
347            JvmInstruction::DupX1 => {
348                self.validate_stack_size(2);
349                let top = self.stack.pop().unwrap();
350                let second = self.stack.pop().unwrap();
351                self.stack.push(top.clone());
352                self.stack.push(second);
353                self.stack.push(top);
354            }
355            JvmInstruction::DupX2 => {
356                self.validate_stack_size(3);
357                let top = self.stack.pop().unwrap();
358                let second = self.stack.pop().unwrap();
359                let third = self.stack.pop().unwrap();
360                self.stack.push(top.clone());
361                self.stack.push(third);
362                self.stack.push(second);
363                self.stack.push(top);
364            }
365            JvmInstruction::Dup2 => {
366                self.validate_stack_size(2);
367                let top = self.stack.pop().unwrap();
368                let second = self.stack.pop().unwrap();
369                self.stack.push(second.clone());
370                self.stack.push(top.clone());
371                self.stack.push(second);
372                self.stack.push(top);
373            }
374            JvmInstruction::Dup2X1 => {
375                self.validate_stack_size(3);
376                let top = self.stack.pop().unwrap();
377                let second = self.stack.pop().unwrap();
378                let third = self.stack.pop().unwrap();
379                self.stack.push(second.clone());
380                self.stack.push(top.clone());
381                self.stack.push(third);
382                self.stack.push(second);
383                self.stack.push(top);
384            }
385            JvmInstruction::Dup2X2 => {
386                self.validate_stack_size(4);
387                let top = self.stack.pop().unwrap();
388                let second = self.stack.pop().unwrap();
389                let third = self.stack.pop().unwrap();
390                let fourth = self.stack.pop().unwrap();
391                self.stack.push(second.clone());
392                self.stack.push(top.clone());
393                self.stack.push(fourth);
394                self.stack.push(third);
395                self.stack.push(second);
396                self.stack.push(top);
397            }
398            JvmInstruction::Swap => {
399                self.validate_stack_size(2);
400                let top = self.stack.pop().unwrap();
401                let second = self.stack.pop().unwrap();
402                self.stack.push(top);
403                self.stack.push(second);
404            }
405            JvmInstruction::Iadd | JvmInstruction::Isub | JvmInstruction::Imul |
406            JvmInstruction::Idiv | JvmInstruction::Irem | JvmInstruction::Ineg |
407            JvmInstruction::Ishl | JvmInstruction::Ishr | JvmInstruction::Iushr |
408            JvmInstruction::Iand | JvmInstruction::Ior | JvmInstruction::Ixor => {
409                // Integer operations: pop 2 (or 1 for neg), push 1
410                let required = if matches!(instruction, JvmInstruction::Ineg) { 1 } else { 2 };
411                self.validate_stack_size(required);
412                for _ in 0..required {
413                    self.stack.pop();
414                }
415                self.stack.push(JvmVerificationType::Integer);
416            }
417            JvmInstruction::Ladd | JvmInstruction::Lsub | JvmInstruction::Lmul |
418            JvmInstruction::Ldiv | JvmInstruction::Lrem | JvmInstruction::Lneg |
419            JvmInstruction::Lshl | JvmInstruction::Lshr | JvmInstruction::Lushr |
420            JvmInstruction::Land | JvmInstruction::Lor | JvmInstruction::Lxor => {
421                // Long operations: pop 2 (or 1 for neg), push 1
422                let required = if matches!(instruction, JvmInstruction::Lneg) { 1 } else { 2 };
423                self.validate_stack_size(required);
424                for _ in 0..required {
425                    self.stack.pop();
426                }
427                self.stack.push(JvmVerificationType::Long);
428            }
429            JvmInstruction::Fadd | JvmInstruction::Fsub | JvmInstruction::Fmul |
430            JvmInstruction::Fdiv | JvmInstruction::Frem | JvmInstruction::Fneg => {
431                // Float operations: pop 2 (or 1 for neg), push 1
432                let required = if matches!(instruction, JvmInstruction::Fneg) { 1 } else { 2 };
433                self.validate_stack_size(required);
434                for _ in 0..required {
435                    self.stack.pop();
436                }
437                self.stack.push(JvmVerificationType::Float);
438            }
439            JvmInstruction::Dadd | JvmInstruction::Dsub | JvmInstruction::Dmul |
440            JvmInstruction::Ddiv | JvmInstruction::Drem | JvmInstruction::Dneg => {
441                // Double operations: pop 2 (or 1 for neg), push 1
442                let required = if matches!(instruction, JvmInstruction::Dneg) { 1 } else { 2 };
443                self.validate_stack_size(required);
444                for _ in 0..required {
445                    self.stack.pop();
446                }
447                self.stack.push(JvmVerificationType::Double);
448            }
449            JvmInstruction::Iinc { index, .. } => {
450                // Iinc doesn't affect stack
451                if *index as usize >= self.locals.len() {
452                    self.errors.push(ValidationError::new(
453                        "Local variable index out of bounds".to_string(),
454                        self.current_index,
455                        Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
456                    ));
457                }
458            }
459            JvmInstruction::I2l => {
460                self.validate_stack_size(1);
461                self.stack.pop();
462                self.stack.push(JvmVerificationType::Long);
463            }
464            JvmInstruction::I2f => {
465                self.validate_stack_size(1);
466                self.stack.pop();
467                self.stack.push(JvmVerificationType::Float);
468            }
469            JvmInstruction::I2d => {
470                self.validate_stack_size(1);
471                self.stack.pop();
472                self.stack.push(JvmVerificationType::Double);
473            }
474            JvmInstruction::L2i => {
475                self.validate_stack_size(1);
476                self.stack.pop();
477                self.stack.push(JvmVerificationType::Integer);
478            }
479            JvmInstruction::L2f => {
480                self.validate_stack_size(1);
481                self.stack.pop();
482                self.stack.push(JvmVerificationType::Float);
483            }
484            JvmInstruction::L2d => {
485                self.validate_stack_size(1);
486                self.stack.pop();
487                self.stack.push(JvmVerificationType::Double);
488            }
489            JvmInstruction::F2i => {
490                self.validate_stack_size(1);
491                self.stack.pop();
492                self.stack.push(JvmVerificationType::Integer);
493            }
494            JvmInstruction::F2l => {
495                self.validate_stack_size(1);
496                self.stack.pop();
497                self.stack.push(JvmVerificationType::Long);
498            }
499            JvmInstruction::F2d => {
500                self.validate_stack_size(1);
501                self.stack.pop();
502                self.stack.push(JvmVerificationType::Double);
503            }
504            JvmInstruction::D2i => {
505                self.validate_stack_size(1);
506                self.stack.pop();
507                self.stack.push(JvmVerificationType::Integer);
508            }
509            JvmInstruction::D2l => {
510                self.validate_stack_size(1);
511                self.stack.pop();
512                self.stack.push(JvmVerificationType::Long);
513            }
514            JvmInstruction::D2f => {
515                self.validate_stack_size(1);
516                self.stack.pop();
517                self.stack.push(JvmVerificationType::Float);
518            }
519            JvmInstruction::I2b | JvmInstruction::I2c | JvmInstruction::I2s => {
520                self.validate_stack_size(1);
521                self.stack.pop();
522                self.stack.push(JvmVerificationType::Integer);
523            }
524            JvmInstruction::Lcmp => {
525                self.validate_stack_size(2);
526                self.stack.pop();
527                self.stack.pop();
528                self.stack.push(JvmVerificationType::Integer);
529            }
530            JvmInstruction::Fcmpl | JvmInstruction::Fcmpg => {
531                self.validate_stack_size(2);
532                self.stack.pop();
533                self.stack.pop();
534                self.stack.push(JvmVerificationType::Integer);
535            }
536            JvmInstruction::Dcmpl | JvmInstruction::Dcmpg => {
537                self.validate_stack_size(2);
538                self.stack.pop();
539                self.stack.pop();
540                self.stack.push(JvmVerificationType::Integer);
541            }
542            JvmInstruction::Ifeq { .. } | JvmInstruction::Ifne { .. } |
543            JvmInstruction::Iflt { .. } | JvmInstruction::Ifge { .. } |
544            JvmInstruction::Ifgt { .. } | JvmInstruction::Ifle { .. } => {
545                // Pop 1 integer
546                self.validate_stack_size(1);
547                self.stack.pop();
548            }
549            JvmInstruction::IfIcmpeq { .. } | JvmInstruction::IfIcmpne { .. } |
550            JvmInstruction::IfIcmplt { .. } | JvmInstruction::IfIcmpge { .. } |
551            JvmInstruction::IfIcmpgt { .. } | JvmInstruction::IfIcmple { .. } => {
552                // Pop 2 integers
553                self.validate_stack_size(2);
554                self.stack.pop();
555                self.stack.pop();
556            }
557            JvmInstruction::IfAcmpeq { .. } | JvmInstruction::IfAcmpne { .. } => {
558                // Pop 2 references
559                self.validate_stack_size(2);
560                self.stack.pop();
561                self.stack.pop();
562            }
563            JvmInstruction::Goto { .. } | JvmInstruction::Jsr { .. } |
564            JvmInstruction::GotoW { .. } | JvmInstruction::JsrW { .. } => {
565                // No stack changes
566            }
567            JvmInstruction::Tableswitch { .. } | JvmInstruction::Lookupswitch { .. } => {
568                // Pop 1 integer
569                self.validate_stack_size(1);
570                self.stack.pop();
571            }
572            JvmInstruction::Ireturn => {
573                // Pop 1 integer
574                self.validate_stack_size(1);
575                self.stack.pop();
576            }
577            JvmInstruction::Lreturn => {
578                // Pop 1 long
579                self.validate_stack_size(1);
580                self.stack.pop();
581            }
582            JvmInstruction::Freturn => {
583                // Pop 1 float
584                self.validate_stack_size(1);
585                self.stack.pop();
586            }
587            JvmInstruction::Dreturn => {
588                // Pop 1 double
589                self.validate_stack_size(1);
590                self.stack.pop();
591            }
592            JvmInstruction::Areturn => {
593                // Pop 1 reference
594                self.validate_stack_size(1);
595                self.stack.pop();
596            }
597            JvmInstruction::Return => {
598                // No stack changes for void return
599                if !self.stack.is_empty() {
600                    self.errors.push(ValidationError::new(
601                        "Stack not empty on void return".to_string(),
602                        self.current_index,
603                        Some(format!("Stack size: {}", self.stack.len())),
604                    ));
605                }
606            }
607            JvmInstruction::Getstatic { .. } => {
608                // Push field value based on descriptor
609                // For simplicity, assume it pushes a value
610                self.stack.push(JvmVerificationType::Integer);
611            }
612            JvmInstruction::Putstatic { .. } => {
613                // Pop field value based on descriptor
614                self.validate_stack_size(1);
615                self.stack.pop();
616            }
617            JvmInstruction::Getfield { .. } => {
618                // Pop object reference, push field value
619                self.validate_stack_size(1);
620                self.stack.pop();
621                self.stack.push(JvmVerificationType::Integer);
622            }
623            JvmInstruction::Putfield { .. } => {
624                // Pop field value, object reference
625                self.validate_stack_size(2);
626                self.stack.pop();
627                self.stack.pop();
628            }
629            JvmInstruction::Invokevirtual { .. } | JvmInstruction::Invokespecial { .. } |
630            JvmInstruction::Invokestatic { .. } | JvmInstruction::Invokeinterface { .. } |
631            JvmInstruction::Invokedynamic { .. } => {
632                // Pop method arguments, push return value (if any)
633                // For simplicity, assume no return value
634                self.validate_stack_size(1); // At least 'this' reference
635                self.stack.pop();
636            }
637            JvmInstruction::New { .. } => {
638                // Push uninitialized object reference
639                self.stack.push(JvmVerificationType::UninitializedThis);
640            }
641            JvmInstruction::Newarray { .. } => {
642                // Pop array length, push array reference
643                self.validate_stack_size(1);
644                self.stack.pop();
645                self.stack.push(JvmVerificationType::Object { class_name: "[I".to_string() });
646            }
647            JvmInstruction::Anewarray { .. } => {
648                // Pop array length, push array reference
649                self.validate_stack_size(1);
650                self.stack.pop();
651                self.stack.push(JvmVerificationType::Object { class_name: "[Ljava/lang/Object;".to_string() });
652            }
653            JvmInstruction::Arraylength => {
654                // Pop array reference, push int length
655                self.validate_stack_size(1);
656                self.stack.pop();
657                self.stack.push(JvmVerificationType::Integer);
658            }
659            JvmInstruction::Athrow => {
660                // Pop exception reference
661                self.validate_stack_size(1);
662                self.stack.pop();
663            }
664            JvmInstruction::Checkcast { .. } => {
665                // Pop reference, push reference (same or subclass)
666                self.validate_stack_size(1);
667                self.stack.pop();
668                self.stack.push(JvmVerificationType::Object { class_name: "java/lang/Object".to_string() });
669            }
670            JvmInstruction::Instanceof { .. } => {
671                // Pop reference, push int (0 or 1)
672                self.validate_stack_size(1);
673                self.stack.pop();
674                self.stack.push(JvmVerificationType::Integer);
675            }
676            JvmInstruction::Monitorenter | JvmInstruction::Monitorexit => {
677                // Pop object reference
678                self.validate_stack_size(1);
679                self.stack.pop();
680            }
681            JvmInstruction::Wide => {
682                // Wide prefix, no stack changes
683            }
684            JvmInstruction::Multianewarray { .. } => {
685                // Pop dimensions count, push array reference
686                self.validate_stack_size(1);
687                self.stack.pop();
688                self.stack.push(JvmVerificationType::Object { class_name: "[[I".to_string() });
689            }
690            JvmInstruction::Ifnull { .. } | JvmInstruction::Ifnonnull { .. } => {
691                // Pop reference
692                self.validate_stack_size(1);
693                self.stack.pop();
694            }
695            JvmInstruction::Ret { index } => {
696                // No stack changes, but validate local variable
697                if *index as usize >= self.locals.len() {
698                    self.errors.push(ValidationError::new(
699                        "Local variable index out of bounds".to_string(),
700                        self.current_index,
701                        Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
702                    ));
703                }
704            }
705            JvmInstruction::Label { .. } => {
706                // Label pseudo-instruction, no stack changes
707            }
708        }
709
710        // Check stack size against max_stack
711        if self.stack.len() > self.method.max_stack as usize {
712            self.errors.push(ValidationError::new(
713                "Stack overflow".to_string(),
714                self.current_index,
715                Some(format!("Stack size {} exceeds max_stack {}", self.stack.len(), self.method.max_stack)),
716            ));
717        }
718    }
719
720    /// Validates a load instruction
721    fn validate_load_instruction(&mut self, index: u16, expected_type: JvmVerificationType) {
722        let index_usize = index as usize;
723        if index_usize >= self.locals.len() {
724            self.errors.push(ValidationError::new(
725                "Local variable index out of bounds".to_string(),
726                self.current_index,
727                Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
728            ));
729        } else if self.locals[index_usize].is_none() {
730            self.errors.push(ValidationError::new(
731                "Uninitialized local variable access".to_string(),
732                self.current_index,
733                Some(format!("Variable at index {} is not initialized", index)),
734            ));
735        } else {
736            // Push the loaded value onto the stack
737            self.stack.push(expected_type);
738        }
739    }
740
741    /// Validates a store instruction
742    fn validate_store_instruction(&mut self, index: u16, expected_type: JvmVerificationType) {
743        let index_usize = index as usize;
744        if index_usize >= self.locals.len() {
745            self.errors.push(ValidationError::new(
746                "Local variable index out of bounds".to_string(),
747                self.current_index,
748                Some(format!("Index {} exceeds max_locals {}", index, self.locals.len())),
749            ));
750        } else if self.stack.is_empty() {
751            self.errors.push(ValidationError::new(
752                "Stack underflow on store instruction".to_string(),
753                self.current_index,
754                None,
755            ));
756        } else {
757            // Pop the value from the stack and store it
758            self.stack.pop();
759            self.locals[index_usize] = Some(expected_type);
760        }
761    }
762
763    /// Validates that the stack has at least the required size
764    fn validate_stack_size(&mut self, required: usize) {
765        if self.stack.len() < required {
766            self.errors.push(ValidationError::new(
767                "Stack underflow".to_string(),
768                self.current_index,
769                Some(format!("Required stack size: {}, actual: {}", required, self.stack.len())),
770            ));
771        }
772    }
773
774    /// Checks that the method ends with a return instruction
775    fn check_return_instruction(&mut self) {
776        if let Some(last_inst) = self.method.instructions.last() {
777            match last_inst {
778                JvmInstruction::Ireturn | JvmInstruction::Lreturn | JvmInstruction::Freturn |
779                JvmInstruction::Dreturn | JvmInstruction::Areturn | JvmInstruction::Return => {
780                    // Valid return instruction
781                }
782                _ => {
783                    self.errors.push(ValidationError::new(
784                        "Method does not end with return instruction".to_string(),
785                        self.method.instructions.len() - 1,
786                        None,
787                    ));
788                }
789            }
790        } else {
791            self.errors.push(ValidationError::new(
792                "Method has no instructions".to_string(),
793                0,
794                None,
795            ));
796        }
797    }
798}
799
800/// Validates a JVM program
801pub fn validate_program(program: &JvmProgram) -> Vec<ValidationError> {
802    let mut all_errors = Vec::new();
803
804    for (_method_index, method) in program.methods.iter().enumerate() {
805        let mut validator = BytecodeValidator::new(method);
806        let method_errors = validator.validate();
807        
808        // Add method context to errors
809        for error in method_errors {
810            all_errors.push(ValidationError::new(
811                format!("Method '{}': {}", method.name, error.message),
812                error.instruction_index,
813                error.detail,
814            ));
815        }
816    }
817
818    all_errors
819}