Skip to content

Commit 8a0ee69

Browse files
committed
Fix JAR manifest lookup and add typed Attributes entry views
1 parent 5e9360a commit 8a0ee69

17 files changed

Lines changed: 693 additions & 132 deletions

‎rustjava-runtime/src/classes/java/util/hash_map.rs‎

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,6 @@ impl HashMap {
125125
Ok(entry_set.into())
126126
}
127127

128-
async fn keys_snapshot(jvm: &Jvm, this: &ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Array<Object>>> {
129-
Self::snapshot_entries(jvm, this, SnapshotKind::Keys).await
130-
}
131-
132-
async fn values_snapshot(jvm: &Jvm, this: &ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Array<Object>>> {
133-
Self::snapshot_entries(jvm, this, SnapshotKind::Values).await
134-
}
135-
136-
async fn entries_snapshot(jvm: &Jvm, this: &ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Array<Object>>> {
137-
Self::snapshot_entries(jvm, this, SnapshotKind::Entries).await
138-
}
139-
140128
async fn init_with_capacity(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, capacity: i32) -> Result<()> {
141129
tracing::debug!("java.util.HashMap::<init>({this:?}, {capacity:?})");
142130

@@ -473,28 +461,40 @@ impl HashMap {
473461
}
474462

475463
async fn key_iterator(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Object>> {
476-
let snapshot = Self::keys_snapshot(jvm, &this).await?;
464+
let snapshot = Self::snapshot_entries(jvm, &this).await?;
477465

478466
Ok(jvm
479-
.new_class("java/util/HashMap$KeyIterator", "([Ljava/lang/Object;)V", (snapshot,))
467+
.new_class(
468+
"java/util/HashMap$KeyIterator",
469+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
470+
(this, snapshot),
471+
)
480472
.await?
481473
.into())
482474
}
483475

484476
async fn value_iterator(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Object>> {
485-
let snapshot = Self::values_snapshot(jvm, &this).await?;
477+
let snapshot = Self::snapshot_entries(jvm, &this).await?;
486478

487479
Ok(jvm
488-
.new_class("java/util/HashMap$ValueIterator", "([Ljava/lang/Object;)V", (snapshot,))
480+
.new_class(
481+
"java/util/HashMap$ValueIterator",
482+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
483+
(this, snapshot),
484+
)
489485
.await?
490486
.into())
491487
}
492488

493489
async fn entry_iterator(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Object>> {
494-
let snapshot = Self::entries_snapshot(jvm, &this).await?;
490+
let snapshot = Self::snapshot_entries(jvm, &this).await?;
495491

496492
Ok(jvm
497-
.new_class("java/util/HashMap$EntryIterator", "([Ljava/lang/Object;)V", (snapshot,))
493+
.new_class(
494+
"java/util/HashMap$EntryIterator",
495+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
496+
(this, snapshot),
497+
)
498498
.await?
499499
.into())
500500
}
@@ -655,7 +655,7 @@ impl HashMap {
655655
(hash & 0x7FFFFFFF) as usize % table_len
656656
}
657657

658-
async fn snapshot_entries(jvm: &Jvm, this: &ClassInstanceRef<Self>, kind: SnapshotKind) -> Result<ClassInstanceRef<Array<Object>>> {
658+
async fn snapshot_entries(jvm: &Jvm, this: &ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Array<Object>>> {
659659
let table: ClassInstanceRef<Array<HashMapEntry>> = jvm.get_field(this, "java/util/HashMap", "table", "[Ljava/util/HashMap$Entry;").await?;
660660
let table_len = jvm.array_length(&table).await?;
661661
let size: i32 = jvm.get_field(this, "java/util/HashMap", "size", "I").await?;
@@ -664,12 +664,7 @@ impl HashMap {
664664
for bucket_index in 0..table_len {
665665
let mut entry = Self::load_bucket(jvm, &table, bucket_index).await?;
666666
while !entry.is_null() {
667-
let element = match kind {
668-
SnapshotKind::Keys => jvm.get_field(&entry, "java/util/HashMap$Entry", "key", "Ljava/lang/Object;").await?,
669-
SnapshotKind::Values => jvm.get_field(&entry, "java/util/HashMap$Entry", "value", "Ljava/lang/Object;").await?,
670-
SnapshotKind::Entries => ClassInstanceRef::new(entry.clone().instance),
671-
};
672-
elements.push(element);
667+
elements.push(ClassInstanceRef::new(entry.clone().instance));
673668

674669
entry = jvm
675670
.get_field(&entry, "java/util/HashMap$Entry", "next", "Ljava/util/HashMap$Entry;")
@@ -689,10 +684,3 @@ impl HashMap {
689684
if capacity <= 0 { 0 } else { (capacity as f32 * load_factor) as i32 }
690685
}
691686
}
692-
693-
#[derive(Copy, Clone)]
694-
enum SnapshotKind {
695-
Keys,
696-
Values,
697-
Entries,
698-
}

‎rustjava-runtime/src/classes/java/util/hash_map_entry_iterator.rs‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use jvm_types::{ClassAccessFlags, MethodAccessFlags};
66

77
use crate::{RuntimeClassProto, RuntimeContext, classes::java::lang::Object};
88

9+
use super::HashMap;
10+
911
// class java.util.HashMap$EntryIterator
1012
pub struct HashMapEntryIterator;
1113

@@ -17,7 +19,7 @@ impl HashMapEntryIterator {
1719
interfaces: vec![],
1820
methods: vec![JavaMethodProto::new(
1921
"<init>",
20-
"([Ljava/lang/Object;)V",
22+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
2123
Self::init,
2224
MethodAccessFlags::empty(),
2325
)],
@@ -26,10 +28,22 @@ impl HashMapEntryIterator {
2628
}
2729
}
2830

29-
async fn init(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, elements: ClassInstanceRef<Array<Object>>) -> Result<()> {
31+
async fn init(
32+
jvm: &Jvm,
33+
_: &mut RuntimeContext,
34+
this: ClassInstanceRef<Self>,
35+
map: ClassInstanceRef<HashMap>,
36+
elements: ClassInstanceRef<Array<Object>>,
37+
) -> Result<()> {
3038
tracing::debug!("java.util.HashMap$EntryIterator::<init>({this:?}, {elements:?})");
3139

32-
jvm.invoke_special(&this, "java/util/HashMap$HashIterator", "<init>", "([Ljava/lang/Object;)V", (elements,))
33-
.await
40+
jvm.invoke_special(
41+
&this,
42+
"java/util/HashMap$HashIterator",
43+
"<init>",
44+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
45+
(map, elements),
46+
)
47+
.await
3448
}
3549
}

‎rustjava-runtime/src/classes/java/util/hash_map_hash_iterator.rs‎

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use jvm_types::{ClassAccessFlags, FieldAccessFlags, MethodAccessFlags};
66

77
use crate::{RuntimeClassProto, RuntimeContext, classes::java::lang::Object};
88

9+
use super::{HashMap, HashMapEntry};
10+
911
// abstract class java.util.HashMap$HashIterator
1012
pub struct HashMapHashIterator;
1113

@@ -16,24 +18,39 @@ impl HashMapHashIterator {
1618
parent_class: Some("java/lang/Object"),
1719
interfaces: vec!["java/util/Iterator"],
1820
methods: vec![
19-
JavaMethodProto::new("<init>", "([Ljava/lang/Object;)V", Self::init, MethodAccessFlags::empty()),
21+
JavaMethodProto::new(
22+
"<init>",
23+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
24+
Self::init,
25+
MethodAccessFlags::empty(),
26+
),
2027
JavaMethodProto::new("hasNext", "()Z", Self::has_next, MethodAccessFlags::PUBLIC | MethodAccessFlags::FINAL),
2128
JavaMethodProto::new("next", "()Ljava/lang/Object;", Self::next, MethodAccessFlags::PUBLIC),
2229
JavaMethodProto::new("remove", "()V", Self::remove, MethodAccessFlags::PUBLIC | MethodAccessFlags::FINAL),
2330
],
2431
fields: vec![
32+
JavaFieldProto::new("map", "Ljava/util/HashMap;", FieldAccessFlags::PRIVATE),
33+
JavaFieldProto::new("lastReturned", "Ljava/util/HashMap$Entry;", FieldAccessFlags::PRIVATE),
2534
JavaFieldProto::new("elements", "[Ljava/lang/Object;", FieldAccessFlags::PRIVATE),
2635
JavaFieldProto::new("index", "I", FieldAccessFlags::empty()),
2736
],
2837
access_flags: ClassAccessFlags::ABSTRACT,
2938
}
3039
}
3140

32-
async fn init(jvm: &Jvm, _: &mut RuntimeContext, mut this: ClassInstanceRef<Self>, elements: ClassInstanceRef<Array<Object>>) -> Result<()> {
41+
async fn init(
42+
jvm: &Jvm,
43+
_: &mut RuntimeContext,
44+
mut this: ClassInstanceRef<Self>,
45+
map: ClassInstanceRef<HashMap>,
46+
elements: ClassInstanceRef<Array<Object>>,
47+
) -> Result<()> {
3348
tracing::debug!("java.util.HashMap$HashIterator::<init>({this:?}, {elements:?})");
3449

3550
let _: () = jvm.invoke_special(&this, "java/lang/Object", "<init>", "()V", ()).await?;
3651

52+
jvm.put_field(&mut this, "java/util/HashMap$HashIterator", "map", "Ljava/util/HashMap;", map)
53+
.await?;
3754
jvm.put_field(&mut this, "java/util/HashMap$HashIterator", "elements", "[Ljava/lang/Object;", elements)
3855
.await?;
3956
jvm.put_field(&mut this, "java/util/HashMap$HashIterator", "index", "I", 0).await?;
@@ -66,19 +83,48 @@ impl HashMapHashIterator {
6683
return Err(jvm.exception("java/util/NoSuchElementException", "HashMap iterator exhausted").await);
6784
}
6885

69-
let mut values = jvm.load_array(&elements, index as usize, 1).await?;
86+
let mut values: alloc::vec::Vec<ClassInstanceRef<Object>> = jvm.load_array(&elements, index as usize, 1).await?;
7087
let Some(element) = values.pop() else {
7188
return Err(jvm.exception("java/util/NoSuchElementException", "HashMap iterator exhausted").await);
7289
};
7390
jvm.put_field(&mut this, "java/util/HashMap$HashIterator", "index", "I", index + 1)
7491
.await?;
92+
jvm.put_field(
93+
&mut this,
94+
"java/util/HashMap$HashIterator",
95+
"lastReturned",
96+
"Ljava/util/HashMap$Entry;",
97+
element.clone(),
98+
)
99+
.await?;
75100

76101
Ok(element)
77102
}
78103

79-
async fn remove(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<()> {
104+
async fn remove(jvm: &Jvm, _: &mut RuntimeContext, mut this: ClassInstanceRef<Self>) -> Result<()> {
80105
tracing::debug!("java.util.HashMap$HashIterator::remove({this:?})");
81106

82-
Err(jvm.exception("java/lang/UnsupportedOperationException", "Iterator.remove").await)
107+
let entry: ClassInstanceRef<HashMapEntry> = jvm
108+
.get_field(&this, "java/util/HashMap$HashIterator", "lastReturned", "Ljava/util/HashMap$Entry;")
109+
.await?;
110+
if entry.is_null() {
111+
return Err(jvm.exception("java/lang/IllegalStateException", "No entry to remove").await);
112+
}
113+
let map = jvm
114+
.get_field(&this, "java/util/HashMap$HashIterator", "map", "Ljava/util/HashMap;")
115+
.await?;
116+
let key: ClassInstanceRef<Object> = jvm.get_field(&entry, "java/util/HashMap$Entry", "key", "Ljava/lang/Object;").await?;
117+
let _: ClassInstanceRef<Object> = jvm
118+
.invoke_virtual(&map, "java/util/HashMap", "remove", "(Ljava/lang/Object;)Ljava/lang/Object;", (key,))
119+
.await?;
120+
let null_entry: ClassInstanceRef<HashMapEntry> = None.into();
121+
jvm.put_field(
122+
&mut this,
123+
"java/util/HashMap$HashIterator",
124+
"lastReturned",
125+
"Ljava/util/HashMap$Entry;",
126+
null_entry,
127+
)
128+
.await
83129
}
84130
}

‎rustjava-runtime/src/classes/java/util/hash_map_key_iterator.rs‎

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use jvm_types::{ClassAccessFlags, MethodAccessFlags};
66

77
use crate::{RuntimeClassProto, RuntimeContext, classes::java::lang::Object};
88

9+
use super::HashMap;
10+
911
// class java.util.HashMap$KeyIterator
1012
pub struct HashMapKeyIterator;
1113

@@ -15,21 +17,43 @@ impl HashMapKeyIterator {
1517
name: "java/util/HashMap$KeyIterator",
1618
parent_class: Some("java/util/HashMap$HashIterator"),
1719
interfaces: vec![],
18-
methods: vec![JavaMethodProto::new(
19-
"<init>",
20-
"([Ljava/lang/Object;)V",
21-
Self::init,
22-
MethodAccessFlags::empty(),
23-
)],
20+
methods: vec![
21+
JavaMethodProto::new(
22+
"<init>",
23+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
24+
Self::init,
25+
MethodAccessFlags::empty(),
26+
),
27+
JavaMethodProto::new("next", "()Ljava/lang/Object;", Self::next, MethodAccessFlags::PUBLIC),
28+
],
2429
fields: vec![],
2530
access_flags: ClassAccessFlags::FINAL,
2631
}
2732
}
2833

29-
async fn init(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, elements: ClassInstanceRef<Array<Object>>) -> Result<()> {
34+
async fn next(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Object>> {
35+
let entry = jvm
36+
.invoke_special(&this, "java/util/HashMap$HashIterator", "next", "()Ljava/lang/Object;", ())
37+
.await?;
38+
jvm.get_field(&entry, "java/util/HashMap$Entry", "key", "Ljava/lang/Object;").await
39+
}
40+
41+
async fn init(
42+
jvm: &Jvm,
43+
_: &mut RuntimeContext,
44+
this: ClassInstanceRef<Self>,
45+
map: ClassInstanceRef<HashMap>,
46+
elements: ClassInstanceRef<Array<Object>>,
47+
) -> Result<()> {
3048
tracing::debug!("java.util.HashMap$KeyIterator::<init>({this:?}, {elements:?})");
3149

32-
jvm.invoke_special(&this, "java/util/HashMap$HashIterator", "<init>", "([Ljava/lang/Object;)V", (elements,))
33-
.await
50+
jvm.invoke_special(
51+
&this,
52+
"java/util/HashMap$HashIterator",
53+
"<init>",
54+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
55+
(map, elements),
56+
)
57+
.await
3458
}
3559
}

‎rustjava-runtime/src/classes/java/util/hash_map_value_iterator.rs‎

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use jvm_types::{ClassAccessFlags, MethodAccessFlags};
66

77
use crate::{RuntimeClassProto, RuntimeContext, classes::java::lang::Object};
88

9+
use super::HashMap;
10+
911
// class java.util.HashMap$ValueIterator
1012
pub struct HashMapValueIterator;
1113

@@ -15,21 +17,43 @@ impl HashMapValueIterator {
1517
name: "java/util/HashMap$ValueIterator",
1618
parent_class: Some("java/util/HashMap$HashIterator"),
1719
interfaces: vec![],
18-
methods: vec![JavaMethodProto::new(
19-
"<init>",
20-
"([Ljava/lang/Object;)V",
21-
Self::init,
22-
MethodAccessFlags::empty(),
23-
)],
20+
methods: vec![
21+
JavaMethodProto::new(
22+
"<init>",
23+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
24+
Self::init,
25+
MethodAccessFlags::empty(),
26+
),
27+
JavaMethodProto::new("next", "()Ljava/lang/Object;", Self::next, MethodAccessFlags::PUBLIC),
28+
],
2429
fields: vec![],
2530
access_flags: ClassAccessFlags::FINAL,
2631
}
2732
}
2833

29-
async fn init(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>, elements: ClassInstanceRef<Array<Object>>) -> Result<()> {
34+
async fn next(jvm: &Jvm, _: &mut RuntimeContext, this: ClassInstanceRef<Self>) -> Result<ClassInstanceRef<Object>> {
35+
let entry = jvm
36+
.invoke_special(&this, "java/util/HashMap$HashIterator", "next", "()Ljava/lang/Object;", ())
37+
.await?;
38+
jvm.get_field(&entry, "java/util/HashMap$Entry", "value", "Ljava/lang/Object;").await
39+
}
40+
41+
async fn init(
42+
jvm: &Jvm,
43+
_: &mut RuntimeContext,
44+
this: ClassInstanceRef<Self>,
45+
map: ClassInstanceRef<HashMap>,
46+
elements: ClassInstanceRef<Array<Object>>,
47+
) -> Result<()> {
3048
tracing::debug!("java.util.HashMap$ValueIterator::<init>({this:?}, {elements:?})");
3149

32-
jvm.invoke_special(&this, "java/util/HashMap$HashIterator", "<init>", "([Ljava/lang/Object;)V", (elements,))
33-
.await
50+
jvm.invoke_special(
51+
&this,
52+
"java/util/HashMap$HashIterator",
53+
"<init>",
54+
"(Ljava/util/HashMap;[Ljava/lang/Object;)V",
55+
(map, elements),
56+
)
57+
.await
3458
}
3559
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
mod attributes;
2+
mod attributes_name;
23
mod jar_entry;
34
mod jar_file;
45
mod jar_file_entries;
56
mod manifest;
67

7-
pub use {attributes::Attributes, jar_entry::JarEntry, jar_file::JarFile, jar_file_entries::JarFileEntries, manifest::Manifest};
8+
pub use {
9+
attributes::Attributes, attributes_name::AttributesName, jar_entry::JarEntry, jar_file::JarFile, jar_file_entries::JarFileEntries,
10+
manifest::Manifest,
11+
};

0 commit comments

Comments
 (0)