--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+
+#include "stdafx.h"
+
+#include "../../shared/riscv64/primitives.cpp"
${CORDBEE_HEADERS_DAC_AND_WKS}
)
+list(APPEND CORDBEE_SOURCES_WKS ${ARCH_SOURCES_DIR}/walker.cpp)
+
if(CLR_CMAKE_TARGET_ARCH_AMD64)
- list(APPEND CORDBEE_SOURCES_WKS
- ${ARCH_SOURCES_DIR}/debuggerregdisplayhelper.cpp
- ${ARCH_SOURCES_DIR}/amd64walker.cpp
- )
+ list(APPEND CORDBEE_SOURCES_WKS ${ARCH_SOURCES_DIR}/debuggerregdisplayhelper.cpp)
elseif(CLR_CMAKE_TARGET_ARCH_I386)
- list(APPEND CORDBEE_SOURCES_WKS
- ${ARCH_SOURCES_DIR}/debuggerregdisplayhelper.cpp
- ${ARCH_SOURCES_DIR}/x86walker.cpp
- )
-elseif(CLR_CMAKE_TARGET_ARCH_ARM)
- list(APPEND CORDBEE_SOURCES_WKS ${ARCH_SOURCES_DIR}/armwalker.cpp)
-elseif(CLR_CMAKE_TARGET_ARCH_ARM64)
- list(APPEND CORDBEE_SOURCES_WKS ${ARCH_SOURCES_DIR}/arm64walker.cpp)
-elseif(CLR_CMAKE_TARGET_ARCH_LOONGARCH64)
- list(APPEND CORDBEE_SOURCES_WKS ${ARCH_SOURCES_DIR}/loongarch64walker.cpp)
+ list(APPEND CORDBEE_SOURCES_WKS ${ARCH_SOURCES_DIR}/debuggerregdisplayhelper.cpp)
endif()
convert_to_absolute_path(CORDBEE_SOURCES_DAC ${CORDBEE_SOURCES_DAC})
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//*****************************************************************************
-// File: Amd64walker.cpp
-//
+//*****************************************************************************
//
// AMD64 instruction decoding/stepping logic
//
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//*****************************************************************************
-// File: armwalker.cpp
-//
+//*****************************************************************************
//
// ARM instruction decoding/stepping logic
//
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//*****************************************************************************
-// File: Arm64walker.cpp
-//
+//*****************************************************************************
//
// ARM64 instruction decoding/stepping logic
//
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//*****************************************************************************
-// File: x86walker.cpp
-//
+//*****************************************************************************
//
// x86 instruction decoding/stepping logic
//
// The .NET Foundation licenses this file to you under the MIT license.
//*****************************************************************************
-// File: Loongarch64walker.cpp
-//
-
//
// LOONGARCH64 instruction decoding/stepping logic
//
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-//
-
-#include "stdafx.h"
-#include "utilcode.h"
-#include "crosscomp.h"
-
#error Unsupported platform
-
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "asmconstants.h"
+#include "unixasmmacros.inc"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+
+#include "stdafx.h"
+#include "threads.h"
+#include "../../shared/riscv64/primitives.cpp"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//*****************************************************************************
+//
+// RISCV64 instruction decoding/stepping logic
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+#include "walker.h"
+#include "frames.h"
+#include "openum.h"
+
+#ifdef TARGET_RISCV64
+
+#error "TODO-RISCV64: missing implementation"
+
+#endif
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error Unsupported platform
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//*****************************************************************************
+// File: primitives.cpp
+//
+
+//
+// Platform-specific debugger primitives
+//
+//*****************************************************************************
+
+#include "primitives.h"
+
+#error "TODO-RISCV64: missing implementation"
private:
#ifndef _MSC_VER
- static void ArmInterlockedOperationBarrier();
+ static void InterlockedOperationBarrier();
#endif // !_MSC_VER
public:
#endif // _MSC_VER
#ifndef _MSC_VER
-__forceinline void Interlocked::ArmInterlockedOperationBarrier()
+__forceinline void Interlocked::InterlockedOperationBarrier()
{
-#ifdef HOST_ARM64
- // See PAL_ArmInterlockedOperationBarrier() in the PAL
+#if defined(HOST_ARM64) || defined(HOST_LOONGARCH64)
+ // See PAL_InterlockedOperationBarrier() in the PAL
__sync_synchronize();
-#endif // HOST_ARM64
-#ifdef HOST_LOONGARCH64
- __sync_synchronize();
-#endif //HOST_LOONGARCH64
+#endif
}
#endif // !_MSC_VER
return _InterlockedIncrement((long*)addend);
#else
T result = __sync_add_and_fetch(addend, 1);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
return _InterlockedDecrement((long*)addend);
#else
T result = __sync_sub_and_fetch(addend, 1);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
return _InterlockedExchange((long*)destination, value);
#else
T result = __atomic_exchange_n(destination, value, __ATOMIC_ACQ_REL);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
return _InterlockedCompareExchange((long*)destination, exchange, comparand);
#else
T result = __sync_val_compare_and_swap(destination, comparand, exchange);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
return _InterlockedExchangeAdd((long*)addend, value);
#else
T result = __sync_fetch_and_add(addend, value);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
return _InterlockedExchangeAdd64((int64_t*)addend, value);
#else
T result = __sync_fetch_and_add(addend, value);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
#endif
#else
T result = __sync_fetch_and_add(addend, value);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
_InterlockedAnd((long*)destination, value);
#else
__sync_and_and_fetch(destination, value);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
#endif
}
_InterlockedOr((long*)destination, value);
#else
__sync_or_and_fetch(destination, value);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
#endif
}
#endif
#else
T result = (T)(TADDR)__atomic_exchange_n((void* volatile *)destination, value, __ATOMIC_ACQ_REL);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
#endif
#else
T result = (T)(TADDR)__atomic_exchange_n((void* volatile *)destination, value, __ATOMIC_ACQ_REL);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
#endif
#else
T result = (T)(TADDR)__sync_val_compare_and_swap((void* volatile *)destination, comparand, exchange);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
#endif
#else
T result = (T)(TADDR)__sync_val_compare_and_swap((void* volatile *)destination, (void*)comparand, (void*)exchange);
- ArmInterlockedOperationBarrier();
+ InterlockedOperationBarrier();
return result;
#endif
}
#elif defined(TARGET_LINUX) && defined(TARGET_ARM)
#define DAC_CS_NATIVE_DATA_SIZE 80
#elif defined(TARGET_LINUX) && defined(TARGET_ARM64)
-#define DAC_CS_NATIVE_DATA_SIZE 116
+#define DAC_CS_NATIVE_DATA_SIZE 104
#elif defined(TARGET_LINUX) && defined(TARGET_LOONGARCH64)
#define DAC_CS_NATIVE_DATA_SIZE 96
#elif defined(TARGET_LINUX) && defined(TARGET_X86)
#ifndef HASHBV_H
#define HASHBV_H
-#if defined(_M_AMD64) || defined(_M_X86)
+#if defined(HOST_AMD64) || defined(HOST_X86)
#include <xmmintrin.h>
#endif
;;
MACRO
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
dmb ish
MEND
cbnz w9, 1b
2: // exit
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret
LEAF_END RhpLockCmpXchg32, _TEXT
stlxr w9, x1, [x8] // if (x0 == x2) { try *x8 = x1 and goto loop if failed or goto exit }
cbnz w9, 1b
2: // exit
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret
LEAF_END RhpLockCmpXchg64, _TEXT
cbnz w9, %bt1
2 ;; exit
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret
LEAF_END RhpLockCmpXchg32
cbnz w9, %bt1
2 ;; exit
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret
LEAF_END RhpLockCmpXchg64
CmpXchgNoUpdate:
// x10 still contains the original value.
mov x0, x10
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret lr
LEAF_END RhpCheckedLockCmpXchg, _TEXT
// x10 still contains the original value.
mov x0, x10
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret
LEAF_END RhpCheckedXchg, _TEXT
CmpXchgNoUpdate
;; x10 still contains the original value.
mov x0, x10
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret lr
LEAF_END RhpCheckedLockCmpXchg
;; x10 still contains the original value.
mov x0, x10
- ArmInterlockedOperationBarrier
+ InterlockedOperationBarrier
ret
LEAF_END RhpCheckedXchg
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 96
.endm
-.macro ArmInterlockedOperationBarrier
+.macro InterlockedOperationBarrier
dmb ish
.endm
extern bool g_arm64_atomics_present;
#endif
-/******************* Processor-specific glue *****************************/
-
-#ifndef _MSC_VER
-
-#if defined(__i686__) && !defined(_M_IX86)
-#define _M_IX86 600
-#elif defined(__i586__) && !defined(_M_IX86)
-#define _M_IX86 500
-#elif defined(__i486__) && !defined(_M_IX86)
-#define _M_IX86 400
-#elif defined(__i386__) && !defined(_M_IX86)
-#define _M_IX86 300
-#elif defined(__x86_64__) && !defined(_M_AMD64)
-#define _M_AMD64 100
-#elif defined(__arm__) && !defined(_M_ARM)
-#define _M_ARM 7
-#elif defined(__aarch64__) && !defined(_M_ARM64)
-#define _M_ARM64 1
-#elif defined(__loongarch64) && !defined(_M_LOONGARCH64)
-#define _M_LOONGARCH64 1
-#elif defined(__s390x__) && !defined(_M_S390X)
-#define _M_S390X 1
-#elif defined(__powerpc__) && !defined(_M_PPC64)
-#define _M_PPC64 1
-#endif
-
-#if defined(_M_IX86) && !defined(HOST_X86)
-#define HOST_X86
-#elif defined(_M_AMD64) && !defined(HOST_AMD64)
-#define HOST_AMD64
-#elif defined(_M_ARM) && !defined(HOST_ARM)
-#define HOST_ARM
-#elif defined(_M_ARM64) && !defined(HOST_ARM64)
-#define HOST_ARM64
-#elif defined(_M_LOONGARCH64) && !defined(HOST_LOONGARCH64)
-#define HOST_LOONGARCH64
-#elif defined(_M_S390X) && !defined(HOST_S390X)
-#define HOST_S390X
-#elif defined(_M_PPC64) && !defined(HOST_POWERPC64)
-#define HOST_POWERPC64
-#endif
-
-#endif // !_MSC_VER
-
/******************* ABI-specific glue *******************************/
#define MAX_PATH 260
#elif defined(__linux__) && defined(HOST_ARM)
#define PAL_CS_NATIVE_DATA_SIZE 80
#elif defined(__linux__) && defined(HOST_ARM64)
-#define PAL_CS_NATIVE_DATA_SIZE 116
+#define PAL_CS_NATIVE_DATA_SIZE 104
#elif defined(__linux__) && defined(__i386__)
#define PAL_CS_NATIVE_DATA_SIZE 76
#elif defined(__linux__) && defined(__x86_64__)
#define PAL_CS_NATIVE_DATA_SIZE 48
#elif defined(__linux__) && defined(__loongarch64)
#define PAL_CS_NATIVE_DATA_SIZE 96
+#elif defined(__linux__) && defined(_riscv) && __riscv_xlen == 64
+#define PAL_CS_NATIVE_DATA_SIZE 96
#else
-#warning
#error PAL_CS_NATIVE_DATA_SIZE is not defined for this architecture
#endif
return qwMask != 0;
}
-FORCEINLINE void PAL_ArmInterlockedOperationBarrier()
+FORCEINLINE void PAL_InterlockedOperationBarrier()
{
-#ifdef HOST_ARM64
+#if defined(HOST_ARM64) || defined(HOST_LOONGARCH64) || defined(HOST_RISCV64)
// On arm64, most of the __sync* functions generate a code sequence like:
// loop:
// ldaxr (load acquire exclusive)
// require the load to occur after the store. This memory barrier should be used following a call to a __sync* function to
// prevent that reordering. Code generated for arm32 includes a 'dmb' after 'cbnz', so no issue there at the moment.
__sync_synchronize();
-#endif // HOST_ARM64
-#ifdef HOST_LOONGARCH64
- __sync_synchronize();
#endif
}
else \
{ \
RETURN_TYPE result = INTRINSIC_NAME; \
- PAL_ArmInterlockedOperationBarrier(); \
+ PAL_InterlockedOperationBarrier(); \
return result; \
} \
} \
EXTERN_C PALIMPORT inline RETURN_TYPE PALAPI METHOD_DECL \
{ \
RETURN_TYPE result = INTRINSIC_NAME; \
- PAL_ArmInterlockedOperationBarrier(); \
+ PAL_InterlockedOperationBarrier(); \
return result; \
} \
__asm__ __volatile__( "yield");
#elif defined(HOST_LOONGARCH64)
__asm__ volatile( "dbar 0; \n");
+#elif defined(HOST_RISV64)
+ __asm__ __volatile__( "wfi");
#else
return;
#endif
#endif /* defined (_SYSCRT) && defined (HOST_64BIT) */
#if !defined (UNALIGNED)
-#if defined (_M_AMD64)
+#if defined (TARGET_AMD64)
#define UNALIGNED __unaligned
-#else /* defined (_M_AMD64) */
+#else /* defined (TARGET_AMD64) */
#define UNALIGNED
-#endif /* defined (_M_AMD64) */
+#endif /* defined (TARGET_AMD64) */
#endif /* !defined (UNALIGNED) */
-#ifdef _M_IX86
+#ifdef TARGET_X86
/*
* 386/486
*/
#define REG8
#define REG9
-#elif defined (_M_AMD64)
+#elif defined (TARGET_AMD64)
/*
* AMD64
*/
#define REG8 register
#define REG9 register
-#else /* defined (_M_AMD64) */
+#else /* defined (TARGET_AMD64) */
#pragma message ("Machine register set not defined")
#define REG8
#define REG9
-#endif /* defined (_M_AMD64) */
+#endif /* defined (TARGET_AMD64) */
/*
* Are the macro definitions below still needed in this file?
include_directories(${CLR_DIR}/debug/daccess)
set(UNWINDER_SOURCES
- unwinder.cpp
+ baseunwinder.cpp
)
# Include platform specific unwinder for applicable (native and cross-target) builds.
include_directories(${ARCH_SOURCES_DIR})
list(APPEND UNWINDER_SOURCES
- ${ARCH_SOURCES_DIR}/unwinder_${ARCH_SOURCES_DIR}.cpp
+ ${ARCH_SOURCES_DIR}/unwinder.cpp
)
convert_to_absolute_path(UNWINDER_SOURCES ${UNWINDER_SOURCES})
//
#include "stdafx.h"
-#include "unwinder_amd64.h"
+#include "unwinder.h"
typedef DPTR(M128A) PTR_M128A;
#ifndef __unwinder_amd64_h__
#define __unwinder_amd64_h__
-#include "unwinder.h"
+#include "baseunwinder.h"
//---------------------------------------------------------------------------------------
#include "stdafx.h"
#include "utilcode.h"
-#include "unwinder_arm.h"
+#include "unwinder.h"
#define DBS_EXTEND64(x) ((DWORD64)x)
#define MEMORY_READ_BYTE(params, addr) (*dac_cast<PTR_BYTE>(addr))
#ifndef __unwinder_arm__
#define __unwinder_arm__
-#include "unwinder.h"
+#include "baseunwinder.h"
//---------------------------------------------------------------------------------------
#include "utilcode.h"
#include "crosscomp.h"
-#include "unwinder_arm64.h"
+#include "unwinder.h"
typedef struct _ARM64_KTRAP_FRAME {
#ifndef __unwinder_arm64__
#define __unwinder_arm64__
-#include "unwinder.h"
+#include "baseunwinder.h"
//---------------------------------------------------------------------------------------
//
#include "stdafx.h"
-#include "unwinder.h"
+#include "baseunwinder.h"
EXTERN_C void GetRuntimeStackWalkInfo(IN ULONG64 ControlPc,
OUT UINT_PTR* pModuleBase,
//
#include "stdafx.h"
-#include "unwinder_i386.h"
+#include "unwinder.h"
#ifdef FEATURE_EH_FUNCLETS
BOOL OOPStackUnwinderX86::Unwind(T_CONTEXT* pContextRecord, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers)
#ifndef __unwinder_i386_h__
#define __unwinder_i386_h__
-#include "unwinder.h"
+#include "baseunwinder.h"
#ifdef FEATURE_EH_FUNCLETS
//---------------------------------------------------------------------------------------
#include "utilcode.h"
#include "crosscomp.h"
-#include "unwinder_loongarch64.h"
+#include "unwinder.h"
typedef struct _LOONGARCH64_KTRAP_FRAME {
#ifndef __unwinder_loongarch64__
#define __unwinder_loongarch64__
-#include "unwinder.h"
+#include "baseunwinder.h"
//---------------------------------------------------------------------------------------
//
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error Unsupported platform
#include "utilcode.h"
#include "crosscomp.h"
-#error Unsupported platform
+#include "unwinder.h"
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+//
+
+#ifndef __unwinder_riscv64__
+#define __unwinder_riscv64__
+
+#include "baseunwinder.h"
+
+#error "TODO-RISCV64: missing implementation"
+
+#endif // __unwinder_riscv64__
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error Unsupported platform
set(VM_SOURCES_WKS_ARCH
${ARCH_SOURCES_DIR}/profiler.cpp
- ${ARCH_SOURCES_DIR}/armsinglestepper.cpp
+ ${ARCH_SOURCES_DIR}/singlestepper.cpp
exceptionhandling.cpp
gcinfodecoder.cpp
)
if(CLR_CMAKE_HOST_UNIX)
list(APPEND VM_SOURCES_WKS_ARCH
- ${ARCH_SOURCES_DIR}/arm64singlestepper.cpp
+ ${ARCH_SOURCES_DIR}/singlestepper.cpp
)
endif(CLR_CMAKE_HOST_UNIX)
elseif(CLR_CMAKE_TARGET_ARCH_LOONGARCH64)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "asmconstants.h"
+#include "unixasmmacros.inc"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "unixasmmacros.inc"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef __excepcpu_h__
+#define __excepcpu_h__
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "asmconstants.h"
+#include "unixasmmacros.inc"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "common.h"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+#error "TODO-RISCV64: missing implementation"
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#include "common.h"
+
+extern "C"
+{
+ void RedirectForThrowControl()
+ {
+ PORTABILITY_ASSERT("Implement for PAL");
+ }
+};
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#error "TODO-RISCV64: missing implementation"