diff --git a/test/Makefile b/test/Makefile index 3314bd47..a9185fd3 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,7 +1,7 @@ # To compile with -m32 # apt install g++-multilib TARGET = make_nm normalize_prefix bad_address misc cvt_test cvt_test32 noexception misc32 detect_x32 avx10_test -XBYAK_INC=../xbyak/xbyak.h ../xbyak/xbyak_mnemonic.h +XBYAK_INC=../xbyak/xbyak.h ../xbyak/xbyak_mnemonic.h ../xbyak/xbyak_util.h UNAME_S=$(shell uname -s) ifeq ($(shell ./detect_x32),x32) X32?=1 diff --git a/test/sf_test.cpp b/test/sf_test.cpp index a7881d7e..9a3d4f3c 100644 --- a/test/sf_test.cpp +++ b/test/sf_test.cpp @@ -389,3 +389,61 @@ CYBOZU_TEST_AUTO(pack) } } +struct CloseCode : Xbyak::CodeGenerator { + CloseCode(size_t mode) + { + switch (mode) { + case 0: + { + StackFrame sf(this, 0); + // close() is automatically called. + } + break; + + case 1: + { + StackFrame sf(this, 0); + sf.close(); // Explicitly call close(). + } + break; + + case 2: + { + StackFrame sf(this, 0); + sf.close(); + sf.close(); // The second call is ignored. + } + break; + + case 3: + { + StackFrame sf(this, 0); + sf.makeEpilog(); // Explicitly call makeEpilog. + // close() is automatically called. + } + break; + + case 4: + { + StackFrame sf(this, 0); + sf.makeEpilog(); // Explicitly call makeEpilog. + sf.makeEpilog(); // The second call is also valid. + // close() is automatically called. + } + break; + default: + CYBOZU_TEST_ASSERT(false); + } + } +}; + +CYBOZU_TEST_AUTO(close) +{ + const size_t expectedTbl[] = { + 1, 1, 1, 2, 3, + }; + for (size_t i = 0; i < sizeof(expectedTbl)/sizeof(expectedTbl[0]); i++) { + CloseCode c(i); + CYBOZU_TEST_EQUAL(c.getSize(), expectedTbl[i]); + } +} diff --git a/xbyak/xbyak_util.h b/xbyak/xbyak_util.h index 1f138e3b..1e6d2b24 100644 --- a/xbyak/xbyak_util.h +++ b/xbyak/xbyak_util.h @@ -892,17 +892,18 @@ class StackFrame { #endif static const int maxRegNum = 14; // maxRegNum = 16 - rsp - rax Xbyak::CodeGenerator *code_; + Xbyak::Reg64 pTbl_[4]; + Xbyak::Reg64 tTbl_[maxRegNum]; + Pack p_; + Pack t_; int pNum_; int tNum_; - bool useRcx_; - bool useRdx_; int saveNum_; int P_; + bool useRcx_; + bool useRdx_; bool makeEpilog_; - Xbyak::Reg64 pTbl_[4]; - Xbyak::Reg64 tTbl_[maxRegNum]; - Pack p_; - Pack t_; + bool closed_; StackFrame(const StackFrame&); void operator=(const StackFrame&); public: @@ -928,11 +929,12 @@ class StackFrame { : code_(code) , pNum_(pNum) , tNum_(tNum & ~(UseRCX | UseRDX)) - , useRcx_((tNum & UseRCX) != 0) - , useRdx_((tNum & UseRDX) != 0) , saveNum_(0) , P_(0) + , useRcx_((tNum & UseRCX) != 0) + , useRdx_((tNum & UseRDX) != 0) , makeEpilog_(makeEpilog) + , closed_(false) , p(p_) , t(t_) { @@ -966,7 +968,7 @@ class StackFrame { make epilog manually @param callRet [in] call ret() if true */ - void close(bool callRet = true) + void makeEpilog(bool callRet = true) { using namespace Xbyak; const Reg64& _rsp = code_->rsp; @@ -978,6 +980,14 @@ class StackFrame { if (callRet) code_->ret(); } + // close() is automatically called in a destructor. + // It is not called if close() is explicitly called before. + void close(bool callRet = true) + { + if (closed_) return; + makeEpilog(callRet); + closed_ = true; + } ~StackFrame() { if (!makeEpilog_) return;