More error checking in invokestatic
This commit is contained in:
parent
2042007242
commit
fb29955f7d
3 changed files with 41 additions and 2 deletions
|
@ -1,4 +1,5 @@
|
|||
use core::fmt::{Formatter, Debug};
|
||||
use core::ops::BitAnd;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(u16)]
|
||||
|
@ -36,10 +37,18 @@ impl MethodAccessFlag {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct MethodAccessFlagMask {
|
||||
pub mask: u16,
|
||||
}
|
||||
|
||||
impl BitAnd<MethodAccessFlag> for MethodAccessFlagMask {
|
||||
type Output=bool;
|
||||
fn bitand(self, f: MethodAccessFlag) -> bool {
|
||||
return (self.mask & f.discriminant()) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for MethodAccessFlagMask {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
let mut flag_vec = Vec::new();
|
||||
|
|
|
@ -130,6 +130,11 @@ impl ClassStore {
|
|||
|
||||
return Some(was_init);
|
||||
}
|
||||
|
||||
pub fn set_init(&mut self, class_idx: usize, was_init: bool) {
|
||||
let pair = self.classes.get_mut(class_idx).unwrap();
|
||||
pair.0 = was_init;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
29
src/jvm.rs
29
src/jvm.rs
|
@ -17,6 +17,7 @@ pub enum Error {
|
|||
ClassFileError(classfile::Error),
|
||||
BadNameError(String),
|
||||
RunTimeError(String),
|
||||
OpcodeError(String),
|
||||
}
|
||||
|
||||
impl From<classfile::Error> for Error {
|
||||
|
@ -151,6 +152,7 @@ impl JVM {
|
|||
// TODO: ConstantValue Attributes (final)
|
||||
// TODO: Static Stuff
|
||||
|
||||
self.class_store.set_init(class_idx, true);
|
||||
}
|
||||
|
||||
fn prepare_invoke_static(&mut self, class_index: usize, method_name: &String, arguments: &[Value]) -> Result<(), Error> {
|
||||
|
@ -210,6 +212,17 @@ impl JVM {
|
|||
// TODO: Throw exception on fail
|
||||
let callee_method_info = &callee_class_file.methods[callee_method_index];
|
||||
|
||||
if ! (callee_method_info.access_flags & MethodAccessFlag::Static) {
|
||||
// TODO: Throw IncompatibleClassChangeError
|
||||
return Err(Error::RunTimeError(format!(
|
||||
"Invoked method '{}' in class '{}' does not have Access::Static (from invokestatic from '{}' in class '{}')",
|
||||
method.name,
|
||||
class.get_classname().unwrap(),
|
||||
supplied_method_name,
|
||||
supplied_class_name,
|
||||
)));
|
||||
}
|
||||
|
||||
let supplied_descriptor: MethodDescriptor = supplied_descriptor_string.try_into()?;
|
||||
// TODO: Throw exception on fail
|
||||
|
||||
|
@ -225,6 +238,7 @@ impl JVM {
|
|||
}
|
||||
|
||||
let arguments = Vec::new();
|
||||
// TODO: Pass arguments
|
||||
|
||||
let new_frame = StackFrame::new(
|
||||
callee_class_file,
|
||||
|
@ -233,11 +247,22 @@ impl JVM {
|
|||
&arguments.into_boxed_slice(),
|
||||
);
|
||||
|
||||
//println!("{} {} {}", class_name, method_name, method_descriptor);
|
||||
|
||||
return Ok(JVMCallbackOperation::PushFrame(new_frame));
|
||||
},
|
||||
|
||||
Instruction::ReturnVoid() => {
|
||||
let expected_type = AbstractTypeDescription {
|
||||
array_level: 0,
|
||||
kind: AbstractTypeKind::Void(),
|
||||
};
|
||||
|
||||
if method.descriptor.return_type != expected_type {
|
||||
return Err(Error::OpcodeError(format!("Found opcode '{:?}' on method returning '{:?}'", instruction, method.descriptor.return_type)))
|
||||
}
|
||||
|
||||
return Ok(JVMCallbackOperation::PopFrame());
|
||||
},
|
||||
|
||||
_ => {
|
||||
return Err(Error::RunTimeError(format!("Opcode not implemented yet: {:?}", instruction)))
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue