Skip to content

Commit

Permalink
Remove array reshaping functions, fix droparray (#129)
Browse files Browse the repository at this point in the history
  • Loading branch information
Taaitaaiger authored May 19, 2024
1 parent 38756ca commit 7c659c4
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 372 deletions.
13 changes: 0 additions & 13 deletions jl_sys/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,19 +580,6 @@ extern "C" {
dims: *mut crate::types::jl_value_t,
) -> *mut crate::types::jl_array_t;

#[cfg(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
))]
pub fn jl_reshape_array(
atype: *mut crate::types::jl_value_t,
data: *mut crate::types::jl_array_t,
dims: *mut crate::types::jl_value_t,
) -> *mut crate::types::jl_array_t;

pub fn jl_ptr_to_array_1d(
atype: *mut crate::types::jl_value_t,
data: *mut std::ffi::c_void,
Expand Down
138 changes: 0 additions & 138 deletions jlrs/src/data/managed/array/data/accessor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,13 @@ use std::{
sync::atomic::{AtomicPtr, Ordering},
};

#[julia_version(until = "1.10")]
use jl_sys::{jl_apply_array_type, jl_reshape_array};
use jl_sys::{
jl_array_del_end, jl_array_grow_end, jl_value_t, jlrs_array_typetagdata, jlrs_arrayref,
jlrs_arrayset,
};
use jlrs_macros::julia_version;

use super::copied::CopiedArray;
#[julia_version(until = "1.10")]
use crate::data::managed::array::{
dimensions::{ArrayDimensions, CompatibleIndices, RankedDims},
sized_dim_tuple, ArrayBaseData, ArrayBaseResult,
};
use crate::{
catch::{catch_exceptions, unwrap_exc},
data::{
Expand Down Expand Up @@ -106,137 +99,6 @@ pub trait Accessor<'scope, 'data, T, const N: isize> {
ValueRef::wrap(NonNull::new_unchecked(v)).root(target)
}
}

/// Create a new array with dimensions `D` that shares its data with `self`.
///
/// If the number of elements of `dims` is not equal to the number of elements
/// an exception is thrown, which is caught and returned.
#[julia_version(until = "1.10")]
fn reshape<'target, D, Tgt>(
&self,
target: Tgt,
dims: D,
) -> ArrayBaseResult<'target, 'data, Tgt, T, -1>
where
D: RankedDims,
Tgt: Target<'target>,
{
// todo: check size

target.with_local_scope::<_, _, 1>(|target, mut frame| unsafe {
let arr = self.array();
let elty_ptr = arr.element_type().unwrap(Private);

// Safety: The array type is rooted until the array has been constructed, all C API
// functions are called with valid data. If an exception is thrown it's caught.
let callback = || {
let array_type = jl_apply_array_type(elty_ptr, dims.rank());

let tuple = sized_dim_tuple(&mut frame, &dims);

jl_reshape_array(array_type, arr.unwrap(Private), tuple.unwrap(Private))
};

let res = match catch_exceptions(callback, unwrap_exc) {
Ok(array_ptr) => Ok(NonNull::new_unchecked(array_ptr)),
Err(e) => Err(e),
};

target.result_from_ptr(res, Private)
})
}

/// Create a new array with dimensions `D` that shares its data with `self` without checking
/// any invariants.
///
/// If the number of elements of `dims` is not equal to the number of elements
/// an exception is thrown which is not caught.
#[julia_version(until = "1.10")]
unsafe fn reshape_unchecked<'target, D, Tgt>(
&self,
target: Tgt,
dims: D,
) -> ArrayBaseData<'target, 'data, Tgt, T, -1>
where
D: RankedDims,
Tgt: Target<'target>,
{
target.with_local_scope::<_, _, 1>(|target, mut frame| {
let arr = self.array();
let elty_ptr = arr.element_type().unwrap(Private);
let array_type = jl_apply_array_type(elty_ptr, dims.rank());
let tuple = sized_dim_tuple(&mut frame, &dims);
let arr = jl_reshape_array(array_type, arr.unwrap(Private), tuple.unwrap(Private));

target.data_from_ptr(NonNull::new_unchecked(arr), Private)
})
}

