intrinsics.cpp 4.6 KB
Newer Older
M
Marijn Haverbeke 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
// Rust intrinsics. These are built into each compilation unit and are
// run on the Rust stack. They should not call C methods because that
// will very likely result in running off the end of the stack.
// Build with the script in src/etc/gen-intrinsics

#include "../rust_internal.h"
#include "../rust_util.h"
#include <cstdlib>
#include <cstring>

extern "C" CDECL void
rust_task_yield(rust_task *task, bool *killed);

extern "C" void
rust_intrinsic_vec_len(size_t *retptr,
                         void *env,
                         type_desc *ty,
                         rust_vec **vp)
{
    *retptr = (*vp)->fill / ty->size;
}

extern "C" void
rust_intrinsic_ptr_offset(void **retptr,
                          void *env,
                          type_desc *ty,
                          void *ptr,
                          uintptr_t count)
{
    *retptr = &((uint8_t *)ptr)[ty->size * count];
}

extern "C" void
rust_intrinsic_cast(void *retptr,
                    void *env,
                    type_desc *t1,
                    type_desc *t2,
                    void *src)
{
    // assert t1->size == t2->size
    // FIXME: This should be easily expressible in rust
    memmove(retptr, src, t1->size);
}

extern "C" void
rust_intrinsic_addr_of(void **retptr,
                       void *env,
                       type_desc *ty,
                       void *valptr) {
    *retptr = valptr;
}

struct rust_fn {
    uintptr_t *fn;
    rust_box *env;
};

typedef void (*retptr_fn)(void **retptr,
			   void *env,
			   void **dptr);
// FIXME (1185): This exists just to get access to the return pointer
extern "C" void
rust_intrinsic_call_with_retptr(void **retptr,
				void *env,
				type_desc *ty,
				rust_fn *recvfn) {
    retptr_fn fn = ((retptr_fn)(recvfn->fn));
    ((retptr_fn)(*fn))(NULL, recvfn->env, retptr);
}

extern "C" void
rust_intrinsic_get_type_desc(void **retptr,
                             void *env,
                             type_desc* ty) {
    *(type_desc**)retptr = ty;
}

extern "C" void
rust_intrinsic_task_yield(void **retptr,
                          void *env,
			  rust_task *task,
			  bool *killed) {
    rust_task_yield(task, killed);
}

extern "C" void
rust_intrinsic_memmove(void *retptr,
                    void *env,
                    type_desc *ty,
                    void *dst,
                    void *src,
                    uintptr_t count)
{
    memmove(dst, src, ty->size * count);
}

extern "C" void
rust_intrinsic_memcpy(void *retptr,
                    void *env,
                    type_desc *ty,
                    void *dst,
                    void *src,
                    uintptr_t count)
{
    memcpy(dst, src, ty->size * count);
}

extern "C" void
rust_intrinsic_leak(void *retptr,
                    void *env,
                    type_desc *ty,
                    void *thing)
{
}

extern "C" CDECL void *
upcall_shared_realloc(void *ptr, size_t size);

inline void reserve_vec_fast(rust_vec **vpp, size_t size) {
    if (size > (*vpp)->alloc) {
      size_t new_size = next_power_of_two(size);
        size_t alloc_size = new_size + sizeof(rust_vec);
        // Because this is called from an intrinsic we need to use
        // the exported API
        *vpp = (rust_vec*)upcall_shared_realloc(*vpp, alloc_size);
        (*vpp)->alloc = new_size;
    }
}

// Copy elements from one vector to another,
// dealing with reference counts
static inline void
copy_elements(type_desc *elem_t,
              void *pdst, void *psrc, size_t n) {
    char *dst = (char *)pdst, *src = (char *)psrc;
    memmove(dst, src, n);

    // increment the refcount of each element of the vector
    if (elem_t->take_glue) {
        glue_fn *take_glue = elem_t->take_glue;
        size_t elem_size = elem_t->size;
        const type_desc **tydescs = elem_t->first_param;
        for (char *p = dst; p < dst+n; p += elem_size) {
            take_glue(NULL, NULL, tydescs, p);
        }
    }
}

// Because this is used so often, and it calls take glue that must run
// on the rust stack, it is statically compiled into every crate.
extern "C" CDECL void
upcall_intrinsic_vec_push(rust_vec** vp,
			  type_desc* elt_ty, void* elt) {

    size_t new_sz = (*vp)->fill + elt_ty->size;
    reserve_vec_fast(vp, new_sz);
    rust_vec* v = *vp;
    copy_elements(elt_ty, &v->data[0] + v->fill,
                  elt, elt_ty->size);
    v->fill += elt_ty->size;
}

// FIXME: Transational. Remove
extern "C" CDECL void
upcall_vec_push(rust_vec** vp,
		type_desc* elt_ty, void* elt) {
  upcall_intrinsic_vec_push(vp, elt_ty, elt);
}

extern "C" CDECL void
rust_intrinsic_frame_address(void **p, unsigned n) {
    *p = __builtin_frame_address(n);
}