fix: ref msg native fns should be instance methods

This commit is contained in:
Orion Kindel 2023-04-17 20:56:30 -05:00
parent 618133f5f1
commit 72285ad7a1
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
6 changed files with 155 additions and 128 deletions

View File

@ -1,2 +1,5 @@
mod uint;
pub use uint::{u16, u32, u64, u8};
mod ptr;
pub use ptr::Ptr;

View File

@ -0,0 +1,15 @@
use toad_jni::java::lang::{Long, Throwable};
use toad_jni::java::{self};
pub struct Ptr(java::lang::Object);
java::object_newtype!(Ptr);
impl java::Class for Ptr {
const PATH: &'static str = package!(dev.toad.ffi.Ptr);
}
impl Ptr {
pub fn addr(&self, e: &mut java::Env) -> Result<Long, Throwable> {
static ADDR: java::Method<Ptr, fn() -> Result<Long, Throwable>> = java::Method::new("addr");
ADDR.invoke(e, self)
}
}

View File

@ -1,11 +1,13 @@
use std::collections::BTreeMap;
use jni::objects::JClass;
use jni::objects::{JClass, JObject, JThrowable};
use jni::sys::jobject;
use toad::net::Addrd;
use toad_jni::java::lang::Throwable;
use toad_jni::java::net::InetSocketAddress;
use toad_jni::java::{self, Object};
use crate::dev::toad::ffi::Ptr;
use crate::dev::toad::msg::ref_::Opt;
use crate::dev::toad::msg::{Code, Id, Token, Type};
use crate::mem::{Shared, SharedMemoryRegion};
@ -23,6 +25,20 @@ impl Message {
CTOR.invoke(env, msg_addr)
}
pub fn ptr(&self, e: &mut java::Env) -> Ptr {
static PTR: java::Field<Message, Ptr> = java::Field::new("ptr");
PTR.get(e, self)
}
pub fn toad_ref(&self,
e: &mut java::Env)
-> Result<&'static Addrd<toad_msg::alloc::Message>, Throwable> {
self.ptr(e).addr(e).map(|addr| unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr.inner(e)).as_ref()
.unwrap()
})
}
pub fn to_toad(&self, env: &mut java::Env) -> Addrd<toad_msg::alloc::Message> {
let msg = toad_msg::alloc::Message { ty: self.ty(env),
ver: toad_msg::Version::default(),
@ -95,97 +111,131 @@ impl Message {
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_id<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
msg: JObject<'local>)
-> jobject {
let e = &mut env;
let msg = unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr).as_ref()
.unwrap()
};
Id::from_toad(e, msg.data().id).yield_to_java(e)
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.toad_ref(e)
.map(|msg| Id::from_toad(e, msg.data().id).yield_to_java(e))
.map_err(|err| {
let err = JThrowable::from(err.downcast(e).to_local(e));
e.throw(err).unwrap()
})
.unwrap_or(*JObject::null())
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_token<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
msg: JObject<'local>)
-> jobject {
let e = &mut env;
let msg = unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr).as_ref()
.unwrap()
};
Token::from_toad(e, msg.data().token).yield_to_java(e)
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.toad_ref(e)
.map(|msg| {
Token::from_toad(e, msg.data().token).yield_to_java(e)
})
.map_err(|err| {
let err = JThrowable::from(err.downcast(e).to_local(e));
e.throw(err).unwrap()
})
.unwrap_or(*JObject::null())
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_payload<'local>(mut env: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr).as_ref()
.unwrap()
};
env.byte_array_from_slice(&msg.data().payload.0)
.unwrap()
.as_raw()
pub extern "system" fn Java_dev_toad_msg_ref_Message_payloadBytes<'local>(mut env: java::Env<'local>,
msg: JObject<'local>)
-> jobject {
let e = &mut env;
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.toad_ref(e)
.map(|msg| {
e.byte_array_from_slice(&msg.data().payload.0)
.unwrap()
.as_raw()
})
.map_err(|err| {
let err = JThrowable::from(err.downcast(e).to_local(e));
e.throw(err).unwrap()
})
.unwrap_or(*JObject::null())
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_typ<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
-> jobject {
let msg = unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr).as_ref()
.unwrap()
};
Type::new(&mut e, msg.data().ty).yield_to_java(&mut e)
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_code<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
pub extern "system" fn Java_dev_toad_msg_ref_Message_type<'local>(mut env: java::Env<'local>,
msg: JObject<'local>)
-> jobject {
let msg = unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr).as_ref()
.unwrap()
};
Code::from_toad(&mut e, msg.data().code).yield_to_java(&mut e)
let e = &mut env;
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.toad_ref(e)
.map(|msg| {
Type::from_toad(e, msg.data().ty).yield_to_java(e)
})
.map_err(|err| {
let err = JThrowable::from(err.downcast(e).to_local(e));
e.throw(err).unwrap()
})
.unwrap_or(*JObject::null())
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_addr<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
pub extern "system" fn Java_dev_toad_msg_ref_Message_code<'local>(mut env: java::Env<'local>,
msg: JObject<'local>)
-> jobject {
let msg = unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr).as_ref()
.unwrap()
};
InetSocketAddress::from_no_std(&mut e, msg.addr()).yield_to_java(&mut e)
let e = &mut env;
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.toad_ref(e)
.map(|msg| {
Code::from_toad(e, msg.data().code).yield_to_java(e)
})
.map_err(|err| {
let err = JThrowable::from(err.downcast(e).to_local(e));
e.throw(err).unwrap()
})
.unwrap_or(*JObject::null())
}
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_opts<'local>(mut e: java::Env<'local>,
_: JClass<'local>,
addr: i64)
pub extern "system" fn Java_dev_toad_msg_ref_Message_addr<'local>(mut env: java::Env<'local>,
msg: JObject<'local>)
-> jobject {
let msg = unsafe {
Shared::deref::<Addrd<toad_msg::alloc::Message>>(addr).as_ref()
.unwrap()
};
let opts = &msg.data().opts;
let e = &mut env;
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.toad_ref(e)
.map(|msg| {
let addr = InetSocketAddress::from_no_std(e, msg.addr());
java::util::Optional::of(e, addr).yield_to_java(e)
})
.map_err(|err| {
let err = JThrowable::from(err.downcast(e).to_local(e));
e.throw(err).unwrap()
})
.unwrap_or(*JObject::null())
}
let refs = opts.into_iter()
.map(|(n, v)| Opt::new(&mut e, v as *const _ as i64, n.0.into()))
.collect::<Vec<_>>();
#[no_mangle]
pub extern "system" fn Java_dev_toad_msg_ref_Message_optionRefs<'local>(mut env: java::Env<'local>,
msg: JObject<'local>)
-> jobject {
let e = &mut env;
java::lang::Object::from_local(e, msg).upcast_to::<Message>(e)
.toad_ref(e)
.map(|msg| {
let opts = &msg.data().opts;
refs.yield_to_java(&mut e)
let refs =
opts.into_iter()
.map(|(n, v)| {
Opt::new(e, v as *const _ as i64, n.0.into())
})
.collect::<Vec<_>>();
refs.yield_to_java(e)
})
.map_err(|err| {
let err = JThrowable::from(err.downcast(e).to_local(e));
e.throw(err).unwrap()
})
.unwrap_or(*JObject::null())
}
#[cfg(test)]

