Implemented java/lang/Throwable.fill_in_stacktrace
This commit is contained in:
parent
d38d5b2897
commit
45d0aa66e5
2 changed files with 128 additions and 2 deletions
|
@ -375,6 +375,22 @@ impl JavaClassFile {
|
||||||
|
|
||||||
return Ok((class_name, method_name, method_descriptor));
|
return Ok((class_name, method_name, method_descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sourcefile(&self) -> Result<Option<&String>, Error> {
|
||||||
|
match self.attributes.into_iter()
|
||||||
|
.filter_map(|attribute| match &attribute.data {
|
||||||
|
AttributeData::SourceFile(data) => Some(data),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next() {
|
||||||
|
None => Ok(None),
|
||||||
|
Some(data) => {
|
||||||
|
let sourcefile_name = &self.pool_utf8_entry(data.source_file_index)?.utf8;
|
||||||
|
|
||||||
|
Ok(Some(sourcefile_name))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -953,6 +969,13 @@ impl AbstractTypeDescription {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn class_type(class: &str) -> AbstractTypeDescription {
|
||||||
|
AbstractTypeDescription {
|
||||||
|
array_level: 0,
|
||||||
|
kind: AbstractTypeKind::Classname(class.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
@ -1078,6 +1101,23 @@ impl MethodInfo {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_bytecode_linenumber(&self, bytecode_index: u16) -> Option<u16> {
|
||||||
|
let linenumbertable = match self.attributes
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|a| match &a.data {
|
||||||
|
AttributeData::LineNumberTable(data) => Some(data),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.next() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
linenumbertable.entries.into_iter()
|
||||||
|
.take_while(|entry| entry.start_pc < bytecode_index)
|
||||||
|
.map(|entry| entry.line_number)
|
||||||
|
.last()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_code_attribute(&self) -> Option<&CodeAttributeData> {
|
pub fn get_code_attribute(&self) -> Option<&CodeAttributeData> {
|
||||||
return if self.code_attribute_index != self.attributes.len() {
|
return if self.code_attribute_index != self.attributes.len() {
|
||||||
match &self.attributes[self.code_attribute_index].data {
|
match &self.attributes[self.code_attribute_index].data {
|
||||||
|
|
|
@ -350,7 +350,7 @@ struct JavaLangSystem {}
|
||||||
|
|
||||||
impl JavaLangSystem {
|
impl JavaLangSystem {
|
||||||
pub fn arraycopy(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
pub fn arraycopy(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
let frame = {
|
let frame = {
|
||||||
let frame_index = jvm.stack_frames.len() - 1;
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
&mut jvm.stack_frames[frame_index]
|
&mut jvm.stack_frames[frame_index]
|
||||||
};
|
};
|
||||||
|
@ -372,7 +372,93 @@ impl JavaLangSystem {
|
||||||
struct JavaLangThrowable {}
|
struct JavaLangThrowable {}
|
||||||
|
|
||||||
impl JavaLangThrowable {
|
impl JavaLangThrowable {
|
||||||
|
pub fn fill_in_stacktrace(jvm: &mut JVM) -> Result<JVMCallbackOperation, Error> {
|
||||||
|
if ! jvm.class_store.have_class(&String::from("java/lang/StackTraceElement")) {
|
||||||
|
return Ok(JVMCallbackOperation::LoadClass(String::from("java/lang/StackTraceElement")));
|
||||||
|
}
|
||||||
|
if ! jvm.class_store.was_init(&String::from("java/lang/StackTraceElement")).unwrap() {
|
||||||
|
return Ok(JVMCallbackOperation::LoadClass(String::from("java/lang/StackTraceElement")));
|
||||||
|
}
|
||||||
|
|
||||||
|
let stackelement_class_index = jvm.class_store.class_idx_from_name(&String::from("java/lang/StackTraceElement")).unwrap();
|
||||||
|
let stackelement_class_ref = jvm.class_store.get_class_objectref_from_index(stackelement_class_index);
|
||||||
|
let stackelement_type = AbstractTypeDescription::class_type("java/lang/StackTraceElement");
|
||||||
|
let _ = match jvm.class_store.get_array_class_ref(&stackelement_type.array()) {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return Ok(JVMCallbackOperation::MakeArrayClass(stackelement_class_ref, stackelement_type)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let this = {
|
||||||
|
let frame = {
|
||||||
|
let frame_index = jvm.stack_frames.len() - 1;
|
||||||
|
&jvm.stack_frames[frame_index]
|
||||||
|
};
|
||||||
|
frame.load_local_reference(0).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let stackelement_array = jvm.heap_area.make_empty_array(&jvm.class_store, AbstractTypeDescription::class_type("java/lang/StackTraceElement"), jvm.stack_frames.len());
|
||||||
|
|
||||||
|
jvm.heap_area.object_area.set_object_field(
|
||||||
|
this,
|
||||||
|
"stackTrace",
|
||||||
|
stackelement_array.into(),
|
||||||
|
stackelement_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for (index, frame) in (&jvm.stack_frames).into_iter().enumerate() {
|
||||||
|
let class_file = jvm.class_store.class_file_from_idx(frame.class_index).unwrap();
|
||||||
|
let method_info = &class_file.methods[frame.method_index as usize];
|
||||||
|
|
||||||
|
let class_name = class_file.get_classname()?;
|
||||||
|
|
||||||
|
let line_number = method_info.get_bytecode_linenumber(frame.instruction_pointer.try_into().unwrap());
|
||||||
|
|
||||||
|
let stackelement = jvm.heap_area.make_object(&jvm.class_store, stackelement_class_index);
|
||||||
|
|
||||||
|
let class_name_string = jvm.heap_area.make_handmade_string(class_name, &jvm.class_store);
|
||||||
|
let method_name_string = jvm.heap_area.make_handmade_string(&method_info.name, &jvm.class_store);
|
||||||
|
|
||||||
|
let sourcefile = class_file.sourcefile()?;
|
||||||
|
let sourcefile_string = match sourcefile {
|
||||||
|
Some(string) => jvm.heap_area.make_handmade_string(string, &jvm.class_store),
|
||||||
|
None => jvm.heap_area.static_area.get(&String::from("StackTraceElement"), &String::from("UNKNOWN_SOURCE"), AbstractTypeDescription::class_type("java/lang/String")).unwrap().expect_reference(),
|
||||||
|
};
|
||||||
|
|
||||||
|
jvm.heap_area.object_area.set_object_field(
|
||||||
|
stackelement,
|
||||||
|
"declaringClass",
|
||||||
|
FieldValue::Reference(class_name_string),
|
||||||
|
stackelement_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
)?;
|
||||||
|
jvm.heap_area.object_area.set_object_field(
|
||||||
|
stackelement,
|
||||||
|
"methodName",
|
||||||
|
FieldValue::Reference(method_name_string),
|
||||||
|
stackelement_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
)?;
|
||||||
|
jvm.heap_area.object_area.set_object_field(
|
||||||
|
stackelement,
|
||||||
|
"lineNumber",
|
||||||
|
FieldValue::Int(line_number.unwrap_or(1) as i32),
|
||||||
|
stackelement_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
)?;
|
||||||
|
jvm.heap_area.object_area.set_object_field(
|
||||||
|
stackelement,
|
||||||
|
"fileName",
|
||||||
|
FieldValue::Reference(sourcefile_string),
|
||||||
|
stackelement_class_index,
|
||||||
|
&jvm.class_store
|
||||||
|
)?;
|
||||||
|
|
||||||
|
jvm.heap_area.object_area.set_array_element(stackelement_array, index, stackelement.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(JVMCallbackOperation::ReturnFrame(this.into()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JdkInternalMiscUnsafe {}
|
struct JdkInternalMiscUnsafe {}
|
||||||
|
@ -2861,7 +2947,7 @@ pub fn function_for(class_name: &str, m: &crate::classfile::MethodInfo) -> Resul
|
||||||
]),
|
]),
|
||||||
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Throwable".to_string())},
|
return_type: AbstractTypeDescription { array_level: 0, kind: AbstractTypeKind::Classname("java/lang/Throwable".to_string())},
|
||||||
},
|
},
|
||||||
JavaLangThrowable::fill_in_stacktrace()
|
JavaLangThrowable::fill_in_stacktrace
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue