| // Copyright 2012 The Rust Project Developers. See the COPYRIGHT |
| // file at the top-level directory of this distribution and at |
| // http://rust-lang.org/COPYRIGHT. |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| /* |
| 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. |
| */ |
| |
| #include "rust_globals.h" |
| #include "rust_util.h" |
| |
| //Unwinding ABI declarations. |
| typedef int _Unwind_Reason_Code; |
| typedef int _Unwind_Action; |
| |
| struct _Unwind_Context; |
| struct _Unwind_Exception; |
| |
| typedef void (*CDECL stack_switch_shim)(void*); |
| |
| /********************************************************************** |
| * Switches to the C-stack and invokes |fn_ptr|, passing |args| as argument. |
| * This is used by the C compiler to call foreign functions and by other |
| * upcalls to switch to the C stack. The return value is passed through a |
| * field in the args parameter. This upcall is specifically for switching |
| * to the shim functions generated by rustc. |
| */ |
| extern "C" CDECL void |
| upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { |
| stack_switch_shim f = (stack_switch_shim)fn_ptr; |
| f(args); |
| } |
| |
| /* |
| * 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) { |
| // There's no task. Call the function and hope for the best |
| stack_switch_shim f = (stack_switch_shim)fn_ptr; |
| f(args); |
| } |
| |
| /**********************************************************************/ |
| |
| #ifdef __SEH__ |
| # define PERSONALITY_FUNC __gxx_personality_seh0 |
| #else |
| # ifdef __USING_SJLJ_EXCEPTIONS__ |
| # define PERSONALITY_FUNC __gxx_personality_sjlj |
| # else |
| # define PERSONALITY_FUNC __gxx_personality_v0 |
| # endif |
| #endif |
| |
| extern "C" _Unwind_Reason_Code |
| PERSONALITY_FUNC(int version, |
| _Unwind_Action actions, |
| uint64_t exception_class, |
| _Unwind_Exception *ue_header, |
| _Unwind_Context *context); |
| |
| struct s_rust_personality_args { |
| _Unwind_Reason_Code retval; |
| int version; |
| _Unwind_Action actions; |
| uint64_t exception_class; |
| _Unwind_Exception *ue_header; |
| _Unwind_Context *context; |
| }; |
| |
| extern "C" void |
| upcall_s_rust_personality(s_rust_personality_args *args) { |
| args->retval = PERSONALITY_FUNC(args->version, |
| args->actions, |
| args->exception_class, |
| args->ue_header, |
| args->context); |
| } |
| |
| /** |
| 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}; |
| upcall_s_rust_personality(&args); |
| return args.retval; |
| } |
| |
| // NB: This needs to be blazing fast. Don't switch stacks |
| extern "C" CDECL void * |
| upcall_new_stack(size_t stk_sz, void *args_addr, size_t args_sz) { |
| assert(false && "newsched shouldn't be growing the stack"); |
| return NULL; |
| } |
| |
| // NB: This needs to be blazing fast. Don't switch stacks |
| extern "C" CDECL void |
| upcall_del_stack() { |
| assert(false && "newsched shouldn't be growing the 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() { |
| } |
| |
| // |
| // Local Variables: |
| // mode: C++ |
| // fill-column: 78; |
| // indent-tabs-mode: nil |
| // c-basic-offset: 4 |
| // buffer-file-coding-system: utf-8-unix |
| // End: |
| // |