View File

@ -8,7 +8,7 @@ impl java::Class for Type {
}
impl Type {
pub fn new(env: &mut java::Env, ty: toad_msg::Type) -> Self {
pub fn from_toad(env: &mut java::Env, ty: toad_msg::Type) -> Self {
static FROM_STRING: java::StaticMethod<Type, fn(String) -> Type> =
java::StaticMethod::new("fromString");

View File

@ -18,16 +18,14 @@ import java.util.Optional;
*/
public class Ptr {
private static volatile HashSet<Long> validAddresses = new HashSet<>();
protected final long addr;
private final String clazz;
private final String trace;
Long addr;
final String clazz;
final String trace;
/**
* Associate a class instance with a native pointer
*/
public static synchronized Ptr register(Class c, long addr) {
public static Ptr register(Class c, long addr) {
var trace = Thread.currentThread().getStackTrace();
var traceStr = Arrays
.asList(trace)
@ -36,7 +34,6 @@ public class Ptr {
.map(StackTraceElement::toString)
.reduce("", (s, tr) -> s == "" ? tr : s + "\n\t" + tr);
Ptr.validAddresses.add(addr);
return new Ptr(addr, c.toString(), traceStr);
}
@ -49,21 +46,21 @@ public class Ptr {
/**
* Invokes the cleaning action on the object associated with an address
*/
public synchronized void release() {
Ptr.validAddresses.remove(this.addr);
public void release() {
this.addr = null;
}
/**
* Throw `ExpiredError` if object has been leaked
* outside of its appropriate context.
*/
public synchronized void ensureValid() {
if (!Ptr.validAddresses.contains(this.addr)) {
public void ensureValid() {
if (this.addr == null) {
throw new ExpiredError(this);
}
}
public synchronized long addr() {
public Long addr() {
this.ensureValid();
return this.addr;
}

View File

@ -18,23 +18,21 @@ public final class Message implements dev.toad.msg.Message, AutoCloseable {
Ptr ptr;
Optional<InetSocketAddress> addr = Optional.empty();
public native Optional<InetSocketAddress> addr();
static native InetSocketAddress addr(long addr);
public native Id id();
static native Id id(long addr);
public native Token token();
static native Token token(long addr);
public native byte[] payloadBytes();
static native byte[] payload(long addr);
public native Code code();
static native Code code(long addr);
public native Type type();
static native Type typ(long addr);
public native dev.toad.msg.ref.Option[] optionRefs();
static native dev.toad.msg.ref.Option[] opts(long addr);
static native byte[] toBytes(long addr);
public native byte[] toBytes();
Message(long addr) {
this.ptr = Ptr.register(this.getClass(), addr);
@ -44,48 +42,12 @@ public final class Message implements dev.toad.msg.Message, AutoCloseable {
return new dev.toad.msg.owned.Message(this);
}
public Optional<InetSocketAddress> addr() {
if (this.addr.isEmpty()) {
this.addr = Optional.of(this.addr(this.ptr.addr()));
}
return this.addr;
}
public Id id() {
return this.id(this.ptr.addr());
}
public Token token() {
return this.token(this.ptr.addr());
}
public Code code() {
return this.code(this.ptr.addr());
}
public Type type() {
return this.typ(this.ptr.addr());
}
public dev.toad.msg.ref.Option[] optionRefs() {
return this.opts(this.ptr.addr());
}
public List<dev.toad.msg.Option> options() {
return Arrays.asList(this.opts(this.ptr.addr()));
}
public byte[] payloadBytes() {
return this.payload(this.ptr.addr());
return Arrays.asList(this.optionRefs());
}
public String payloadString() {
return new String(this.payload(this.ptr.addr()));
}
public byte[] toBytes() {
return this.toBytes(this.ptr.addr());
return new String(this.payloadBytes());
}
@Override