changhong/xcode/Libraries/libil2cpp/include/os/Unity/ExtendedAtomicOps-arm64-win...

533 lines
21 KiB
C
Raw Normal View History

2025-09-22 17:27:49 +08:00
#include <intrin.h>
static inline void atomic_thread_fence(memory_order_relaxed_t)
{
}
static inline void atomic_thread_fence(memory_order_acquire_t)
{
__dmb(_ARM64_BARRIER_ISH);
}
static inline void atomic_thread_fence(memory_order_release_t)
{
__dmb(_ARM64_BARRIER_ISH);
}
static inline void atomic_thread_fence(memory_order_acq_rel_t)
{
__dmb(_ARM64_BARRIER_ISH);
}
static inline void atomic_thread_fence(int /* memory_order_seq_cst_t */)
{
__dmb(_ARM64_BARRIER_ISH);
}
static inline int atomic_load_explicit(const volatile int* p, memory_order_relaxed_t)
{
return __iso_volatile_load32(p);
}
static inline int atomic_load_explicit(const volatile int* p, memory_order_acquire_t)
{
int res = __iso_volatile_load32(p);
__dmb(_ARM64_BARRIER_ISH);
return res;
}
static inline int atomic_load_explicit(const volatile int* p, int /* memory_order_seq_cst_t */)
{
int res = __iso_volatile_load32(p);
__dmb(_ARM64_BARRIER_ISH);
return res;
}
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_relaxed_t)
{
return __iso_volatile_load64(p);
}
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_acquire_t)
{
atomic_word res = __iso_volatile_load64(p);
__dmb(_ARM64_BARRIER_ISH);
return res;
}
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, int /* memory_order_seq_cst_t */)
{
atomic_word res = __iso_volatile_load64(p);
__dmb(_ARM64_BARRIER_ISH);
return res;
}
static inline void atomic_store_explicit(volatile int* p, int v, memory_order_relaxed_t)
{
__iso_volatile_store32(p, v);
}
static inline void atomic_store_explicit(volatile int* p, int v, memory_order_release_t)
{
__dmb(_ARM64_BARRIER_ISH);
__iso_volatile_store32(p, v);
}
static inline void atomic_store_explicit(volatile int* p, int v, int /* memory_order_seq_cst_t */)
{
__dmb(_ARM64_BARRIER_ISH);
__iso_volatile_store32(p, v);
__dmb(_ARM64_BARRIER_ISH);
}
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
{
__iso_volatile_store64(p, v);
}
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
{
__dmb(_ARM64_BARRIER_ISH);
__iso_volatile_store64(p, v);
}
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
{
__dmb(_ARM64_BARRIER_ISH);
__iso_volatile_store64(p, v);
__dmb(_ARM64_BARRIER_ISH);
}
static inline int atomic_exchange_explicit(volatile int* p, int v, memory_order_relaxed_t)
{
return _InterlockedExchange_nf(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_exchange_explicit(volatile int* p, int v, memory_order_acquire_t)
{
return _InterlockedExchange_acq(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_exchange_explicit(volatile int* p, int v, memory_order_release_t)
{
return _InterlockedExchange_rel(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_exchange_explicit(volatile int* p, int v, memory_order_acq_rel_t)
{
return _InterlockedExchange(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_exchange_explicit(volatile int* p, int v, int /* memory_order_seq_cst_t */)
{
return _InterlockedExchange(reinterpret_cast<volatile long*>(p), v);
}
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
{
return _InterlockedExchange64_nf(p, v);
}
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
{
return _InterlockedExchange64_acq(p, v);
}
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
{
return _InterlockedExchange64_rel(p, v);
}
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
{
return _InterlockedExchange64(p, v);
}
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
{
return _InterlockedExchange64(p, v);
}
// atomic_compare_exchange_weak_explicit: can fail spuriously even if *p == *oldval
#undef ATOMIC_CMP_XCHG
#define ATOMIC_CMP_XCHG(valueType, p, oldval, newval, exchangeFunction) \
do \
{ \
valueType oldValue = *oldval; \
valueType previousValue = exchangeFunction(p, newval, oldValue); \
if (previousValue == oldValue) \
return true; \
\
*oldval = previousValue; \
return false; \
} \
while (false)
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, memory_order_relaxed_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_nf);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, memory_order_acquire_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_acq);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, memory_order_release_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_rel);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, memory_order_acq_rel_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, memory_order_acquire_t, memory_order_acquire_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_acq);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, memory_order_release_t, memory_order_release_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_rel);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile int* p, int *oldval, int newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_relaxed_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_nf);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_acq);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_rel);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_acquire_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_acq);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_release_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_rel);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
// atomic_compare_exchange_strong_explicit: does loop and only returns false if *p != *oldval
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, memory_order_relaxed_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_nf);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, memory_order_acquire_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_acq);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, memory_order_release_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_rel);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, memory_order_acq_rel_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, memory_order_acquire_t, memory_order_acquire_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_acq);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, memory_order_release_t, memory_order_release_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange_rel);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile int* p, int *oldval, int newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
{
ATOMIC_CMP_XCHG(long, reinterpret_cast<volatile long*>(p), oldval, newval, _InterlockedCompareExchange);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_relaxed_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_nf);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_acq);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_rel);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_acquire_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_acq);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_release_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64_rel);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
{
ATOMIC_CMP_XCHG(atomic_word, p, oldval, newval, _InterlockedCompareExchange64);
}
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_relaxed_t)
{
return _InterlockedExchangeAdd_nf(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_acquire_t)
{
return _InterlockedExchangeAdd_acq(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_release_t)
{
return _InterlockedExchangeAdd_rel(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_acq_rel_t)
{
return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(p), v);
}
static inline int atomic_fetch_add_explicit(volatile int* p, int v, int /* memory_order_seq_cst_t */)
{
return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(p), v);
}
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
{
return _InterlockedExchangeAdd64_nf(p, v);
}
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
{
return _InterlockedExchangeAdd64_acq(p, v);
}
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
{
return _InterlockedExchangeAdd64_rel(p, v);
}
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
{
return _InterlockedExchangeAdd64(p, v);
}
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
{
return _InterlockedExchangeAdd64(p, v);
}
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_relaxed_t)
{
return _InterlockedExchangeAdd_nf(reinterpret_cast<volatile long*>(p), -v);
}
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_acquire_t)
{
return _InterlockedExchangeAdd_acq(reinterpret_cast<volatile long*>(p), -v);
}
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_release_t)
{
return _InterlockedExchangeAdd_rel(reinterpret_cast<volatile long*>(p), -v);
}
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_acq_rel_t)
{
return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(p), -v);
}
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, int /* memory_order_seq_cst_t */)
{
return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(p), -v);
}
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
{
return _InterlockedExchangeAdd64_nf(p, -v);
}
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
{
return _InterlockedExchangeAdd64_acq(p, -v);
}
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
{
return _InterlockedExchangeAdd64_rel(p, -v);
}
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
{
return _InterlockedExchangeAdd64(p, -v);
}
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
{
return _InterlockedExchangeAdd64(p, -v);
}
/*
* extensions
*/
static inline void atomic_retain(volatile int* p)
{
atomic_fetch_add_explicit(p, 1, memory_order_relaxed);
}
static inline bool atomic_release(volatile int* p)
{
bool res = atomic_fetch_sub_explicit(p, 1, memory_order_release) == 1;
if (res)
{
atomic_thread_fence(memory_order_acquire);
}
return res;
}
/*
* double word
*/
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, memory_order_relaxed_t)
{
atomic_word2 result = { 0, 0 };
_InterlockedCompareExchange128_nf(/* _Destination */ const_cast<volatile atomic_word*>(&p->lo), /* _ExchangeHigh */ 0, /* _ExchangeLow */ 0, /* _ComparandResult */ &result.lo);
return result;
}
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, memory_order_acquire_t)
{
atomic_word2 result = { 0, 0 };
_InterlockedCompareExchange128_acq(/* _Destination */ const_cast<volatile atomic_word*>(&p->lo), /* _ExchangeHigh */ 0, /* _ExchangeLow */ 0, /* _ComparandResult */ &result.lo);
return result;
}
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, memory_order_relaxed_t)
{
atomic_word2 comparand = v;
while (!_InterlockedCompareExchange128_nf(/* _Destination */ &p->lo, /* _ExchangeHigh */ v.hi, /* _ExchangeLow */ v.lo, /* _ComparandResult */ &comparand.lo))
{
}
}
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, memory_order_release_t)
{
atomic_word2 comparand = v;
while (!_InterlockedCompareExchange128_rel(/* _Destination */ &p->lo, /* _ExchangeHigh */ v.hi, /* _ExchangeLow */ v.lo, /* _ComparandResult */ &comparand.lo))
{
}
}
static inline atomic_word2 atomic_exchange_explicit(volatile atomic_word2* p, atomic_word2 val, memory_order_acq_rel_t)
{
atomic_word2 comparand = val;
while (!_InterlockedCompareExchange128(/* _Destination */ &p->lo, /* _ExchangeHigh */ val.hi, /* _ExchangeLow */ val.lo, /* _ComparandResult */ &comparand.lo))
{
}
return comparand;
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_acquire_t, memory_order_relaxed_t)
{
return _InterlockedCompareExchange128_acq(/* _Destination */ &p->lo, /* _ExchangeHigh */ newval.hi, /* _ExchangeLow */ newval.lo, /* _ComparandResult */ &oldval->lo);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_release_t, memory_order_relaxed_t)
{
return _InterlockedCompareExchange128_rel(/* _Destination */ &p->lo, /* _ExchangeHigh */ newval.hi, /* _ExchangeLow */ newval.lo, /* _ComparandResult */ &oldval->lo);
}
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, int /*memory_order_acq_rel_t*/, memory_order_relaxed_t)
{
return _InterlockedCompareExchange128(/* _Destination */ &p->lo, /* _ExchangeHigh */ newval.hi, /* _ExchangeLow */ newval.lo, /* _ComparandResult */ &oldval->lo);
}
template<class SuccOrder, class FailOrder>
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, SuccOrder o1, FailOrder o2)
{
// TODO: implement proper weak compare exchange
return atomic_compare_exchange_strong_explicit(p, oldval, newval, o1, o2);
}