Skip to content

Commit 34a4235

Browse files
author
jun0
committed
[rustjava-upstream-sync-s4] merge upstream cut 3296139 (GlobalRef/CLI classpath/CDC text, PR dlunch#184)
conflicts 2 resolved: jvm/src/jvm.rs -> union (upstream's load_bootstrap_class + our double_must_use allow); java/lang/thread.rs -> upstream's GlobalRef body under PR #4's manual span.
2 parents c80638a + 3296139 commit 34a4235

50 files changed

Lines changed: 4418 additions & 187 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎Cargo.lock‎

Lines changed: 2 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ tracing-subscriber = { version = "^0.3", features = ["env-filter"] }
4747

4848
jvm = { workspace = true }
4949
jvm_rust = { workspace = true }
50-
classfile = { workspace = true }
5150
java_class_proto = { workspace = true }
5251
java_runtime = { workspace = true }
5352

‎java_runtime/src/classes/java.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod io;
22
pub mod lang;
33
pub mod net;
4+
pub mod text;
45
pub mod util;

‎java_runtime/src/classes/java/io/file.rs‎

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use alloc::vec;
22

33
use java_class_proto::{JavaFieldProto, JavaMethodProto};
4-
use jvm::{ClassInstanceRef, Jvm, Result, runtime::JavaLangString};
4+
use java_constants::{FieldAccessFlags, MethodAccessFlags};
5+
use jvm::{ClassInstanceRef, JavaChar, Jvm, Result, runtime::JavaLangString};
56

67
use crate::{FileType, RuntimeClassProto, RuntimeContext, classes::java::lang::String};
78

@@ -15,6 +16,7 @@ impl File {
1516
parent_class: Some("java/lang/Object"),
1617
interfaces: vec![],
1718
methods: vec![
19+
JavaMethodProto::new("<clinit>", "()V", Self::clinit, MethodAccessFlags::STATIC),
1820
JavaMethodProto::new("<init>", "(Ljava/lang/String;)V", Self::init, Default::default()),
1921
JavaMethodProto::new("getPath", "()Ljava/lang/String;", Self::get_path, Default::default()),
2022
JavaMethodProto::new("exists", "()Z", Self::exists, Default::default()),
@@ -23,11 +25,63 @@ impl File {
2325
JavaMethodProto::new("delete", "()Z", Self::delete, Default::default()),
2426
JavaMethodProto::new("length", "()J", Self::length, Default::default()),
2527
],
26-
fields: vec![JavaFieldProto::new("path", "Ljava/lang/String;", Default::default())],
28+
fields: vec![
29+
JavaFieldProto::new(
30+
"separatorChar",
31+
"C",
32+
FieldAccessFlags::PUBLIC | FieldAccessFlags::STATIC | FieldAccessFlags::FINAL,
33+
),
34+
JavaFieldProto::new(
35+
"separator",
36+
"Ljava/lang/String;",
37+
FieldAccessFlags::PUBLIC | FieldAccessFlags::STATIC | FieldAccessFlags::FINAL,
38+
),
39+
JavaFieldProto::new(
40+
"pathSeparatorChar",
41+
"C",
42+
FieldAccessFlags::PUBLIC | FieldAccessFlags::STATIC | FieldAccessFlags::FINAL,
43+
),
44+
JavaFieldProto::new(
45+
"pathSeparator",
46+
"Ljava/lang/String;",
47+
FieldAccessFlags::PUBLIC | FieldAccessFlags::STATIC | FieldAccessFlags::FINAL,
48+
),
49+
JavaFieldProto::new("path", "Ljava/lang/String;", Default::default()),
50+
],
2751
access_flags: Default::default(),
2852
}
2953
}
3054

55+
async fn clinit(jvm: &Jvm, _: &mut RuntimeContext) -> Result<()> {
56+
tracing::debug!("java.io.File::<clinit>()");
57+
58+
let separator_char = if cfg!(windows) { '\\' } else { '/' };
59+
let separator = if cfg!(windows) { "\\" } else { "/" };
60+
let path_separator_char = if cfg!(windows) { ';' } else { ':' };
61+
let path_separator = if cfg!(windows) { ";" } else { ":" };
62+
63+
jvm.put_static_field("java/io/File", "separatorChar", "C", separator_char as JavaChar)
64+
.await?;
65+
jvm.put_static_field(
66+
"java/io/File",
67+
"separator",
68+
"Ljava/lang/String;",
69+
JavaLangString::from_rust_string(jvm, separator).await?,
70+
)
71+
.await?;
72+
jvm.put_static_field("java/io/File", "pathSeparatorChar", "C", path_separator_char as JavaChar)
73+
.await?;
74+
jvm.put_static_field(
75+
"java/io/File",
76+
"pathSeparator",
77+
"Ljava/lang/String;",
78+
JavaLangString::from_rust_string(jvm, path_separator).await?,
79+
)
80+
.await?;
81+
82+
Ok(())
83+
}
84+
3185
async fn init(jvm: &Jvm, _: &mut RuntimeContext, mut this: ClassInstanceRef<Self>, pathname: ClassInstanceRef<String>) -> Result<()> {
3286
tracing::debug!("java.io.File::<init>({this:?}, {pathname:?})");
3387

‎java_runtime/src/classes/java/lang/class_loader.rs‎

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,28 +97,45 @@ impl ClassLoader {
9797
)
9898
.await?;
9999

100-
let url_array = if !class_path.is_null() {
100+
let (class_paths, urls) = if !class_path.is_null() {
101101
let class_path = JavaLangString::to_rust_string(jvm, &class_path).await?;
102+
let path_separator: ClassInstanceRef<String> = jvm.get_static_field("java/io/File", "pathSeparator", "Ljava/lang/String;").await?;
103+
let path_separator = JavaLangString::to_rust_string(jvm, &path_separator).await?;
102104

105+
let mut class_paths = Vec::new();
103106
let mut urls = Vec::new();
104-
for path in class_path.split(':') {
105-
// TODO File.pathSeparator
107+
for path in class_path.split(path_separator.as_str()) {
108+
class_paths.push(JavaLangString::from_rust_string(jvm, path).await?);
109+
106110
let path = JavaLangString::from_rust_string(jvm, &format!("file:{path}")).await?;
107111
let url = jvm.new_class("java/net/URL", "(Ljava/lang/String;)V", (path,)).await?;
108-
109112
urls.push(url);
110113
}
111114

112-
let mut url_array = jvm.instantiate_array("Ljava/net/URL;", urls.len()).await?;
113-
jvm.store_array(&mut url_array, 0, urls).await?;
114-
115-
url_array
115+
(class_paths, urls)
116116
} else {
117-
jvm.instantiate_array("Ljava/net/URL;", 0).await?
117+
(Vec::new(), Vec::new())
118118
};
119119

120+
let mut class_path_array = jvm.instantiate_array("Ljava/lang/String;", class_paths.len()).await?;
121+
jvm.store_array(&mut class_path_array, 0, class_paths).await?;
122+
let rustjar_class_loader = jvm
123+
.new_class(
124+
"org/rustjava/lang/RustJarClassLoader",
125+
"([Ljava/lang/String;Ljava/lang/ClassLoader;)V",
126+
(class_path_array, None),
127+
)
128+
.await?;
129+
130+
let mut url_array = jvm.instantiate_array("Ljava/net/URL;", urls.len()).await?;
131+
jvm.store_array(&mut url_array, 0, urls).await?;
132+
120133
let url_class_loader = jvm
121-
.new_class("java/net/URLClassLoader", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V", (url_array, None))
134+
.new_class(
135+
"java/net/URLClassLoader",
136+
"([Ljava/net/URL;Ljava/lang/ClassLoader;)V",
137+
(url_array, rustjar_class_loader),
138+
)
122139
.await?;
123140

124141
let class_loader_type: ClassInstanceRef<String> = jvm
@@ -183,7 +200,7 @@ impl ClassLoader {
183200
jvm.invoke_virtual(&parent, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;", (name.clone(),))
184201
.await?
185202
} else {
186-
None.into()
203+
jvm.load_bootstrap_class(&name_str).await?.into()
187204
};
188205

189206
if !class.is_null() {

‎java_runtime/src/classes/java/lang/thread.rs‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::time::Duration;
33

44
use java_class_proto::{JavaFieldProto, JavaMethodProto};
55
use java_constants::{FieldAccessFlags, MethodAccessFlags};
6-
use jvm::{ClassInstanceRef, Jvm, Result, runtime::JavaLangString};
6+
use jvm::{ClassInstanceRef, GlobalRef, Jvm, Result, runtime::JavaLangString};
77
use tracing::Instrument;
88

99
use crate::{
@@ -192,7 +192,7 @@ impl Thread {
192192
struct ThreadStartProxy {
193193
jvm: Jvm,
194194
thread_id: i32,
195-
this: ClassInstanceRef<Thread>,
195+
this: GlobalRef<Thread>,
196196
}
197197

198198
#[async_trait::async_trait]
@@ -231,7 +231,7 @@ impl Thread {
231231
}
232232
}
233233

234-
let mut this = self.this.clone();
234+
let mut this = (*self.this).clone();
235235
let cleanup = if let Err(error) = self.jvm.monitor_enter(&self.this).await {
236236
Err(error)
237237
} else {
@@ -261,12 +261,16 @@ impl Thread {
261261

262262
let id: i32 = jvm.invoke_virtual(&this, "hashCode", "()I", ()).await?;
263263

264+
let this = match jvm.new_global_ref(&this) {
265+
Some(this) => this,
266+
None => return Err(jvm.exception("java/lang/NullPointerException", "thread is null").await),
267+
};
264268
context.spawn(
265269
jvm,
266270
Box::new(ThreadStartProxy {
267271
jvm: jvm.clone(),
268272
thread_id: id,
269-
this: this.clone(),
273+
this,
270274
}),
271275
);
272276

‎java_runtime/src/classes/java/net/url_class_loader.rs‎

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use jvm::{
77
};
88

99
use crate::{
10-
RuntimeClassProto, RuntimeContext,
10+
FileType, RuntimeClassProto, RuntimeContext,
1111
classes::java::{
1212
lang::{Class, ClassLoader, String},
1313
net::{JarURLConnection, URL},
@@ -59,32 +59,14 @@ impl URLClassLoader {
5959

6060
async fn find_class(
6161
jvm: &Jvm,
62-
context: &mut RuntimeContext,
62+
_: &mut RuntimeContext,
6363
this: ClassInstanceRef<Self>,
6464
name: ClassInstanceRef<String>,
6565
) -> Result<ClassInstanceRef<Class>> {
6666
tracing::debug!("java.net.URLClassLoader::findClass({this:?}, {name:?})");
6767

6868
let name_str = JavaLangString::to_rust_string(jvm, &name).await?;
6969

70-
// find rustjar first
71-
let urls = jvm.get_field(&this, "urls", "[Ljava/net/URL;").await?;
72-
let urls: Vec<ClassInstanceRef<URL>> = jvm.load_array(&urls, 0, jvm.array_length(&urls).await? as _).await?;
73-
74-
for url in urls {
75-
let file = jvm.invoke_virtual(&url, "getFile", "()Ljava/lang/String;", ()).await?;
76-
let file = JavaLangString::to_rust_string(jvm, &file).await?;
77-
78-
if file.ends_with(".rustjar") {
79-
let class = context.find_rustjar_class(jvm, &file, &name_str).await?;
80-
if let Some(class) = class {
81-
let java_class = jvm.register_class(class, Some(this.into())).await?.unwrap();
82-
83-
return Ok(java_class.into());
84-
}
85-
}
86-
}
87-
8870
let resource_name = format!("{}.class", name_str.replace('.', "/"));
8971
let resource_name = JavaLangString::from_rust_string(jvm, &resource_name).await?;
9072

@@ -130,12 +112,16 @@ impl URLClassLoader {
130112
for url in urls {
131113
let file = jvm.invoke_virtual(&url, "getFile", "()Ljava/lang/String;", ()).await?;
132114
let file = JavaLangString::to_rust_string(jvm, &file).await?;
133-
if file.ends_with('/') || file.is_empty() {
115+
116+
let metadata = runtime.metadata(&file).await;
117+
if file.ends_with('/') || file.is_empty() || metadata.as_ref().is_ok_and(|metadata| metadata.r#type == FileType::Directory) {
134118
// directory
135-
let final_path = if file.ends_with('/') {
119+
let final_path = if file.is_empty() {
120+
name_str.clone()
121+
} else if file.ends_with('/') {
136122
format!("{file}{name_str}")
137123
} else {
138-
name_str.clone()
124+
format!("{file}/{name_str}")
139125
};
140126

141127
if runtime.metadata(&final_path).await.is_ok() {
@@ -153,8 +139,8 @@ impl URLClassLoader {
153139

154140
return Ok(new_url.into());
155141
}
156-
} else if file.ends_with(".rustjar") {
157-
// TODO rustjar resource
142+
} else if metadata.is_err() {
143+
continue;
158144
} else {
159145
// treat as jar
160146
let name_str = name_str.trim_start_matches('/');

‎java_runtime/src/classes/java/net/url_stream_handler.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,11 @@ impl URLStreamHandler {
9595

9696
let protocol = parsed_url.scheme();
9797
let path = parsed_url.path().to_owned() + &parsed_url.query().map(|x| "?".to_owned() + x).unwrap_or("".into());
98-
// TODO handle more elegantly..
99-
let file = if protocol == "file" { path.trim_start_matches('/') } else { &path };
98+
let file = if protocol == "file" && spec_str.strip_prefix("file:").is_some_and(|file| !file.starts_with('/')) {
99+
path.trim_start_matches('/')
100+
} else {
101+
&path
102+
};
100103

101104
let protocol = JavaLangString::from_rust_string(jvm, parsed_url.scheme()).await?;
102105
let host = JavaLangString::from_rust_string(jvm, parsed_url.host_str().unwrap_or("")).await?;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
mod date_format;
2+
mod decimal_format;
3+
mod field_position;
4+
mod format;
5+
mod number_format;
6+
mod parse_exception;
7+
mod parse_position;
8+
mod simple_date_format;
9+
10+
pub use self::{
11+
date_format::DateFormat, decimal_format::DecimalFormat, field_position::FieldPosition, format::Format, number_format::NumberFormat,
12+
parse_exception::ParseException, parse_position::ParsePosition, simple_date_format::SimpleDateFormat,
13+
};

0 commit comments

Comments
 (0)