/// See [`ArrayBase::reshape`]. The only difference is that the rank of the returned array is
/// set.
#[julia_version(until = "1.10")]
fn reshape_ranked<'target, D, Tgt, const M: isize>(
&self,
target: Tgt,
dims: D,
) -> JlrsResult<ArrayBaseResult<'target, 'data, Tgt, T, M>>
where
D: RankedDims,
Tgt: Target<'target>,
{
let _ = D::ASSERT_RANKED;
let _ = <(ArrayDimensions<'_, M>, D) as CompatibleIndices<_, _>>::ASSERT_COMPATIBLE;

// todo: check size

target.with_local_scope::<_, _, 1>(|target, mut frame| unsafe {
let arr = self.array();
let elty_ptr = arr.element_type().unwrap(Private);

// Safety: The array type is rooted until the array has been constructed, all C API
// functions are called with valid data. If an exception is thrown it's caught.
let callback = || {
let array_type = jl_apply_array_type(elty_ptr, dims.rank());

let tuple = sized_dim_tuple(&mut frame, &dims);

jl_reshape_array(array_type, arr.unwrap(Private), tuple.unwrap(Private))
};

let res = match catch_exceptions(callback, unwrap_exc) {
Ok(array_ptr) => Ok(NonNull::new_unchecked(array_ptr)),
Err(e) => Err(e),
};

Ok(target.result_from_ptr(res, Private))
})
}

/// See [`ArrayBase::reshape_unchecked`]. The only difference is that the rank of the returned
/// array is set.
#[julia_version(until = "1.10")]
unsafe fn reshape_ranked_unchecked<'target, D, Tgt, const M: isize>(
&self,
target: Tgt,
dims: D,
) -> ArrayBaseData<'target, 'data, Tgt, T, M>
where
D: RankedDims,
Tgt: Target<'target>,
{
let _ = D::ASSERT_RANKED;
let _ = <(ArrayDimensions<'_, M>, D) as CompatibleIndices<_, _>>::ASSERT_COMPATIBLE;

target.with_local_scope::<_, _, 1>(|target, mut frame| {
let arr = self.array();
let elty_ptr = arr.element_type().unwrap(Private);
let array_type = jl_apply_array_type(elty_ptr, dims.rank());
let tuple = sized_dim_tuple(&mut frame, &dims);
let arr = jl_reshape_array(array_type, arr.unwrap(Private), tuple.unwrap(Private));

target.data_from_ptr(NonNull::new_unchecked(arr), Private)
})
}
}

/// Functionality supported by all mutable accessors.
Expand Down
139 changes: 115 additions & 24 deletions jlrs/src/data/managed/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,19 @@ use jl_sys::{
};
use jlrs_macros::julia_version;

#[julia_version(until = "1.10")]
use self::dimensions::Dims;

#[julia_version(since = "1.11")]
use std::ptr::null_mut;

use self::{
data::accessor::{
BitsAccessor, BitsAccessorMut, BitsUnionAccessor, BitsUnionAccessorMut,
IndeterminateAccessor, IndeterminateAccessorMut, InlineAccessor, InlineAccessorMut,
ManagedAccessor, ManagedAccessorMut, ValueAccessor, ValueAccessorMut,
},
dimensions::{ArrayDimensions, Dims, DimsExt, DimsRankAssert, DimsRankCheck, RankedDims},
dimensions::{ArrayDimensions, DimsExt, DimsRankAssert, DimsRankCheck, RankedDims},
tracked::{TrackedArrayBase, TrackedArrayBaseMut},
};
use super::{
Expand Down Expand Up @@ -499,11 +505,24 @@ pub trait ConstructTypedArray<T: ConstructType, const N: isize> {
let array_type = Self::array_type(&target, &dims).as_value();
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);

jl_gc_add_ptr_finalizer(
get_tls(),
array.ptr().as_ptr().cast(),
droparray::<U> as *mut c_void,
);
#[cfg(not(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
)))]
let mem = jlrs_array_mem(array.ptr().as_ptr());
#[cfg(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
))]
let mem = array.ptr().as_ptr().cast();

jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);

array
};
Expand Down Expand Up @@ -541,12 +560,24 @@ pub trait ConstructTypedArray<T: ConstructType, const N: isize> {

let array_type = Self::array_type(&target, &dims).as_value();
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);

