2011-12-07 17:54:35 -08:00
|
|
|
/*
|
|
|
|
Upcalls
|
|
|
|
|
|
|
|
These are runtime functions that the compiler knows about and generates
|
|
|
|
calls to. They are called on the Rust stack and, in most cases, immediately
|
|
|
|
switch to the C stack.
|
|
|
|
*/
|
|
|
|
|
2011-09-20 16:47:59 -07:00
|
|
|
#include "rust_cc.h"
|
2011-08-19 13:03:46 -07:00
|
|
|
#include "rust_gc.h"
|
2010-06-23 21:03:09 -07:00
|
|
|
#include "rust_internal.h"
|
2011-09-27 17:14:18 -07:00
|
|
|
#include "rust_scheduler.h"
|
2011-09-15 12:52:50 -07:00
|
|
|
#include "rust_unwind.h"
|
2011-06-15 22:04:31 -07:00
|
|
|
#include "rust_upcall.h"
|
2011-09-07 11:44:34 -07:00
|
|
|
#include <stdint.h>
|
2010-06-23 21:03:09 -07:00
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
#define SWITCH_STACK(A, F) upcall_call_shim_on_c_stack((void*)A, (void*)F)
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
extern "C" void record_sp(void *limit);
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
2011-12-02 19:04:35 -08:00
|
|
|
* Switches to the C-stack and invokes |fn_ptr|, passing |args| as argument.
|
2011-12-07 17:54:35 -08:00
|
|
|
* This is used by the C compiler to call native functions and by other
|
2011-12-15 11:06:48 -08:00
|
|
|
* upcalls to switch to the C stack. The return value is passed through a
|
|
|
|
* field in the args parameter.
|
2011-12-02 19:04:35 -08:00
|
|
|
*/
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
|
|
|
|
rust_task *task = rust_scheduler::get_task();
|
|
|
|
|
|
|
|
// FIXME (1226) - The shim functions generated by rustc contain the
|
|
|
|
// morestack prologue, so we need to let them know they have enough
|
|
|
|
// stack.
|
|
|
|
record_sp(0);
|
|
|
|
|
|
|
|
rust_scheduler *sched = task->sched;
|
|
|
|
try {
|
|
|
|
sched->c_context.call_shim_on_c_stack(args, fn_ptr);
|
|
|
|
} catch (...) {
|
|
|
|
task = rust_scheduler::get_task();
|
|
|
|
task->record_stack_limit();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
task = rust_scheduler::get_task();
|
|
|
|
task->record_stack_limit();
|
|
|
|
}
|
2010-06-23 21:03:09 -07:00
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_fail_args {
|
|
|
|
char const *expr;
|
|
|
|
char const *file;
|
|
|
|
size_t line;
|
|
|
|
};
|
|
|
|
|
2010-08-31 14:36:51 -07:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_fail(s_fail_args *args) {
|
2011-10-20 12:32:43 +02:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-12-02 19:04:35 -08:00
|
|
|
LOG_ERR(task, upcall, "upcall fail '%s', %s:%" PRIdPTR,
|
|
|
|
args->expr, args->file, args->line);
|
2011-08-10 12:57:53 -07:00
|
|
|
task->fail();
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_fail(char const *expr,
|
|
|
|
char const *file,
|
|
|
|
size_t line) {
|
|
|
|
s_fail_args args = {expr,file,line};
|
2011-12-11 13:38:56 -08:00
|
|
|
SWITCH_STACK(&args, upcall_s_fail);
|
2011-12-07 17:54:35 -08:00
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Allocate an object in the task-local heap.
|
|
|
|
*/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_malloc_args {
|
2011-12-07 15:32:21 -08:00
|
|
|
uintptr_t retval;
|
2011-12-02 19:04:35 -08:00
|
|
|
size_t nbytes;
|
|
|
|
type_desc *td;
|
|
|
|
};
|
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_malloc(s_malloc_args *args) {
|
2011-09-27 17:14:18 -07:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
2011-09-20 14:20:16 -07:00
|
|
|
"upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ")",
|
2011-12-02 19:04:35 -08:00
|
|
|
args->nbytes, args->td);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-08-19 13:03:46 -07:00
|
|
|
gc::maybe_gc(task);
|
2011-09-20 16:47:59 -07:00
|
|
|
cc::maybe_cc(task);
|
2011-08-19 13:03:46 -07:00
|
|
|
|
2011-07-18 12:02:26 -07:00
|
|
|
// TODO: Maybe use dladdr here to find a more useful name for the
|
|
|
|
// type_desc.
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
void *p = task->malloc(args->nbytes, "tdesc", args->td);
|
|
|
|
memset(p, '\0', args->nbytes);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
task->local_allocs[p] = args->td;
|
2011-09-23 11:42:20 -07:00
|
|
|
debug::maybe_track_origin(task, p);
|
2011-09-20 15:35:14 -07:00
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
2011-09-20 14:20:16 -07:00
|
|
|
"upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ") = 0x%" PRIxPTR,
|
2011-12-02 19:04:35 -08:00
|
|
|
args->nbytes, args->td, (uintptr_t)p);
|
2011-12-07 15:32:21 -08:00
|
|
|
args->retval = (uintptr_t) p;
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL uintptr_t
|
|
|
|
upcall_malloc(size_t nbytes, type_desc *td) {
|
|
|
|
s_malloc_args args = {0, nbytes, td};
|
|
|
|
SWITCH_STACK(&args, upcall_s_malloc);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Called whenever an object in the task-local heap is freed.
|
|
|
|
*/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_free_args {
|
|
|
|
void *ptr;
|
|
|
|
uintptr_t is_gc;
|
|
|
|
};
|
|
|
|
|
2010-06-23 21:03:09 -07:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_free(s_free_args *args) {
|
2011-10-20 11:42:40 +02:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-06-28 12:15:41 -07:00
|
|
|
rust_scheduler *sched = task->sched;
|
|
|
|
DLOG(sched, mem,
|
2010-09-29 17:22:07 -07:00
|
|
|
"upcall free(0x%" PRIxPTR ", is_gc=%" PRIdPTR ")",
|
2011-12-02 19:04:35 -08:00
|
|
|
(uintptr_t)args->ptr, args->is_gc);
|
2011-09-20 15:35:14 -07:00
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
task->local_allocs.erase(args->ptr);
|
|
|
|
debug::maybe_untrack_origin(task, args->ptr);
|
2011-09-23 11:42:20 -07:00
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
task->free(args->ptr, (bool) args->is_gc);
|
2010-06-28 18:53:16 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_free(void* ptr, uintptr_t is_gc) {
|
|
|
|
s_free_args args = {ptr, is_gc};
|
|
|
|
SWITCH_STACK(&args, upcall_s_free);
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Allocate an object in the exchange heap.
|
|
|
|
*/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_shared_malloc_args {
|
2011-12-07 15:32:21 -08:00
|
|
|
uintptr_t retval;
|
2011-12-02 19:04:35 -08:00
|
|
|
size_t nbytes;
|
|
|
|
type_desc *td;
|
|
|
|
};
|
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_shared_malloc(s_shared_malloc_args *args) {
|
2011-10-20 11:42:40 +02:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2011-07-05 22:55:41 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
|
|
|
LOG(task, mem,
|
2011-12-02 19:04:35 -08:00
|
|
|
"upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR ")",
|
|
|
|
args->nbytes, args->td);
|
|
|
|
void *p = task->kernel->malloc(args->nbytes, "shared malloc");
|
|
|
|
memset(p, '\0', args->nbytes);
|
2011-07-05 22:55:41 -07:00
|
|
|
LOG(task, mem,
|
2011-12-02 19:04:35 -08:00
|
|
|
"upcall shared_malloc(%" PRIdPTR ", 0x%" PRIxPTR
|
|
|
|
") = 0x%" PRIxPTR,
|
|
|
|
args->nbytes, args->td, (uintptr_t)p);
|
2011-12-07 15:32:21 -08:00
|
|
|
args->retval = (uintptr_t) p;
|
2011-07-05 22:55:41 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL uintptr_t
|
|
|
|
upcall_shared_malloc(size_t nbytes, type_desc *td) {
|
|
|
|
s_shared_malloc_args args = {0, nbytes, td};
|
|
|
|
SWITCH_STACK(&args, upcall_s_shared_malloc);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Called whenever an object in the exchange heap is freed.
|
|
|
|
*/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_shared_free_args {
|
|
|
|
void *ptr;
|
|
|
|
};
|
|
|
|
|
2011-07-05 22:55:41 -07:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_shared_free(s_shared_free_args *args) {
|
2011-10-20 11:42:40 +02:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2011-07-05 22:55:41 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-12 11:53:45 -07:00
|
|
|
|
2011-07-05 22:55:41 -07:00
|
|
|
rust_scheduler *sched = task->sched;
|
|
|
|
DLOG(sched, mem,
|
|
|
|
"upcall shared_free(0x%" PRIxPTR")",
|
2011-12-02 19:04:35 -08:00
|
|
|
(uintptr_t)args->ptr);
|
|
|
|
task->kernel->free(args->ptr);
|
2011-07-05 22:55:41 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_shared_free(void* ptr) {
|
|
|
|
s_shared_free_args args = {ptr};
|
|
|
|
SWITCH_STACK(&args, upcall_s_shared_free);
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Called to deep copy a type descriptor onto the exchange heap.
|
|
|
|
* Used when sending closures. It's possible that we should have
|
|
|
|
* a central hashtable to avoid copying and re-copying the same
|
|
|
|
* type descriptors.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct s_create_shared_type_desc_args {
|
2011-12-11 20:42:37 -08:00
|
|
|
const type_desc *td;
|
|
|
|
type_desc *res;
|
|
|
|
};
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
void upcall_s_create_shared_type_desc(s_create_shared_type_desc_args *args)
|
2011-12-11 20:42:37 -08:00
|
|
|
{
|
2011-12-13 16:53:10 -08:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
2011-12-11 20:42:37 -08:00
|
|
|
// Copy the main part of the type descriptor:
|
|
|
|
const type_desc *td = args->td;
|
2011-12-16 08:06:13 -08:00
|
|
|
int n_params = td->n_params;
|
|
|
|
size_t sz = sizeof(type_desc) + sizeof(type_desc*) * n_params;
|
2011-12-15 11:06:48 -08:00
|
|
|
args->res = (type_desc*) task->kernel->malloc(sz, "create_shared_type_desc");
|
2011-12-11 20:42:37 -08:00
|
|
|
memcpy(args->res, td, sizeof(type_desc));
|
|
|
|
|
|
|
|
// Recursively copy any referenced descriptors:
|
2011-12-16 08:06:13 -08:00
|
|
|
if (n_params == 0) {
|
2011-12-15 11:06:48 -08:00
|
|
|
args->res->first_param = NULL;
|
|
|
|
} else {
|
|
|
|
args->res->first_param = &args->res->descs[1];
|
|
|
|
args->res->descs[0] = args->res;
|
2011-12-16 08:06:13 -08:00
|
|
|
for (int i = 0; i < n_params; i++) {
|
|
|
|
s_create_shared_type_desc_args rec_args = {
|
|
|
|
td->first_param[i], 0
|
|
|
|
};
|
2011-12-15 11:06:48 -08:00
|
|
|
upcall_s_create_shared_type_desc(&rec_args);
|
2011-12-16 08:06:13 -08:00
|
|
|
args->res->first_param[i] = rec_args.res;
|
2011-12-15 11:06:48 -08:00
|
|
|
}
|
2011-12-11 20:42:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-13 21:43:55 -08:00
|
|
|
extern "C" CDECL type_desc *
|
2011-12-15 11:06:48 -08:00
|
|
|
upcall_create_shared_type_desc(type_desc *td) {
|
|
|
|
s_create_shared_type_desc_args args = { td, 0 };
|
|
|
|
SWITCH_STACK(&args, upcall_s_create_shared_type_desc);
|
2011-12-11 20:42:37 -08:00
|
|
|
return args.res;
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Called to deep free a type descriptor from the exchange heap.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void upcall_s_free_shared_type_desc(type_desc *td)
|
|
|
|
{
|
|
|
|
rust_task *task = rust_scheduler::get_task();
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
|
|
|
// Recursively free any referenced descriptors:
|
2011-12-16 08:06:13 -08:00
|
|
|
for (unsigned i = 0; i < td->n_params; i++) {
|
|
|
|
upcall_s_free_shared_type_desc((type_desc*) td->first_param[i]);
|
2011-12-15 11:06:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
task->kernel->free(td);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_free_shared_type_desc(type_desc *td) {
|
|
|
|
SWITCH_STACK(td, upcall_s_free_shared_type_desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* Called to intern a task-local type descriptor into the hashtable
|
|
|
|
* associated with each scheduler.
|
|
|
|
*/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_get_type_desc_args {
|
2011-12-07 15:32:21 -08:00
|
|
|
type_desc *retval;
|
2011-12-02 19:04:35 -08:00
|
|
|
size_t size;
|
|
|
|
size_t align;
|
|
|
|
size_t n_descs;
|
|
|
|
type_desc const **descs;
|
|
|
|
uintptr_t n_obj_params;
|
|
|
|
};
|
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_get_type_desc(s_get_type_desc_args *args) {
|
2011-10-20 11:42:40 +02:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, cache, "upcall get_type_desc with size=%" PRIdPTR
|
2011-12-02 19:04:35 -08:00
|
|
|
", align=%" PRIdPTR ", %" PRIdPTR " descs", args->size, args->align,
|
|
|
|
args->n_descs);
|
2011-05-26 18:20:48 -07:00
|
|
|
rust_crate_cache *cache = task->get_crate_cache();
|
2011-12-02 19:04:35 -08:00
|
|
|
type_desc *td = cache->get_type_desc(args->size, args->align, args->n_descs,
|
|
|
|
args->descs, args->n_obj_params);
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, cache, "returning tydesc 0x%" PRIxPTR, td);
|
2011-12-07 15:32:21 -08:00
|
|
|
args->retval = td;
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL type_desc *
|
|
|
|
upcall_get_type_desc(void *curr_crate, // ignored, legacy compat.
|
|
|
|
size_t size,
|
|
|
|
size_t align,
|
|
|
|
size_t n_descs,
|
|
|
|
type_desc const **descs,
|
|
|
|
uintptr_t n_obj_params) {
|
|
|
|
s_get_type_desc_args args = {0,size,align,n_descs,descs,n_obj_params};
|
|
|
|
SWITCH_STACK(&args, upcall_s_get_type_desc);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_vec_grow_args {
|
|
|
|
rust_vec** vp;
|
|
|
|
size_t new_sz;
|
|
|
|
};
|
|
|
|
|
2011-07-05 22:55:41 -07:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_vec_grow(s_vec_grow_args *args) {
|
2011-10-20 11:42:40 +02:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2011-07-05 22:55:41 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-12-02 19:04:35 -08:00
|
|
|
reserve_vec(task, args->vp, args->new_sz);
|
|
|
|
(*args->vp)->fill = args->new_sz;
|
2011-07-05 22:55:41 -07:00
|
|
|
}
|
2011-08-16 19:48:47 -07:00
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_vec_grow(rust_vec** vp, size_t new_sz) {
|
|
|
|
s_vec_grow_args args = {vp, new_sz};
|
|
|
|
SWITCH_STACK(&args, upcall_s_vec_grow);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy elements from one vector to another,
|
|
|
|
// dealing with reference counts
|
|
|
|
static inline void
|
|
|
|
copy_elements(rust_task *task, 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_vec_push_args {
|
|
|
|
rust_vec** vp;
|
|
|
|
type_desc* elt_ty;
|
|
|
|
void* elt;
|
|
|
|
};
|
|
|
|
|
2011-08-24 13:53:34 +02:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_vec_push(s_vec_push_args *args) {
|
2011-10-20 11:42:40 +02:00
|
|
|
rust_task *task = rust_scheduler::get_task();
|
2011-08-24 13:53:34 +02:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-12-02 19:04:35 -08:00
|
|
|
size_t new_sz = (*args->vp)->fill + args->elt_ty->size;
|
|
|
|
reserve_vec(task, args->vp, new_sz);
|
|
|
|
rust_vec* v = *args->vp;
|
|
|
|
copy_elements(task, args->elt_ty, &v->data[0] + v->fill,
|
|
|
|
args->elt, args->elt_ty->size);
|
|
|
|
v->fill += args->elt_ty->size;
|
2011-08-24 13:53:34 +02:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_vec_push(rust_vec** vp, type_desc* elt_ty, void* elt) {
|
|
|
|
// FIXME: Switching stacks here causes crashes, probably
|
|
|
|
// because this upcall calls take glue
|
|
|
|
s_vec_push_args args = {vp, elt_ty, elt};
|
|
|
|
upcall_s_vec_push(&args);
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Returns a token that can be used to deallocate all of the allocated space
|
|
|
|
* space in the dynamic stack.
|
|
|
|
*/
|
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
struct s_dynastack_mark_args {
|
|
|
|
void *retval;
|
|
|
|
};
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_s_dynastack_mark(s_dynastack_mark_args *args) {
|
|
|
|
args->retval = rust_scheduler::get_task()->dynastack.mark();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL void *
|
|
|
|
upcall_dynastack_mark() {
|
|
|
|
s_dynastack_mark_args args = {0};
|
|
|
|
SWITCH_STACK(&args, upcall_s_dynastack_mark);
|
|
|
|
return args.retval;
|
2011-08-16 19:48:47 -07:00
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Allocates space in the dynamic stack and returns it.
|
|
|
|
*
|
|
|
|
* FIXME: Deprecated since dynamic stacks need to be self-describing for GC.
|
|
|
|
*/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_dynastack_alloc_args {
|
2011-12-07 15:32:21 -08:00
|
|
|
void *retval;
|
2011-12-02 19:04:35 -08:00
|
|
|
size_t sz;
|
|
|
|
};
|
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_dynastack_alloc(s_dynastack_alloc_args *args) {
|
|
|
|
size_t sz = args->sz;
|
2011-12-07 15:32:21 -08:00
|
|
|
args->retval = sz ?
|
|
|
|
rust_scheduler::get_task()->dynastack.alloc(sz, NULL) : NULL;
|
2011-08-31 19:19:05 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void *
|
|
|
|
upcall_dynastack_alloc(size_t sz) {
|
|
|
|
s_dynastack_alloc_args args = {0, sz};
|
|
|
|
SWITCH_STACK(&args, upcall_s_dynastack_alloc);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Allocates space associated with a type descriptor in the dynamic stack and
|
|
|
|
* returns it.
|
|
|
|
*/
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_dynastack_alloc_2_args {
|
2011-12-07 15:32:21 -08:00
|
|
|
void *retval;
|
2011-12-02 19:04:35 -08:00
|
|
|
size_t sz;
|
|
|
|
type_desc *ty;
|
|
|
|
};
|
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_dynastack_alloc_2(s_dynastack_alloc_2_args *args) {
|
|
|
|
size_t sz = args->sz;
|
|
|
|
type_desc *ty = args->ty;
|
2011-12-07 15:32:21 -08:00
|
|
|
args->retval = sz ?
|
|
|
|
rust_scheduler::get_task()->dynastack.alloc(sz, ty) : NULL;
|
2011-08-16 19:48:47 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void *
|
|
|
|
upcall_dynastack_alloc_2(size_t sz, type_desc *ty) {
|
|
|
|
s_dynastack_alloc_2_args args = {0, sz, ty};
|
|
|
|
SWITCH_STACK(&args, upcall_s_dynastack_alloc_2);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_dynastack_free_args {
|
|
|
|
void *ptr;
|
|
|
|
};
|
|
|
|
|
2011-08-16 19:48:47 -07:00
|
|
|
extern "C" CDECL void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_dynastack_free(s_dynastack_free_args *args) {
|
|
|
|
return rust_scheduler::get_task()->dynastack.free(args->ptr);
|
2011-11-18 15:40:23 -08:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
/** Frees space in the dynamic stack. */
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_dynastack_free(void *ptr) {
|
|
|
|
s_dynastack_free_args args = {ptr};
|
|
|
|
SWITCH_STACK(&args, upcall_s_dynastack_free);
|
|
|
|
}
|
|
|
|
|
2011-09-07 11:44:34 -07:00
|
|
|
extern "C" _Unwind_Reason_Code
|
|
|
|
__gxx_personality_v0(int version,
|
|
|
|
_Unwind_Action actions,
|
|
|
|
uint64_t exception_class,
|
|
|
|
_Unwind_Exception *ue_header,
|
|
|
|
_Unwind_Context *context);
|
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
struct s_rust_personality_args {
|
2011-12-07 15:32:21 -08:00
|
|
|
_Unwind_Reason_Code retval;
|
2011-12-02 19:04:35 -08:00
|
|
|
int version;
|
|
|
|
_Unwind_Action actions;
|
|
|
|
uint64_t exception_class;
|
|
|
|
_Unwind_Exception *ue_header;
|
|
|
|
_Unwind_Context *context;
|
|
|
|
};
|
|
|
|
|
2011-12-07 15:32:21 -08:00
|
|
|
extern "C" void
|
2011-12-02 19:04:35 -08:00
|
|
|
upcall_s_rust_personality(s_rust_personality_args *args) {
|
2011-12-07 15:32:21 -08:00
|
|
|
args->retval = __gxx_personality_v0(args->version,
|
|
|
|
args->actions,
|
|
|
|
args->exception_class,
|
|
|
|
args->ue_header,
|
|
|
|
args->context);
|
2011-12-02 19:04:35 -08:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
/**
|
|
|
|
The exception handling personality function. It figures
|
|
|
|
out what to do with each landing pad. Just a stack-switching
|
|
|
|
wrapper around the C++ personality function.
|
|
|
|
*/
|
|
|
|
extern "C" _Unwind_Reason_Code
|
|
|
|
upcall_rust_personality(int version,
|
|
|
|
_Unwind_Action actions,
|
|
|
|
uint64_t exception_class,
|
|
|
|
_Unwind_Exception *ue_header,
|
|
|
|
_Unwind_Context *context) {
|
|
|
|
s_rust_personality_args args = {(_Unwind_Reason_Code)0,
|
|
|
|
version, actions, exception_class,
|
|
|
|
ue_header, context};
|
|
|
|
SWITCH_STACK(&args, upcall_s_rust_personality);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
2011-12-06 21:14:00 -08:00
|
|
|
extern "C" void
|
|
|
|
shape_cmp_type(int8_t *result, const type_desc *tydesc,
|
|
|
|
const type_desc **subtydescs, uint8_t *data_0,
|
|
|
|
uint8_t *data_1, uint8_t cmp_type);
|
|
|
|
|
|
|
|
struct s_cmp_type_args {
|
|
|
|
int8_t *result;
|
|
|
|
const type_desc *tydesc;
|
|
|
|
const type_desc **subtydescs;
|
|
|
|
uint8_t *data_0;
|
|
|
|
uint8_t *data_1;
|
|
|
|
uint8_t cmp_type;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern "C" void
|
|
|
|
upcall_s_cmp_type(s_cmp_type_args *args) {
|
|
|
|
shape_cmp_type(args->result, args->tydesc, args->subtydescs,
|
|
|
|
args->data_0, args->data_1, args->cmp_type);
|
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" void
|
|
|
|
upcall_cmp_type(int8_t *result, const type_desc *tydesc,
|
|
|
|
const type_desc **subtydescs, uint8_t *data_0,
|
|
|
|
uint8_t *data_1, uint8_t cmp_type) {
|
|
|
|
s_cmp_type_args args = {result, tydesc, subtydescs, data_0, data_1, cmp_type};
|
|
|
|
SWITCH_STACK(&args, upcall_s_cmp_type);
|
|
|
|
}
|
|
|
|
|
2011-12-06 21:14:00 -08:00
|
|
|
extern "C" void
|
|
|
|
shape_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level);
|
|
|
|
|
|
|
|
struct s_log_type_args {
|
|
|
|
const type_desc *tydesc;
|
|
|
|
uint8_t *data;
|
|
|
|
uint32_t level;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern "C" void
|
|
|
|
upcall_s_log_type(s_log_type_args *args) {
|
|
|
|
shape_log_type(args->tydesc, args->data, args->level);
|
|
|
|
}
|
|
|
|
|
2011-12-06 20:55:03 -08:00
|
|
|
extern "C" void
|
|
|
|
upcall_log_type(const type_desc *tydesc, uint8_t *data, uint32_t level) {
|
2011-12-06 21:14:00 -08:00
|
|
|
s_log_type_args args = {tydesc, data, level};
|
2011-12-07 15:32:21 -08:00
|
|
|
SWITCH_STACK(&args, upcall_s_log_type);
|
2011-12-06 20:55:03 -08:00
|
|
|
}
|
|
|
|
|
2011-12-06 21:19:59 -08:00
|
|
|
struct rust_new_stack2_args {
|
|
|
|
void *new_stack;
|
|
|
|
size_t stk_sz;
|
|
|
|
void *args_addr;
|
|
|
|
size_t args_sz;
|
|
|
|
};
|
|
|
|
|
|
|
|
// A new stack function suitable for calling through
|
|
|
|
// upcall_call_shim_on_c_stack
|
|
|
|
// FIXME: Convert this to the same arrangement as
|
|
|
|
// the other upcalls, simplify __morestack
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_new_stack(struct rust_new_stack2_args *args) {
|
|
|
|
rust_task *task = rust_scheduler::get_task();
|
|
|
|
args->new_stack = task->new_stack(args->stk_sz,
|
|
|
|
args->args_addr,
|
|
|
|
args->args_sz);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: As above
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_del_stack() {
|
|
|
|
rust_task *task = rust_scheduler::get_task();
|
|
|
|
task->del_stack();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Landing pads need to call this to insert the
|
|
|
|
// correct limit into TLS.
|
|
|
|
// NB: This must run on the Rust stack because it
|
|
|
|
// needs to acquire the value of the stack pointer
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_reset_stack_limit() {
|
|
|
|
rust_task *task = rust_scheduler::get_task();
|
|
|
|
task->reset_stack_limit();
|
|
|
|
}
|
|
|
|
|
2010-06-23 21:03:09 -07:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: C++
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|