#include "InterpreterSpecific.h"
#ifdef INTERPRETER_ENABLED
#include "Base/LogFile.h"
#include "CjScheduler.h"
#include "Common/BaseObject.h"
#include "Common/ScopedObjectAccess.h"
#include "Common/TypeDef.h"
#include "ExceptionManager.inline.h"
#include "Heap/Barrier/Barrier.h"
#include "Heap/Collector/Collector.h"
#include "Interpreter/RTInterface.h"
#include "LoaderManager.h"
#include "Mutator/Mutator.h"
#include "Mutator/ThreadLocal.h"
#include "ObjectManager.inline.h"
#include "ObjectModel/MArray.h"
#include "ObjectModel/MClass.h"
#include "StackManager.h"
#include "TypeInfoManager.h"
#include "dlfcn.h"
#include <cstdint>
#include <cstring>
namespace MapleRuntime {
extern "C" void CJ_MCC_StackGrowStub(...);
#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
extern "C" void CJ_MCC_I2NStub(...);
extern "C" void CJ_MCC_I2NStubEnd(...);
#endif
extern "C" FuncPtr* CJ_MCC_GetMTable(TypeInfo* ti, TypeInfo* itf);
extern "C" TypeInfo* CJ_MCC_GetMethodOuterTI(TypeInfo* ti, TypeInfo* itf, U64 index);
extern "C" void CJ_MCC_UpdateVMT(TypeInfo* ti, TypeInfo* itf, ExtensionData* extensionData);
struct {
bool initialized = false;
INT_InterpreterInterface interpreterInterface;
void initialize(INT_InterpreterInterface& value)
{
interpreterInterface = value;
initialized = true;
}
operator bool()
{
return initialized;
}
INT_InterpreterInterface* operator->()
{
if (initialized) {
return &interpreterInterface;
}
LOG(RTLOG_FATAL, "Usage of uninitialized interpreter interface\n");
return nullptr;
}
} g_interpreterInterface;
void FillInterpretedFrameInfo(uint64_t fp, uint64_t ip, INT_InterpretedFrameInfo* fInfo)
{
auto framePointer = reinterpret_cast<DYN_FramePointer>(fp);
auto instructionPointer = reinterpret_cast<DYN_InstructionPointer>(ip);
DLOG(INTERPRETER, "FillInterpretedFrameInfo(fp=%p, ip=%p)", framePointer, instructionPointer);
if (g_interpreterInterface) {
g_interpreterInterface->frameInfoProvider(framePointer, instructionPointer, fInfo);
}
}
void IterateFramesWithState(
DYN_CJThreadSpecificData cjThreadData, void (*callback)(DYN_VisitingState, void*), void* ctx)
{
if (g_interpreterInterface) {
g_interpreterInterface->iterateFramesWithState(cjThreadData, callback, ctx);
}
}
INT_FrameDesc toFrameDesc(FrameInfo frameInfo)
{
return {
.fp = frameInfo.GetMachineFrame().GetFA(),
.ip = frameInfo.GetMachineFrame().GetIP(),
};
}
void VisitInterpreterFrameRootsExpansion(DYN_VisitingState state, FrameInfo frameDesc, DYN_RootVisitor stackPtrVisitor,
DYN_DerivedPtrVisitor derivedPtrVisitor)
{
if (g_interpreterInterface) {
INT_FrameDesc fd = toFrameDesc(frameDesc);
g_interpreterInterface->visitFrameRootsExpansion(state, fd, stackPtrVisitor, derivedPtrVisitor);
}
}
void VisitInterpreterFrameRootsMarking(DYN_VisitingState state, FrameInfo frameDesc, DYN_RootVisitor rootVisitor)
{
if (g_interpreterInterface) {
INT_FrameDesc fd = toFrameDesc(frameDesc);
g_interpreterInterface->visitFrameRootsMarking(state, fd, rootVisitor);
}
}
void VisitInterpreterFrameRootsAdjusting(
DYN_VisitingState state, FrameInfo frameDesc, DYN_RootVisitor rootVisitor, DYN_DerivedPtrVisitor derivedPtrVisitor)
{
if (g_interpreterInterface) {
INT_FrameDesc fd = toFrameDesc(frameDesc);
g_interpreterInterface->visitFrameRootsAdjusting(state, fd, rootVisitor, derivedPtrVisitor);
}
}
void VisitInterpreterGlobalRoots(DYN_RootVisitor visitor)
{
if (g_interpreterInterface) {
g_interpreterInterface->visitGlobalRoots(visitor);
}
}
void InterpreterCJThreadStart(DYN_CJThreadSpecificData* dataField)
{
if (g_interpreterInterface) {
g_interpreterInterface->cjThreadOnStart(dataField);
}
}
void InterpreterCJThreadDestroy(DYN_CJThreadSpecificData* dataField)
{
if (g_interpreterInterface) {
g_interpreterInterface->cjThreadOnDestroy(dataField);
}
}
DYN_CJThreadHandle NewCJThread(void* execute, DYN_ObjRef future, void* scheduler)
{
DLOG(INTERPRETER, "NewCJThread: execute=%p, future=%p, scheduler=%p", execute, future, scheduler);
return MCC_NewCJThread(execute, future, scheduler);
}
void VisitRootFromInterpreter(DYN_RootVisitor _visitor, DYN_Placeholder _placeholder)
{
const RootVisitor* visitor = static_cast<const RootVisitor*>(_visitor);
ObjectRef* placeholder = static_cast<ObjectRef*>(_placeholder);
DLOG(INTERPRETER, "VisitRootFromInterpreter: visitor=[%p], placeholder=[%p]", (void*)visitor, (void*)placeholder);
(*visitor)(*placeholder);
}
void VisitDerivedPtrFromInterpreter(
DYN_DerivedPtrVisitor _visitor, DYN_Placeholder _basePtrHolder, DYN_Placeholder _derivedPtrHolder)
{
const DerivedPtrVisitor* visitor = static_cast<const DerivedPtrVisitor*>(_visitor);
BasePtrType* basePtrLocation = static_cast<BasePtrType*>(_basePtrHolder);
DerivedPtrType* derivedPtrLocation = static_cast<DerivedPtrType*>(_derivedPtrHolder);
DLOG(INTERPRETER, "VisitDerivedPtrFromInterpreter: visitor=[%p], placeholder=[%p]", (void*)visitor,
(void*)derivedPtrLocation);
(*visitor)(*basePtrLocation, *derivedPtrLocation);
}
struct DYN_TypeInfo* TypeInfoProvider(const char* sig)
{
DLOG(INTERPRETER, "TypeInfoProvider: %s", sig);
auto* result =
reinterpret_cast<struct DYN_TypeInfo*>(LoaderManager::GetInstance()->FindTypeInfoFromLoadedFiles(sig));
DLOG(INTERPRETER, "FindTypeInfoFromLoadedFiles(%s) return %p", sig, result);
return result;
}
DYN_TypeTemplate FindTypeTemplate(const char* mangledName)
{
DLOG(INTERPRETER, "FindTypeTemplate: %s", mangledName);
DYN_TypeTemplate result = LoaderManager::GetInstance()->FindTypeTemplateFromLoadedFiles(mangledName);
DLOG(INTERPRETER, "FindTypeTemplateFromLoadedFiles(%s) return %p", mangledName, result);
return result;
}
struct DYN_TypeInfo* GetOrCreateTypeInfo(
DYN_TypeTemplate typeTemplate, uint32_t typeArgsCount, struct DYN_TypeInfo** typeArgs)
{
DLOG(INTERPRETER, "GetOrCreateTypeInfo: template=%p size=%u", typeTemplate, typeArgsCount);
return reinterpret_cast<struct DYN_TypeInfo*>(TypeInfoManager::GetTypeInfoManager().GetOrCreateTypeInfo(
static_cast<TypeTemplate*>(typeTemplate), typeArgsCount, reinterpret_cast<TypeInfo**>(typeArgs)));
}
uint32_t GetInstanceSize(struct DYN_TypeInfo* typeInfoPtr)
{
TypeInfo* ti = reinterpret_cast<TypeInfo*>(typeInfoPtr);
DLOG(INTERPRETER, "GetInstanceSize: %s", ti->GetName());
return ti->GetInstanceSize();
}
DYN_FuncPtr* GetMTable(struct DYN_TypeInfo* ti, struct DYN_TypeInfo* itf)
{
DLOG(INTERPRETER, "GetMTable: ti=%p, itf=%p", ti, itf);
return reinterpret_cast<DYN_FuncPtr*>(
CJ_MCC_GetMTable(reinterpret_cast<TypeInfo*>(ti), reinterpret_cast<TypeInfo*>(itf)));
}
struct DYN_TypeInfo* GetMethodOuterTI(struct DYN_TypeInfo* ti, struct DYN_TypeInfo* itf, uint64_t index)
{
DLOG(INTERPRETER, "GetMethodOuterTI: ti=%p, itf=%p, index=%llu", ti, itf, static_cast<unsigned long long>(index));
return reinterpret_cast<struct DYN_TypeInfo*>(
CJ_MCC_GetMethodOuterTI(reinterpret_cast<TypeInfo*>(ti), reinterpret_cast<TypeInfo*>(itf), index));
}
void UpdateVMT(struct DYN_TypeInfo* ti, struct DYN_TypeInfo* itf, struct DYN_ExtensionData* extensionData)
{
DLOG(INTERPRETER, "UpdateVMT: ti=%p, itf=%p, extensionData=%p", ti, itf, extensionData);
CJ_MCC_UpdateVMT(reinterpret_cast<TypeInfo*>(ti), reinterpret_cast<TypeInfo*>(itf),
reinterpret_cast<ExtensionData*>(extensionData));
}
uint32_t GetTypeInfoUUID(struct DYN_TypeInfo* ti)
{
TypeInfo* typeInfo = reinterpret_cast<TypeInfo*>(ti);
DLOG(INTERPRETER, "GetTypeInfoUUID: ti=%p", ti);
return typeInfo->GetUUID();
}
DYN_ObjRef ObjectAllocate(struct DYN_TypeInfo* tpe)
{
TypeInfo* typeInfo = reinterpret_cast<TypeInfo*>(tpe);
MSize size = AlignUp<MSize>(typeInfo->GetInstanceSize(), 8) + sizeof(TypeInfo*);
ObjRef obj = ObjectManager::NewObject(typeInfo, size);
DLOG(INTERPRETER, "ObjectAllocate: type=%p (%s), addr=%p, size=%u", tpe, typeInfo->GetName(), obj, size);
return (DYN_ObjRef)obj;
}
DYN_ObjRef ArrayAllocate(struct DYN_TypeInfo* tpe, uint64_t size)
{
TypeInfo* typeInfo = reinterpret_cast<TypeInfo*>(tpe);
ArrayRef arr = ObjectManager::NewArray(size, typeInfo);
DLOG(INTERPRETER, "ArrayAllocate: type=%p, addr=%p, size=%u", tpe, arr, size);
return (DYN_ObjRef)arr;
}
void SafePoint()
{
DLOG(INTERPRETER, "SafePoint");
ScopedEnterSaferegion gcpoint(true);
}
bool IsPendingSafePoint(DYN_ThreadLocalData tlData)
{
if (tlData == nullptr) {
LOG(RTLOG_ERROR, "[Interpreter] IsPendingSafePoint called with null DYN_ThreadLocalData");
return false;
}
ThreadLocalData* threadLocalData = reinterpret_cast<ThreadLocalData*>(tlData);
return threadLocalData->safepointState != 0;
}
void ThrowException(DYN_ObjRef exception)
{
ExceptionRef exceptionRef = static_cast<ExceptionRef>(exception);
const char* exceptionTypeName = (exceptionRef != nullptr && exceptionRef->GetTypeInfo() != nullptr)
? exceptionRef->GetTypeInfo()->GetName()
: "<null>";
DLOG(INTERPRETER, "ThrowException: exception=%p, type=%s", exceptionRef, exceptionTypeName);
ExceptionManager::ThrowException(exceptionRef);
}
void ThrowOutOfMemoryError()
{
DLOG(INTERPRETER, "ThrowOutOfMemoryError");
ExceptionManager::OutOfMemory();
ExceptionManager::ThrowPendingException();
}
DYN_ObjRef GetPendingException()
{
ExceptionRef ref = ExceptionManager::GetPendingException();
DLOG(INTERPRETER, "GetPendingException: %p", ref);
return static_cast<DYN_ObjRef>(ref);
}
DYN_ObjRef GetAndClearPendingException()
{
auto ref = GetPendingException();
ExceptionManager::ClearPendingException();
DLOG(INTERPRETER, "GetAndClearPendingException: %p", ref);
return ref;
}
bool InstanceOf(DYN_ObjRef ref, struct DYN_TypeInfo* ti)
{
DLOG(INTERPRETER, "InstanceOf: ref=%p, typeInfo=%p", ref, ti);
MObject* obj = static_cast<MObject*>(ref);
TypeInfo* tinfo = reinterpret_cast<TypeInfo*>(ti);
DLOG(INTERPRETER, " obj type is %s", obj->GetTypeInfo()->GetName());
DLOG(INTERPRETER, " type to check is %s", tinfo->GetName());
return obj->IsSubType(*tinfo);
}
bool IsSubType(struct DYN_TypeInfo* typeInfo, struct DYN_TypeInfo* superTypeInfo)
{
DLOG(INTERPRETER, "IsSubType: ti=%p, sti=%p", typeInfo, superTypeInfo);
if (typeInfo == nullptr || superTypeInfo == nullptr) {
return false;
}
if (typeInfo == superTypeInfo) {
return true;
}
TypeInfo* tInfo = reinterpret_cast<TypeInfo*>(typeInfo);
TypeInfo* sInfo = reinterpret_cast<TypeInfo*>(superTypeInfo);
return tInfo->IsSubType(sInfo);
}
DYN_ObjRef ReadStaticField(DYN_FieldRef source)
{
DLOG(INTERPRETER, "ReadStaticField %p", source);
BaseObject* res = Heap::GetBarrier().ReadStaticRef(*static_cast<RefField<false>*>(source));
return static_cast<DYN_ObjRef>(res);
}
void WriteStaticField(DYN_FieldRef destination, DYN_ObjRef new_value)
{
DLOG(INTERPRETER, "WriteStaticField %p %p", destination, new_value);
Heap::GetBarrier().WriteStaticRef(*static_cast<RefField<false>*>(destination), static_cast<BaseObject*>(new_value));
}
DYN_ObjRef ReadInstanceField(DYN_ObjRef source, DYN_FieldRef field)
{
DLOG(INTERPRETER, "ReadInstanceField %p %p", source, field);
RefField<false>& ref = *static_cast<RefField<false>*>(field);
BaseObject* res = Heap::GetBarrier().ReadReference(static_cast<BaseObject*>(source), ref);
return static_cast<DYN_ObjRef>(res);
}
void WriteInstanceField(DYN_ObjRef destination, DYN_FieldRef field, DYN_ObjRef new_value)
{
DLOG(INTERPRETER, "WriteInstanceField %p %p %p", destination, field, new_value);
RefField<false>& ref = *static_cast<RefField<false>*>(field);
Heap::GetBarrier().WriteReference(static_cast<BaseObject*>(destination), ref, static_cast<BaseObject*>(new_value));
}
DYN_ObjRef GetArrayElement(DYN_ObjRef source, U64 index)
{
DLOG(INTERPRETER, "GetArrayElement %p %llu", source, index);
MArray* array = static_cast<MArray*>(source);
return static_cast<DYN_ObjRef>(array->GetRefElement(index));
}
void SetArrayElement(DYN_ObjRef source, U64 index, DYN_ObjRef new_value)
{
DLOG(INTERPRETER, "SetArrayElement %p %llu %p", source, index, new_value);
MArray* array = static_cast<MArray*>(source);
array->SetRefElement(index, static_cast<BaseObject*>(new_value));
}
void ReadStructFieldOfObject(MAddress dstPtr, DYN_ObjRef obj, MAddress srcField, size_t size)
{
DLOG(INTERPRETER, "ReadStructFieldOfObject %p %p %p %zu", dstPtr, obj, srcField, size);
if (size == 0) {
return;
}
Heap::GetHeap().GetBarrier().ReadStruct(dstPtr, static_cast<BaseObject*>(obj), srcField, size);
}
void WriteStructFieldOfObject(DYN_ObjRef obj, MAddress dst, MAddress src, size_t size)
{
DLOG(INTERPRETER, "WriteStructFieldOfObject %p %p %p %zu", obj, dst, src, size);
CHECK_DETAIL((dst != 0u && src != 0u), "MCC_WriteStructField wrong parameter, dst: %p src: %p", dst, src);
if (UNLIKELY(!Heap::IsHeapAddress(obj))) {
CHECK_DETAIL(
memcpy_s(reinterpret_cast<void*>(dst), size, reinterpret_cast<void*>(src), size) == EOK, "memcpy_s failed");
return;
}
Heap::GetBarrier().WriteStruct(static_cast<BaseObject*>(obj), dst, size, src, size);
}
void ReadStaticStructField(uintptr_t dstPtr, size_t dstSize, uintptr_t srcPtr, size_t srcSize, DYN_GCTib tib)
{
DLOG(INTERPRETER, "ReadStaticStructField dst=%p size=%zu src=%p size=%zu tib_val=%zx", dstPtr, dstSize, srcPtr,
srcSize, static_cast<size_t>(tib.raw));
GCTib gcTib = *reinterpret_cast<GCTib*>(&tib);
Heap::GetHeap().GetBarrier().ReadStaticStruct(dstPtr, srcPtr, dstSize, gcTib);
}
void WriteStaticStructField(uintptr_t dst, size_t dstLen, uintptr_t src, size_t srcLen, DYN_GCTib tib)
{
DLOG(INTERPRETER, "WriteStaticStructField dst=%p size=%zu src=%p size=%zu tib_val=%zx", dst, dstLen, src, srcLen,
static_cast<size_t>(tib.raw));
CHECK_DETAIL((dst != 0u && src != 0u), "WriteStaticStructField wrong parameter, dst: %p src: %p", dst, src);
GCTib gcTib = *reinterpret_cast<GCTib*>(&tib);
Heap::GetBarrier().WriteStaticStruct(dst, dstLen, src, srcLen, gcTib);
}
void ReadGenericField(DYN_ObjRef dst, DYN_ObjRef srcObj, uintptr_t srcField, size_t size)
{
DLOG(INTERPRETER, "ReadGenericField dst=%p srcObj=%p srcField=%p size=%zu", dst, srcObj, srcField, size);
if (size == 0) {
return;
}
Heap::GetBarrier().ReadGeneric(
static_cast<BaseObject*>(dst), static_cast<BaseObject*>(srcObj), reinterpret_cast<void*>(srcField), size);
}
void WriteGenericField(DYN_ObjRef dstObj, uintptr_t dstField, DYN_ObjRef src, size_t size)
{
DLOG(INTERPRETER, "WriteGenericField dstObj=%p dstField=%p src=%p size=%zu", dstObj, dstField, src, size);
if (src == nullptr || size == 0) {
return;
}
Heap::GetBarrier().WriteGeneric(
static_cast<BaseObject*>(dstObj), reinterpret_cast<void*>(dstField), static_cast<BaseObject*>(src), size);
}
DYN_ThreadLocalData GetThreadLocalData()
{
return reinterpret_cast<DYN_ThreadLocalData>(MRT_GetThreadLocalData());
}
bool IsActiveGCPhase(DYN_ThreadLocalData tld)
{
ThreadLocalData* threadLocalData = static_cast<ThreadLocalData*>(tld);
Mutator* mutator = threadLocalData->mutator;
return mutator->GetMutatorPhase() >= GCPhase::GC_PHASE_ENUM;
}
DYN_ExceptionWrapper GetExceptionWrapper()
{
DLOG(INTERPRETER, "GetExceptionWrapper");
return static_cast<DYN_ExceptionWrapper>(ExceptionManager::GetExceptionWrapper());
}
extern "C" uintptr_t GetCurrentCatchFunctionPC()
{
ExceptionWrapper& eWrapper = Mutator::GetMutator()->GetExceptionWrapper();
return eWrapper.GetCurrentCatchFunctionPC();
}
void* PostThrowException(DYN_ExceptionWrapper exception_wrapper)
{
DLOG(INTERPRETER, "PostThrowException %p", exception_wrapper);
ExceptionWrapper* wrapper = static_cast<ExceptionWrapper*>(exception_wrapper);
return ExceptionManager::BeginCatch(wrapper);
}
void NativeLogger(int logLevel, char* tag, char* message)
{
VLOG(static_cast<LogType>(logLevel), "[%s] %s", tag, message);
}
size_t ComputeCJThreadDataOffset()
{
union MutatorTmpContainer {
MutatorTmpContainer()
{
}
~MutatorTmpContainer()
{
}
Mutator mutator;
} tmp;
return reinterpret_cast<size_t>(&tmp.mutator.interpreterCJThreadData) - reinterpret_cast<size_t>(&tmp.mutator);
}
void LogInterpreterParam(const InterpreterParam& interpreterParam)
{
const char* libName = interpreterParam.interpreterLibName;
const int argsCount = interpreterParam.interpreterArgsCount;
INT_InterpreterArgs args = interpreterParam.interpreterArgs;
VLOG(INTERPRETER, "Interpreter parameter:\n\tInterpreter library: %s\n\tInterpreter arguments count: %d",
libName != nullptr ? libName : "(null)", argsCount);
if (args != nullptr && argsCount > 0) {
for (int i = 0; i < argsCount; ++i) {
VLOG(INTERPRETER, "\tInterpreter argument #%d: %s", i, args[i] != nullptr ? args[i] : "(null)");
}
}
}
bool IsValidInterpreterLibName(const char* libName)
{
if (libName == nullptr || std::strlen(libName) == 0) {
DLOG(INTERPRETER, "interpreter library name is empty, interpreter could not be initialized");
return false;
}
return true;
}
void* LoadInterpreterLibrary(const char* libName)
{
#if defined(__OHOS__)
return LoaderManager::GetInstance()->LoadInterpreter(libName);
#else
return dlopen(libName, RTLD_LAZY);
#endif
}
INT_InitInterpreter ResolveInterpreterInit(void* interpreterLibHandle)
{
void* sym = dlsym(interpreterLibHandle, "interpreter_bridge_init");
if (sym == nullptr) {
DLOG(INTERPRETER, "dlsym failed: %s", dlerror());
return nullptr;
}
return reinterpret_cast<INT_InitInterpreter>(sym);
}
DYN_CJNativeInterface CreateCJNativeInterface(void* symbolHandle)
{
#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
DYN_I2NStubFn i2nStub = reinterpret_cast<DYN_I2NStubFn>(&CJ_MCC_I2NStub);
#else
DYN_I2NStubFn i2nStub = nullptr;
#endif
DYN_CJNativeInterface cjnativeInterface = {
.version = DYN_CJNATIVE_INTERFACE_VERSION,
.appLibHandle = symbolHandle,
.carrierSpecificOffset = offsetof(ThreadLocalData, mutator),
.cjThreadSpecificOffset = ComputeCJThreadDataOffset(),
.newCJThread = &NewCJThread,
.typeInfo = &TypeInfoProvider,
.typeTemplate = &FindTypeTemplate,
.getOrCreateTypeInfo = &GetOrCreateTypeInfo,
.getInstanceSize = &GetInstanceSize,
.getMTable = &GetMTable,
.getMethodOuterTI = &GetMethodOuterTI,
.updateVMT = &UpdateVMT,
.getTypeInfoUUID = &GetTypeInfoUUID,
.objectAlloc = &ObjectAllocate,
.arrayAlloc = &ArrayAllocate,
.safePoint = &SafePoint,
.isPendingSafePoint = &IsPendingSafePoint,
.throwException = &ThrowException,
.throwOom = &ThrowOutOfMemoryError,
.getPendingException = &GetPendingException,
.getAndClearPendingException = &GetAndClearPendingException,
.getExceptionWrapper = &GetExceptionWrapper,
.postThrowException = &PostThrowException,
.getCurrentCatchFunctionPc = &GetCurrentCatchFunctionPC,
.instanceOf = &InstanceOf,
.isSubType = &IsSubType,
.visitRootFromInterpreter = &VisitRootFromInterpreter,
.visitDerivedPtrFromInterpreter = &VisitDerivedPtrFromInterpreter,
.readStaticField = &ReadStaticField,
.writeStaticField = &WriteStaticField,
.readInstanceField = &ReadInstanceField,
.writeInstanceField = &WriteInstanceField,
.readStructField = &ReadStructFieldOfObject,
.writeStructField = &WriteStructFieldOfObject,
.readStaticStructField = &ReadStaticStructField,
.writeStaticStructField = &WriteStaticStructField,
.readGenericField = &ReadGenericField,
.writeGenericField = &WriteGenericField,
.arrayBodyOffset = static_cast<size_t>(MArray::GetContentOffset()),
.getArrayRefElement = &GetArrayElement,
.setArrayRefElement = &SetArrayElement,
.getThreadLocalData = &GetThreadLocalData,
.isActiveGcPhase = &IsActiveGCPhase,
.stackGrowStub = reinterpret_cast<DYN_StackGrowStubFn>(&CJ_MCC_StackGrowStub),
.i2nStub = i2nStub,
.nativeLogger = &NativeLogger,
};
return cjnativeInterface;
}
RTErrorCode InitializeInterpreterInterface(
INT_InitInterpreter init, DYN_CJNativeInterface& cjnativeInterface, const InterpreterParam& interpreterParam)
{
INT_InterpreterInterface interpreterInterface{};
interpreterInterface.version = INT_INTERPRETER_INTERFACE_VERSION;
int code = init(&interpreterInterface, &cjnativeInterface, interpreterParam.interpreterArgsCount,
interpreterParam.interpreterArgs);
if (code != 0) {
DLOG(INTERPRETER, "interpreter_bridge_init failed, return code: %d", code);
return E_FAILED;
}
if (interpreterInterface.version != INT_INTERPRETER_INTERFACE_VERSION) {
DLOG(INTERPRETER, "unsupported interpreter interface version: %lld, expected: %d",
static_cast<long long>(interpreterInterface.version), INT_INTERPRETER_INTERFACE_VERSION);
return E_FAILED;
}
g_interpreterInterface.initialize(interpreterInterface);
return E_OK;
}
RTErrorCode InitInterpreter(const InterpreterParam& interpreterParam)
{
LogInterpreterParam(interpreterParam);
const char* libName = interpreterParam.interpreterLibName;
if (!IsValidInterpreterLibName(libName)) {
return E_ARGS;
}
void* interpreterLibHandle = LoadInterpreterLibrary(libName);
if (interpreterLibHandle == nullptr) {
DLOG(INTERPRETER, "interpreter library could not be loaded: %s", dlerror());
return E_FAILED;
}
StackManager::InitAddressScopeForInterpreter(libName);
INT_InitInterpreter init = ResolveInterpreterInit(interpreterLibHandle);
if (init == nullptr) {
return E_FAILED;
}
DYN_CJNativeInterface cjnativeInterface = CreateCJNativeInterface(interpreterParam.appLibHandle);
return InitializeInterpreterInterface(init, cjnativeInterface, interpreterParam);
}
bool IsC2IStubAddr(const uintptr_t address)
{
if (!g_interpreterInterface) {
return false;
}
bool res = g_interpreterInterface->c2iStubStartAddr <= address && address < g_interpreterInterface->c2iStubEndAddr;
DLOG(INTERPRETER, "Checking c2i virtual executor borders: is %p in [%p, %p)? -- %s", address,
g_interpreterInterface->c2iStubStartAddr, g_interpreterInterface->c2iStubEndAddr, res ? "true" : "false");
return res;
}
bool IsI2IAdapterStartAddr(const uintptr_t address)
{
if (!g_interpreterInterface) {
return false;
}
bool res =
g_interpreterInterface->i2iAdapterStartAddr <= address && address < g_interpreterInterface->i2iAdapterEndAddr;
DLOG(INTERPRETER, "Checking i2i function borders: is %p in [%p, %p)? -- %s", address,
g_interpreterInterface->i2iAdapterStartAddr, g_interpreterInterface->i2iAdapterEndAddr, res ? "true" : "false");
return res;
}
bool IsI2NStubAddr(const uintptr_t address)
{
#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
uintptr_t i2nStubStartAddr = reinterpret_cast<uintptr_t>(&CJ_MCC_I2NStub);
uintptr_t i2nStubEndAddr = reinterpret_cast<uintptr_t>(&CJ_MCC_I2NStubEnd);
bool res = i2nStubStartAddr <= address && address < i2nStubEndAddr;
DLOG(INTERPRETER, "Checking I2N stub borders: is %p in [%p, %p)? -- %s", address, i2nStubStartAddr, i2nStubEndAddr,
res ? "true" : "false");
return res;
#else
DLOG(INTERPRETER, "Checking I2N stub borders: I2N not supported on this architecture");
return false;
#endif
}
bool IsInterpreterPrologueAddr(const uintptr_t address)
{
if (!g_interpreterInterface) {
return false;
}
uintptr_t startAddr = g_interpreterInterface->interpreterPrologueStartAddr;
uintptr_t endAddr = g_interpreterInterface->interpreterPrologueEndAddr;
bool hasRange = startAddr != 0 && startAddr < endAddr;
bool res = hasRange && startAddr <= address && address < endAddr;
DLOG(INTERPRETER, "Checking interpreter prologue borders: is %p in [%p, %p)? -- %s", address, startAddr, endAddr,
res ? "true" : "false");
return res;
}
uintptr_t GetCommonInterpreterLandingPad()
{
if (!g_interpreterInterface) {
return 0;
}
DLOG(INTERPRETER, "GetCommonInterpreterLandingPad: %p", g_interpreterInterface->landingPad);
return reinterpret_cast<uintptr_t>(g_interpreterInterface->landingPad);
}
}
#endif