Skip to content

Commit

Permalink
Is intereface (#44)
Browse files Browse the repository at this point in the history
Add cast to interface logic (along with TreeMap test)
  • Loading branch information
hextriclosan authored Oct 9, 2024
1 parent b1c4c8c commit 320dd29
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 12 deletions.
11 changes: 10 additions & 1 deletion tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,16 @@ fn should_do_trivial_hashmaps() {
let last_frame_value = vm
.run("samples.javabase.util.hashmap.trivial.TrivialHashMap")
.unwrap();
assert_eq!(-999, get_int(last_frame_value))
assert_eq!(84, get_int(last_frame_value))
}

#[test]
fn should_do_trivial_treemaps() {
let mut vm = VM::new("std");
let last_frame_value = vm
.run("samples.javabase.util.treemap.trivial.TrivialTreeMap")
.unwrap();
assert_eq!(84, get_int(last_frame_value))
}

fn get_int(locals: Option<Vec<i32>>) -> i32 {
Expand Down
19 changes: 16 additions & 3 deletions tests/test_data/TrivialHashMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,24 @@
import java.util.HashMap;

public class TrivialHashMap {

public static void main(String[] args) {
int result = getSum();
}

private static int getSum() {
Map<Integer, Integer> map = new HashMap<>();
map.put(13, -999);
map.put(1, 10);
map.put(2, 20);
map.put(3, 30);

int result = map.get(13);
map.remove(2);
map.put(1, 50);

int sum = 0;
for (var entry : map.entrySet()) {
sum += entry.getKey() + entry.getValue();
}
return sum;
}
}

26 changes: 26 additions & 0 deletions tests/test_data/TrivialTreeMap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package samples.javabase.util.treemap.trivial;

import java.util.Map;
import java.util.TreeMap;

public class TrivialTreeMap {
public static void main(String[] args) {
int result = getSum();
}

private static int getSum() {
Map<Integer, Integer> map = new TreeMap<>();
map.put(1, 10);
map.put(2, 20);
map.put(3, 30);

map.remove(2);
map.put(1, 50);

int sum = 0;
for (var entry : map.entrySet()) {
sum += entry.getKey() + entry.getValue();
}
return sum;
}
}
Binary file not shown.
Binary file not shown.
5 changes: 5 additions & 0 deletions vm/src/execution_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ impl Engine {
stack_frame.incr_pc();
println!("ACONST_NULL");
}
ICONST_M1 => {
stack_frame.push(-1);
stack_frame.incr_pc();
println!("ICONST_M1");
}
ICONST_0 => {
stack_frame.push(0);
stack_frame.incr_pc();
Expand Down
21 changes: 21 additions & 0 deletions vm/src/method_area/instance_checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ impl InstanceChecker {
return Ok(base_of);
}

if let Some(implements) = Self::is_implements(class_cast_to, class_cast_from) {
return Ok(implements);
}

Ok(false)
}

Expand All @@ -31,4 +35,21 @@ impl InstanceChecker {

Self::is_base_of(base, &class_name)
}

fn is_implements(interface: &str, implementor: &str) -> Option<bool> {
let class = with_method_area(|method_area| method_area.get(interface)).ok()?;
if !class.is_interface() {
return None;
}
let class_implementor =
with_method_area(|method_area| method_area.get(implementor)).ok()?;

if class_implementor.interfaces().contains(interface) {
return Some(true);
}

let class_name = class_implementor.parent().clone()?;

Self::is_implements(interface, &class_name)
}
}
18 changes: 12 additions & 6 deletions vm/src/method_area/java_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ use crate::method_area::java_method::JavaMethod;
use crate::method_area::method_area::with_method_area;
use jdescriptor::TypeDescriptor;
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

const INTERFACE: u16 = 0x00000200;

#[derive(Debug)]
pub(crate) struct JavaClass {
pub(crate) methods: Methods,
Expand All @@ -20,7 +22,7 @@ pub(crate) struct JavaClass {
cpool_helper: CPoolHelper,
this_class_name: String,
parent: Option<String>,
_interfaces: Vec<String>,
interfaces: HashSet<String>,
access_flags: u16,

static_fields_initialized: AtomicBool,
Expand Down Expand Up @@ -65,7 +67,7 @@ impl JavaClass {
cpool_helper: CPoolHelper,
this_class_name: String,
parent: Option<String>,
interfaces: Vec<String>,
interfaces: HashSet<String>,
access_flags: u16,
) -> Self {
Self {
Expand All @@ -75,7 +77,7 @@ impl JavaClass {
cpool_helper,
this_class_name,
parent,
_interfaces: interfaces,
interfaces,
access_flags,
static_fields_initialized: AtomicBool::new(false),
reflection_ref: OnceCell::new(),
Expand Down Expand Up @@ -105,8 +107,12 @@ impl JavaClass {
&self.parent
}

pub fn _interfaces(&self) -> &Vec<String> {
&self._interfaces
pub fn interfaces(&self) -> &HashSet<String> {
&self.interfaces
}

pub fn is_interface(&self) -> bool {
self.access_flags & INTERFACE != 0
}

pub fn static_field(&self, field_name: &str) -> crate::error::Result<Arc<Field>> {
Expand Down
4 changes: 2 additions & 2 deletions vm/src/method_area/method_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use jclass::fields::{FieldFlags, FieldInfo};
use jclass::methods::{MethodFlags, MethodInfo};
use jdescriptor::TypeDescriptor;
use once_cell::sync::OnceCell;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -148,7 +148,7 @@ impl MethodArea {
Error::new_constant_pool(&format!("Error getting interface by index={index}"))
})
})
.collect::<crate::error::Result<Vec<String>>>()?;
.collect::<crate::error::Result<HashSet<String>>>()?;

let methods = Self::get_methods(&class_file.methods(), &cpool_helper, &class_name)?;
let (non_static_field_descriptors, static_fields) =
Expand Down

0 comments on commit 320dd29

Please sign in to comment.