swh:1:snp:a72e953ecd624a7df6e6196bbdd05851996c5e40
Raw File
Tip revision: 1c8ddb3248af1a21018abd316a98efdcf24e914e authored by Jacob Quinn on 16 July 2019, 21:33:13 UTC
Start work on builtin jl_buffer_t/Core.Buffer type
Tip revision: 1c8ddb3
buffer.c
// This file is a part of Julia. License is MIT: https://julialang.org/license

/*
  buffer constructors and primitives
*/
#include <stdlib.h>
#include <string.h>
#ifdef _OS_WINDOWS_
#include <malloc.h>
#endif
#include "julia.h"
#include "julia_internal.h"
#include "julia_assert.h"

#ifdef __cplusplus
extern "C"
{
#endif

char *jl_buffer_typetagdata(jl_buffer_t *b) JL_NOTSAFEPOINT
{
    // assert(jl_array_isbitsunion(a));
    return ((char*)jl_buffer_data(b)) + jl_buffer_len(b) * jl_buffer_elsize(b);
}

JL_DLLEXPORT int jl_isinlinealloc(jl_value_t *type) JL_NOTSAFEPOINT
{
    size_t fsz = 0, al = 0;
    return jl_islayout_inline(type, &fsz, &al);
}

JL_DLLEXPORT jl_buffer_t *jl_new_buffer(jl_value_t *btype, size_t length)
{
    //TODO: assert btype is a Buffer{T} datatype, length is reasonable
    jl_ptls_t ptls = jl_get_ptls_states();
    jl_value_t *eltype = jl_tparam0(btype);
    size_t tot = 0, elsize = 0, al = 0;
    int isinlinealloc = jl_islayout_inline(eltype, &elsize, &al);
    int isunion = jl_is_uniontype(eltype);
    void *data;
    jl_buffer_t *b;

    if (isinlinealloc) {
        size_t tot = (size_t)elsize * (size_t)length;
        if (isunion)
            tot += length;
        else if (elsize == 1)
            tot++;
    } else {
        tot = (size_t)sizeof(void *) * (size_t)length;
    }

    int tsz = LLT_ALIGN(sizeof(jl_buffer_t), JL_CACHE_BYTE_ALIGNMENT);
    if (tot <= ARRAY_INLINE_NBYTES) {
        if (isinlinealloc && elsize >= 4)
            tsz = LLT_ALIGN(tsz, JL_SMALL_BYTE_ALIGNMENT); // align data area
        size_t doffs = tsz;
        tsz += tot;
        tsz = LLT_ALIGN(tsz, JL_SMALL_BYTE_ALIGNMENT); // align whole object
        b = (jl_buffer_t *)jl_gc_alloc(ptls, tsz, btype);
        // No allocation or safepoint allowed after this
        b->flags.how = 0;
        data = (char *)b + doffs;
        if ((tot > 0 && !isinlinealloc) || isunion)
            memset(data, 0, tot);
    } else {
        tsz = LLT_ALIGN(tsz, JL_CACHE_BYTE_ALIGNMENT); // align whole object
        data = jl_gc_managed_malloc(tot);
        // Allocate the Array **after** allocating the data
        // to make sure the array is still young
        b = (jl_buffer_t *)jl_gc_alloc(ptls, tsz, btype);
        // No allocation or safepoint allowed after this
        b->flags.how = 2;
        jl_gc_track_malloced_buffer(ptls, b);
        if (!isinlinealloc || isunion)
            // need to zero out isbits union buffer selector bytes to ensure a valid type index
            memset(data, 0, tot);
    }

    b->data = data;
    b->length = length;
    b->flags.pooled = tsz <= GC_MAX_SZCLASS;
    b->flags.isshared = 0;
    b->flags.isaligned = 1;
    b->flags.isinlinealloc = isinlinealloc;
    return b;
}

// own_buffer != 0 iff GC should call free() on this pointer eventually
JL_DLLEXPORT jl_buffer_t *jl_ptr_to_buffer(jl_value_t *btype, void *data, size_t nel, int own_buffer)
{
    jl_ptls_t ptls = jl_get_ptls_states();
    jl_buffer_t *b;
    jl_value_t *eltype = jl_tparam0(btype);
    size_t elsize = 0, al = 0;
    int isinlinealloc = jl_islayout_inline(eltype, &elsize, &al);
    int isunion = jl_is_uniontype(eltype);

    if (isinlinealloc && isunion)
        jl_exceptionf(jl_argumenterror_type,
                      "unsafe_wrap: unspecified layout for union element type");
    if (((uintptr_t)data) & (al - 1))
        jl_exceptionf(jl_argumenterror_type,
                      "unsafe_wrap: pointer %p is not properly aligned to %u bytes", data, al);

    int tsz = LLT_ALIGN(sizeof(jl_buffer_t), JL_CACHE_BYTE_ALIGNMENT);
    b = (jl_buffer_t *)jl_gc_alloc(ptls, tsz, btype);
    // No allocation or safepoint allowed after this
    b->data = data;
    b->length = nel;
    b->flags.pooled = tsz <= GC_MAX_SZCLASS;
    b->flags.isshared = 1;
    b->flags.isaligned = 0; // TODO: allow passing memalign'd buffers
    b->flags.isinlinealloc = isinlinealloc;
    if (own_buffer) {
        b->flags.how = 2;
        jl_gc_track_malloced_buffer(ptls, b);
        jl_gc_count_allocd(nel * elsize + (elsize == 1 ? 1 : 0));
    } else {
        b->flags.how = 0;
    }

    return b;
}

JL_DLLEXPORT jl_value_t *jl_bufferref(jl_buffer_t *b, size_t i)
{
    assert(i < b->length);
    if (b->flags.isinlinealloc) {
        jl_value_t *eltype = (jl_value_t *)jl_tparam0(jl_typeof(b));
        if (jl_is_uniontype(eltype)) {
            // isbits union selector bytes are always stored directly after the last buffer element
            uint8_t sel = jl_buffer_typetagdata(b)[i];
            eltype = jl_nth_union_component(eltype, sel);
            if (jl_is_datatype_singleton((jl_datatype_t *)eltype))
                return ((jl_datatype_t *)eltype)->instance;
        }
        return jl_new_bits(eltype, &((char *)b->data)[i * jl_datatype_size(eltype)]);
    } else {
        jl_value_t *elt = ((jl_value_t **)b->data)[i];
        if (elt == NULL)
            jl_throw(jl_undefref_exception);
        return elt;
    }
}

JL_DLLEXPORT int jl_buffer_isassigned(jl_buffer_t *b, size_t i)
{
    if (b->flags.isinlinealloc)
        return ((jl_value_t **)jl_buffer_data(b))[i] != NULL;
    return 1;
}

JL_DLLEXPORT void jl_bufferset(jl_buffer_t *b JL_ROOTING_ARGUMENT, jl_value_t *rhs JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED, size_t i)
{
    assert(i < jl_array_len(b));
    jl_value_t *eltype = jl_tparam0(jl_typeof(b));
    if (eltype != (jl_value_t *)jl_any_type)
    {
        JL_GC_PUSH1(&rhs);
        if (!jl_isa(rhs, eltype))
            jl_type_error("bufferset", eltype, rhs);
        JL_GC_POP();
    }
    if (b->flags.isinlinealloc)
    {
        if (jl_is_uniontype(eltype))
        {
            uint8_t *psel = &((uint8_t *)jl_buffer_typetagdata(b))[i];
            unsigned nth = 0;
            if (!jl_find_union_component(eltype, jl_typeof(rhs), &nth))
                assert(0 && "invalid bufferset to isbits union");
            *psel = nth;
            if (jl_is_datatype_singleton((jl_datatype_t *)jl_typeof(rhs)))
                return;
        }
        jl_assign_bits(&((char *)b->data)[i * jl_buffer_elsize(b)], rhs);
    }
    else
    {
        ((jl_value_t **)b->data)[i] = rhs;
        //TODO: do we need to store owner pointer for buffer?
        jl_gc_wb(b, rhs);
    }
}

JL_DLLEXPORT void jl_bufferunset(jl_buffer_t *b, size_t i)
{
    if (i >= jl_buffer_len(b))
        jl_bounds_error_int((jl_value_t *)b, i + 1);
    if (!b->flags.isinlinealloc)
        ((jl_value_t **)b->data)[i] = NULL;
}
back to top