fix arm bug of smart_call
This commit is contained in:
40
deps/oblib/src/common/ob_smart_call.cpp
vendored
40
deps/oblib/src/common/ob_smart_call.cpp
vendored
@ -17,6 +17,46 @@ namespace oceanbase
|
||||
namespace common
|
||||
{
|
||||
|
||||
|
||||
#if defined(__x86_64__)
|
||||
OB_NOINLINE int jump_call(void * arg_, int(*func_) (void*), void* stack_addr)
|
||||
{
|
||||
int ret = 0;
|
||||
__asm__ __volatile__ (
|
||||
"leaq -0x10(%3), %3\n\t" /* reserve space for old RSP on new stack, 0x10 for align */
|
||||
"movq %%rsp, (%3)\n\t" /* store RSP in new stack */
|
||||
"movq %3, %%rsp\n\t" /* jump to new stack */
|
||||
"call *%2\n\t" /* run the second arg func_ */
|
||||
"popq %%rsp\n\t" /* jump back to old stack */
|
||||
:"=a" (ret) /* specify rax assigned to ret */
|
||||
:"D"(arg_), "r"(func_), "r"(stack_addr) /* specify rdi assigned to arg_ */
|
||||
:"memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
OB_NOINLINE int jump_call(void * arg_, int(*func_) (void*), void* stack_addr)
|
||||
{
|
||||
register int64_t ret __asm__("x0") = 0; /* specify x0 assigned to ret */
|
||||
register void* x0 __asm__("x0") = arg_; /* specify x0 assigned to arg_ */
|
||||
__asm__ __volatile__ (
|
||||
"sub %3, %3, #0x20\n\t" /* reserve space for old sp on new stack, 0x10 for align */
|
||||
"stp x29, x30, [%3, #0x10]\n\t" /* x29, x30 may not be stored in the innest function. */
|
||||
"mov x9, sp\n\t" /* transit SP by x9 */
|
||||
"str x9, [%3, #0x00]\n\t" /* store SP in new stack */
|
||||
"mov sp, %3\n\t" /* jump SP to new stack */
|
||||
"blr %2\n\t" /* run the second arg func_ */
|
||||
"ldp x29, x30, [sp, #0x10]\n\t" /* restore x29, x30 */
|
||||
"ldr x9, [sp, #0x00]\n\t" /* jump back to old stack */
|
||||
"mov sp, x9\n\t" /* transit SP by x9 */
|
||||
:"=r" (ret) /* output */
|
||||
:"r"(x0), "r"(func_), "r"(stack_addr) /* input*/
|
||||
:"x9", "memory" /* specify x9 is used */
|
||||
);
|
||||
return (int) ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
_RLOCAL(int64_t, all_stack_size);
|
||||
|
||||
} // namespace common
|
||||
|
42
deps/oblib/src/common/ob_smart_call.h
vendored
42
deps/oblib/src/common/ob_smart_call.h
vendored
@ -26,45 +26,7 @@ static constexpr int64_t STACK_PER_EXTEND = 2L << 20;
|
||||
static constexpr int64_t STACK_RESERVED_SIZE = 128L << 10;
|
||||
RLOCAL_EXTERN(int64_t, all_stack_size);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
inline int jump_call(void * arg_, int(*func_) (void*), void* stack_addr)
|
||||
{
|
||||
|
||||
int ret = 0;
|
||||
__asm__ __volatile__ (
|
||||
"leaq -0x10(%3), %3\n\t" /* reserve space for old RSP on new stack, 0x10 for align */
|
||||
"movq %%rsp, (%3)\n\t" /* store RSP in new stack */
|
||||
"movq %3, %%rsp\n\t" /* jump to new stack */
|
||||
"call *%2\n\t" /* run the second arg func_ */
|
||||
"popq %%rsp\n\t" /* jump back to old stack */
|
||||
:"=a" (ret) /* specify rax assigned to ret */
|
||||
:"D"(arg_), "r"(func_), "r"(stack_addr) /* specify rdi assigned to arg_ */
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
inline int jump_call(void * arg_, int(*func_) (void*), void* stack_addr)
|
||||
{
|
||||
int64_t ret = 0;
|
||||
__asm__ __volatile__ (
|
||||
"mov x0, %1\n\t"
|
||||
"sub %3, %3, #0x20\n\t" /* reserve space for old sp on new stack, 0x10 for align */
|
||||
"stp x29, x30, [%3, #0x10]\n\t" /* x29, x30 may not be stored in the innest function. */
|
||||
"mov x9, sp\n\t" /* store SP in new stack */
|
||||
"str x9, [%3, #0x00]\n\t"
|
||||
"mov sp, %3\n\t" /* jump SP to new stack */
|
||||
"blr %2\n\t" /* run the second arg func_ */
|
||||
"ldp x29, x30, [sp, #0x10]\n\t" /* restore x29, x30 */
|
||||
"ldr x9, [sp, #0x00]\n\t" /* jump back to old stack */
|
||||
"mov sp, x9\n\t"
|
||||
"mov %0, x0\n\t"
|
||||
:"=r" (ret)
|
||||
:"r"(arg_), "r"(func_), "r"(stack_addr)
|
||||
:"x9"
|
||||
);
|
||||
return (int) ret;
|
||||
}
|
||||
#endif
|
||||
int jump_call(void * arg_, int(*func_) (void*), void* stack_addr);
|
||||
|
||||
inline int call_with_new_stack(void * arg_, int(*func_) (void*))
|
||||
{
|
||||
@ -87,9 +49,7 @@ inline int call_with_new_stack(void * arg_, int(*func_) (void*))
|
||||
// To prevent the check_stack_overflow call before the jump
|
||||
// Do not introduce other code between the two set_stackattr
|
||||
set_stackattr(stack_addr, stack_size);
|
||||
WEAK_BARRIER();
|
||||
ret = jump_call(arg_, func_, (char *)stack_addr + stack_size);
|
||||
WEAK_BARRIER();
|
||||
set_stackattr(ori_stack_addr, ori_stack_size);
|
||||
lib::g_stack_allocer.dealloc(stack_addr);
|
||||
all_stack_size -= stack_size;
|
||||
|
42
deps/oblib/unittest/common/test_smart_call.cpp
vendored
42
deps/oblib/unittest/common/test_smart_call.cpp
vendored
@ -24,6 +24,27 @@ namespace oceanbase
|
||||
namespace common
|
||||
{
|
||||
|
||||
#define TEST_SMART_CALL(func, addr) \
|
||||
({ \
|
||||
int ret = OB_SUCCESS; \
|
||||
std::function<int()> f = [&]() { \
|
||||
int ret = OB_SUCCESS; \
|
||||
try { \
|
||||
in_try_stmt = true; \
|
||||
ret = func; \
|
||||
in_try_stmt = false; \
|
||||
} catch (OB_BASE_EXCEPTION &except) { \
|
||||
ret = except.get_errno(); \
|
||||
in_try_stmt = false; \
|
||||
} \
|
||||
return ret; \
|
||||
}; \
|
||||
int(*func_) (void*) = [](void *arg) { return (*(decltype(f)*)(arg))(); };\
|
||||
void * arg_ = &f; \
|
||||
ret = jump_call(arg_, func_, addr); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
int dec(int &i)
|
||||
{
|
||||
if (i <= 0) {
|
||||
@ -36,10 +57,13 @@ int dec(int &i)
|
||||
TEST(sc, usability)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
static constexpr int stack_size = 1024 * 1024 * 2;
|
||||
char stack1[stack_size];
|
||||
char stack2[stack_size];
|
||||
// global function
|
||||
{
|
||||
int i = 10;
|
||||
ret = SMART_CALL(dec(i));
|
||||
ret = TEST_SMART_CALL(dec(i), (char *)stack1 + stack_size);
|
||||
EXPECT_EQ(ret, OB_SUCCESS);
|
||||
EXPECT_EQ(i, 0);
|
||||
}
|
||||
@ -65,6 +89,22 @@ TEST(sc, usability)
|
||||
|
||||
// lambda && error code
|
||||
EXPECT_EQ(OB_ERR_UNEXPECTED, SMART_CALL([]() { return OB_ERR_UNEXPECTED;}()));
|
||||
|
||||
// nested SMART_CALL
|
||||
{
|
||||
std::function<int(int &)> nested_dec = [&](int &i) {
|
||||
int ret = OB_SUCCESS;
|
||||
int backup = i;
|
||||
ret = dec(i);
|
||||
i = backup;
|
||||
ret = TEST_SMART_CALL(dec(i), (char *)stack2 + stack_size);
|
||||
return ret;
|
||||
};
|
||||
int i = 10;
|
||||
ret = TEST_SMART_CALL(nested_dec(i), (char *)stack1 + stack_size);
|
||||
EXPECT_EQ(ret, OB_SUCCESS);
|
||||
EXPECT_EQ(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void *cur_stack_addr = nullptr;
|
||||
|
Reference in New Issue
Block a user