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.
|
|
|
|
*/
|
|
|
|
|
2012-04-02 22:18:01 -05:00
|
|
|
#include "rust_globals.h"
|
|
|
|
#include "rust_task.h"
|
2011-09-20 16:47:59 -07:00
|
|
|
#include "rust_cc.h"
|
2012-03-29 16:31:30 -07:00
|
|
|
#include "rust_sched_loop.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"
|
2012-01-06 12:06:35 -08:00
|
|
|
#include "rust_util.h"
|
2010-06-23 21:03:09 -07:00
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
#ifdef __GNUC__
|
|
|
|
#define LOG_UPCALL_ENTRY(task) \
|
|
|
|
LOG(task, upcall, \
|
|
|
|
"> UPCALL %s - task: %s 0x%" PRIxPTR \
|
|
|
|
" retpc: x%" PRIxPTR, \
|
|
|
|
__FUNCTION__, \
|
|
|
|
(task)->name, (task), \
|
|
|
|
__builtin_return_address(0));
|
|
|
|
#else
|
|
|
|
#define LOG_UPCALL_ENTRY(task) \
|
|
|
|
LOG(task, upcall, "> UPCALL task: %s @x%" PRIxPTR, \
|
|
|
|
(task)->name, (task));
|
|
|
|
#endif
|
|
|
|
|
2011-12-15 00:24:35 -08:00
|
|
|
// This is called to ensure we've set up our rust stacks
|
|
|
|
// correctly. Strategically placed at entry to upcalls because they begin on
|
|
|
|
// the rust stack and happen frequently enough to catch most stack changes,
|
|
|
|
// including at the beginning of all landing pads.
|
2011-12-17 13:49:02 -08:00
|
|
|
// FIXME: Enable this for windows
|
2012-03-28 13:49:39 -07:00
|
|
|
#if (defined __linux__ || defined __APPLE__ || defined __FreeBSD__) \
|
|
|
|
&& (defined(GCC_VERSION) && GCC_VERSION > 40300)
|
2011-12-15 00:24:35 -08:00
|
|
|
extern "C" void
|
|
|
|
check_stack_alignment() __attribute__ ((aligned (16)));
|
2011-12-16 12:09:34 -08:00
|
|
|
#else
|
|
|
|
static void check_stack_alignment() { }
|
|
|
|
#endif
|
2011-12-15 00:24:35 -08:00
|
|
|
|
2011-12-18 16:17:52 -08:00
|
|
|
#define UPCALL_SWITCH_STACK(A, F) call_upcall_on_c_stack((void*)A, (void*)F)
|
|
|
|
|
|
|
|
inline void
|
|
|
|
call_upcall_on_c_stack(void *args, void *fn_ptr) {
|
2011-12-20 16:50:54 -08:00
|
|
|
check_stack_alignment();
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2012-02-08 21:42:04 -08:00
|
|
|
task->call_on_c_stack(args, fn_ptr);
|
2011-12-18 16:17:52 -08:00
|
|
|
}
|
2011-12-07 15:32:21 -08:00
|
|
|
|
2012-03-21 14:12:12 -07:00
|
|
|
extern "C" void record_sp_limit(void *limit);
|
2011-12-02 19:04:35 -08:00
|
|
|
|
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
|
2011-12-18 16:17:52 -08:00
|
|
|
* field in the args parameter. This upcall is specifically for switching
|
|
|
|
* to the shim functions generated by rustc.
|
2011-12-02 19:04:35 -08:00
|
|
|
*/
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2011-12-02 19:04:35 -08:00
|
|
|
|
|
|
|
// FIXME (1226) - The shim functions generated by rustc contain the
|
|
|
|
// morestack prologue, so we need to let them know they have enough
|
|
|
|
// stack.
|
2012-03-21 14:12:12 -07:00
|
|
|
record_sp_limit(0);
|
2011-12-02 19:04:35 -08:00
|
|
|
|
|
|
|
try {
|
2012-02-08 21:42:04 -08:00
|
|
|
task->call_on_c_stack(args, fn_ptr);
|
2011-12-02 19:04:35 -08:00
|
|
|
} catch (...) {
|
2012-02-09 11:51:34 -08:00
|
|
|
LOG_ERR(task, task, "Native code threw an exception");
|
|
|
|
abort();
|
2011-12-02 19:04:35 -08:00
|
|
|
}
|
2011-12-18 16:17:52 -08:00
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
task->record_stack_limit();
|
|
|
|
}
|
2010-06-23 21:03:09 -07:00
|
|
|
|
2012-02-09 11:51:34 -08:00
|
|
|
/*
|
|
|
|
* The opposite of above. Starts on a C stack and switches to the Rust
|
|
|
|
* stack. This is the only upcall that runs from the C stack.
|
|
|
|
*/
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2012-02-09 11:51:34 -08:00
|
|
|
|
|
|
|
// FIXME: Because of the hack in the other function that disables the
|
|
|
|
// stack limit when entering the C stack, here we restore the stack limit
|
|
|
|
// again.
|
|
|
|
task->record_stack_limit();
|
|
|
|
|
|
|
|
try {
|
|
|
|
task->call_on_rust_stack(args, fn_ptr);
|
|
|
|
} catch (...) {
|
|
|
|
// We can't count on being able to unwind through arbitrary
|
|
|
|
// code. Our best option is to just fail hard.
|
|
|
|
LOG_ERR(task, task,
|
|
|
|
"Rust task failed after reentering the Rust stack");
|
|
|
|
abort();
|
|
|
|
}
|
2012-02-28 16:57:22 -08:00
|
|
|
|
|
|
|
// FIXME: As above
|
2012-03-21 14:12:12 -07:00
|
|
|
record_sp_limit(0);
|
2012-02-09 11:51:34 -08: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) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2012-03-31 23:12:06 -07:00
|
|
|
LOG_ERR(task, upcall, "upcall fail '%s', %s:%" PRIdPTR,
|
2011-12-02 19:04:35 -08:00
|
|
|
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) {
|
2011-12-18 16:59:49 -08:00
|
|
|
s_fail_args args = {expr,file,line};
|
|
|
|
UPCALL_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
|
|
|
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) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
LOG(task, mem, "upcall malloc(0x%" PRIxPTR ")", args->td);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2011-09-20 16:47:59 -07:00
|
|
|
cc::maybe_cc(task);
|
2011-08-19 13:03:46 -07:00
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
// FIXME--does this have to be calloc?
|
|
|
|
rust_opaque_box *box = task->boxed.calloc(args->td);
|
|
|
|
void *body = box_body(box);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
debug::maybe_track_origin(task, box);
|
2011-09-20 15:35:14 -07:00
|
|
|
|
2011-04-19 12:21:57 +02:00
|
|
|
LOG(task, mem,
|
2012-02-01 18:52:08 -08:00
|
|
|
"upcall malloc(0x%" PRIxPTR ") = box 0x%" PRIxPTR
|
|
|
|
" with body 0x%" PRIxPTR,
|
|
|
|
args->td, (uintptr_t)box, (uintptr_t)body);
|
|
|
|
args->retval = (uintptr_t) box;
|
2010-06-23 21:03:09 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL uintptr_t
|
2012-02-01 18:52:08 -08:00
|
|
|
upcall_malloc(type_desc *td) {
|
|
|
|
s_malloc_args args = {0, td};
|
2011-12-18 16:17:52 -08:00
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_malloc);
|
2011-12-07 17:54:35 -08:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
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) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2010-06-23 21:03:09 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-06 12:48:43 -07:00
|
|
|
|
2012-03-29 16:31:30 -07:00
|
|
|
rust_sched_loop *sched_loop = task->sched_loop;
|
|
|
|
DLOG(sched_loop, mem,
|
2010-09-29 17:22:07 -07:00
|
|
|
"upcall free(0x%" PRIxPTR ", is_gc=%" PRIdPTR ")",
|
2012-02-03 09:34:42 +01:00
|
|
|
(uintptr_t)args->ptr);
|
2011-09-20 15:35:14 -07:00
|
|
|
|
2011-12-02 19:04:35 -08:00
|
|
|
debug::maybe_untrack_origin(task, args->ptr);
|
2011-09-23 11:42:20 -07:00
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
rust_opaque_box *box = (rust_opaque_box*) args->ptr;
|
|
|
|
task->boxed.free(box);
|
2010-06-28 18:53:16 -07:00
|
|
|
}
|
|
|
|
|
2011-12-07 17:54:35 -08:00
|
|
|
extern "C" CDECL void
|
2012-02-03 09:34:42 +01:00
|
|
|
upcall_free(void* ptr) {
|
|
|
|
s_free_args args = {ptr};
|
2011-12-18 16:17:52 -08:00
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_free);
|
2011-12-07 17:54:35 -08:00
|
|
|
}
|
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
/**********************************************************************
|
|
|
|
* Sanity checks on boxes, insert when debugging possible
|
|
|
|
* use-after-free bugs. See maybe_validate_box() in trans.rs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_validate_box(rust_opaque_box* ptr) {
|
|
|
|
if (ptr) {
|
|
|
|
assert(ptr->ref_count > 0);
|
|
|
|
assert(ptr->td != NULL);
|
|
|
|
assert(ptr->td->align <= 8);
|
|
|
|
assert(ptr->td->size <= 4096); // might not really be true...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
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) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2011-07-05 22:55:41 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
|
2012-02-21 15:01:19 +01:00
|
|
|
LOG(task, mem, "upcall shared_malloc(%" PRIdPTR ")", args->nbytes);
|
2011-12-02 19:04:35 -08:00
|
|
|
void *p = task->kernel->malloc(args->nbytes, "shared malloc");
|
|
|
|
memset(p, '\0', args->nbytes);
|
2012-02-21 15:01:19 +01:00
|
|
|
LOG(task, mem, "upcall shared_malloc(%" PRIdPTR ") = 0x%" PRIxPTR,
|
|
|
|
args->nbytes, (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
|
2012-02-21 15:01:19 +01:00
|
|
|
upcall_shared_malloc(size_t nbytes) {
|
|
|
|
s_shared_malloc_args args = {0, nbytes};
|
2011-12-18 16:17:52 -08:00
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_shared_malloc);
|
2011-12-07 17:54:35 -08:00
|
|
|
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) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2011-07-05 22:55:41 -07:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
2011-07-12 11:53:45 -07:00
|
|
|
|
2012-03-29 16:31:30 -07:00
|
|
|
rust_sched_loop *sched_loop = task->sched_loop;
|
|
|
|
DLOG(sched_loop, mem,
|
2011-07-05 22:55:41 -07:00
|
|
|
"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};
|
2011-12-18 16:17:52 -08:00
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_shared_free);
|
2011-12-07 17:54:35 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 12:08:03 -08:00
|
|
|
struct s_shared_realloc_args {
|
|
|
|
void *retval;
|
|
|
|
void *ptr;
|
|
|
|
size_t size;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_s_shared_realloc(s_shared_realloc_args *args) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2012-02-17 12:08:03 -08:00
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
args->retval = task->kernel->realloc(args->ptr, args->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL void *
|
|
|
|
upcall_shared_realloc(void *ptr, size_t size) {
|
|
|
|
s_shared_realloc_args args = {NULL, ptr, size};
|
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_shared_realloc);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
2011-12-15 11:06:48 -08:00
|
|
|
/**********************************************************************/
|
|
|
|
|
2012-04-02 17:37:59 -07:00
|
|
|
struct s_str_new_args {
|
|
|
|
const char *cstr;
|
|
|
|
size_t len;
|
|
|
|
rust_str *retval;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_s_str_new(s_str_new_args *args) {
|
|
|
|
rust_task *task = rust_get_current_task();
|
|
|
|
LOG_UPCALL_ENTRY(task);
|
|
|
|
args->retval = make_str(task->kernel, args->cstr, args->len, "str_new");
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL rust_str*
|
|
|
|
upcall_str_new(const char *cstr, size_t len) {
|
|
|
|
s_str_new_args args = { cstr, len, 0 };
|
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_str_new);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_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};
|
2011-12-18 16:17:52 -08:00
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_vec_grow);
|
2011-12-07 17:54:35 -08:00
|
|
|
}
|
|
|
|
|
2012-03-19 14:06:59 -07:00
|
|
|
struct s_str_concat_args {
|
|
|
|
rust_vec* lhs;
|
|
|
|
rust_vec* rhs;
|
|
|
|
rust_vec* retval;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern "C" CDECL void
|
|
|
|
upcall_s_str_concat(s_str_concat_args *args) {
|
|
|
|
rust_vec *lhs = args->lhs;
|
|
|
|
rust_vec *rhs = args->rhs;
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2012-03-19 14:06:59 -07:00
|
|
|
size_t fill = lhs->fill + rhs->fill - 1;
|
|
|
|
rust_vec* v = (rust_vec*)task->kernel->malloc(fill + sizeof(rust_vec),
|
|
|
|
"str_concat");
|
|
|
|
v->fill = v->alloc = fill;
|
|
|
|
memmove(&v->data[0], &lhs->data[0], lhs->fill - 1);
|
|
|
|
memmove(&v->data[lhs->fill - 1], &rhs->data[0], rhs->fill);
|
|
|
|
args->retval = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" CDECL rust_vec*
|
|
|
|
upcall_str_concat(rust_vec* lhs, rust_vec* rhs) {
|
|
|
|
s_str_concat_args args = {lhs, rhs, 0};
|
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_str_concat);
|
|
|
|
return args.retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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};
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2011-12-18 16:59:49 -08:00
|
|
|
|
|
|
|
// The personality function is run on the stack of the
|
|
|
|
// last function that threw or landed, which is going
|
|
|
|
// to sometimes be the C stack. If we're on the Rust stack
|
|
|
|
// then switch to the C stack.
|
|
|
|
|
|
|
|
if (task->on_rust_stack()) {
|
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_rust_personality);
|
|
|
|
} else {
|
|
|
|
upcall_s_rust_personality(&args);
|
|
|
|
}
|
2011-12-07 17:54:35 -08:00
|
|
|
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) {
|
2012-03-31 23:12:06 -07:00
|
|
|
s_cmp_type_args args = {result, tydesc, subtydescs,
|
|
|
|
data_0, data_1, cmp_type};
|
2011-12-18 16:17:52 -08:00
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_cmp_type);
|
2011-12-07 17:54:35 -08:00
|
|
|
}
|
|
|
|
|
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-18 16:17:52 -08:00
|
|
|
UPCALL_SWITCH_STACK(&args, upcall_s_log_type);
|
2011-12-06 20:55:03 -08:00
|
|
|
}
|
|
|
|
|
2012-03-21 13:17:24 -07:00
|
|
|
// NB: This needs to be blazing fast. Don't switch stacks
|
2011-12-19 15:58:03 -08:00
|
|
|
extern "C" CDECL void *
|
|
|
|
upcall_new_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2012-03-21 13:17:24 -07:00
|
|
|
return task->next_stack(stk_sz,
|
|
|
|
args_addr,
|
|
|
|
args_sz);
|
2011-12-06 21:19:59 -08:00
|
|
|
}
|
|
|
|
|
2012-03-21 00:31:40 -07:00
|
|
|
// NB: This needs to be blazing fast. Don't switch stacks
|
2011-12-06 21:19:59 -08:00
|
|
|
extern "C" CDECL void
|
2012-03-21 00:31:40 -07:00
|
|
|
upcall_del_stack() {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2012-02-08 18:04:14 -08:00
|
|
|
task->prev_stack();
|
2011-12-06 21:19:59 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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() {
|
2012-04-02 00:13:39 -05:00
|
|
|
rust_task *task = rust_get_current_task();
|
2011-12-06 21:19:59 -08:00
|
|
|
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:
|
|
|
|
//
|