jl_gc_add_ptr_finalizer(
get_tls(),
array.ptr().as_ptr().cast(),
droparray::<U> as *mut c_void,
);
#[cfg(not(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
)))]
let mem = jlrs_array_mem(array.ptr().as_ptr());
#[cfg(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
))]
let mem = array.ptr().as_ptr().cast();

jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);

target.data_from_ptr(array.ptr(), Private)
}
Expand Down Expand Up @@ -1171,12 +1202,24 @@ impl<const N: isize> ArrayBase<'_, '_, Unknown, N> {
let array_type = jl_apply_array_type(ty.unwrap(Private), D::RANK as _);
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);

jl_gc_add_ptr_finalizer(
get_tls(),
array.ptr().as_ptr().cast(),
droparray::<U> as *mut c_void,
);
#[cfg(not(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
)))]
let mem = jlrs_array_mem(array.ptr().as_ptr());
#[cfg(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
))]
let mem = array.ptr().as_ptr().cast();

jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);

array
};
Expand Down Expand Up @@ -1217,12 +1260,24 @@ impl<const N: isize> ArrayBase<'_, '_, Unknown, N> {
let array_type = jl_apply_array_type(ty.unwrap(Private), D::RANK as _);
let array_type = Value::wrap_non_null(NonNull::new_unchecked(array_type), Private);
let array = dims.alloc_array_with_data(&target, array_type, data.as_mut_ptr() as _);

jl_gc_add_ptr_finalizer(
get_tls(),
array.ptr().as_ptr().cast(),
droparray::<U> as *mut c_void,
);
#[cfg(not(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
)))]
let mem = jlrs_array_mem(array.ptr().as_ptr());
#[cfg(any(
feature = "julia-1-6",
feature = "julia-1-7",
feature = "julia-1-8",
feature = "julia-1-9",
feature = "julia-1-10",
))]
let mem = array.ptr().as_ptr().cast();

jl_gc_add_ptr_finalizer(get_tls(), mem, droparray::<U> as *mut c_void);

target.data_from_ptr(array.ptr(), Private)
}
Expand Down Expand Up @@ -3149,6 +3204,7 @@ where

// Safety: must be used as a finalizer when moving array data from Rust to Julia
// to ensure it's freed correctly.
#[julia_version(until = "1.10")]
unsafe extern "C" fn droparray<T>(a: Array) {
let sz = a.dimensions().size();
let data_ptr = a.data_ptr().cast::<T>();
Expand All @@ -3157,6 +3213,21 @@ unsafe extern "C" fn droparray<T>(a: Array) {
std::mem::drop(data);
}

#[julia_version(since = "1.11")]
unsafe extern "C" fn droparray<T>(a: *mut c_void) {
#[repr(C)]
struct GenericMemory<T> {
length: usize,
ptr: *mut T,
}

let a = NonNull::new_unchecked(a as *mut GenericMemory<T>).as_mut();
let v = Vec::from_raw_parts(a.ptr as *mut T, a.length, a.length);
a.ptr = null_mut();
a.length = 0;
std::mem::drop(v);
}

// If LTO is not enabled accessing arrays is very slow, so we're going to optimize
// the common case a little.
#[julia_version(until = "1.10")]
Expand All @@ -3176,6 +3247,26 @@ const unsafe fn jlrs_array_dims_ptr(a: *mut jl_array_t) -> *mut usize {
(a as *mut u8).add(OFFSET) as *mut usize
}

#[julia_version(since = "1.11")]
#[inline]
const unsafe fn jlrs_array_mem(a: *mut jl_array_t) -> *mut jl_sys::types::jl_value_t {
#[repr(C)]
struct GenericMemoryRef {
ptr_or_offset: *mut std::ffi::c_void,
mem: *mut std::ffi::c_void,
}

#[repr(C)]
struct RawArray {
ref_inner: GenericMemoryRef,
}

NonNull::new_unchecked(a as *mut RawArray)
.as_ref()
.ref_inner
.mem as _
}

#[julia_version(since = "1.11")]
#[inline]
const unsafe fn jlrs_array_dims_ptr(a: *mut jl_array_t) -> *mut usize {
Expand Down
Loading

0 comments on commit 7c659c4

Please sign in to comment.