#include "j9cel4ro64.h"
#include <assert.h>
typedef void cel4ro64_cwi_func(void*);
#pragma linkage (cel4ro64_cwi_func,OS_UPSTACK)
#define CEL4RO64_FNPTR ((cel4ro64_cwi_func *)(*(int*)((char*)(*(int*)(((char*)__gtca())+1024))+8)))
#define CEL4RO64_CEEPCBFLAG6_VALUE *((char *)(*(int *)(((char *)__gtca())+756))+84)
#define CEL4RO64_CEEPCB_3164_MASK 0x4
#pragma linkage (J9VM_STE,OS)
float J9VM_STE(void);
#pragma linkage (J9VM_STD,OS)
double J9VM_STD(void);
#pragma linkage (J9VM_LE,OS)
void J9VM_LE(float);
#pragma linkage (J9VM_LD,OS)
void J9VM_LD(double);
static void
populateArguments(uint64_t *outgoingArgs, J9_CEL4RO64_ArgType *argTypes, uint64_t *argValues, uint32_t numArgs)
{
uint32_t *lengthPtr = (uint32_t*)outgoingArgs;
*lengthPtr = sizeof(uint64_t) * numArgs;
outgoingArgs = (uint64_t *)&(lengthPtr[1]);
for (uint32_t i = 0; i < numArgs; i++) {
J9_CEL4RO64_ArgType argType = argTypes[i];
jfloat floatArg;
jdouble doubleArg;
switch(argType) {
case CEL4RO64_type_jboolean:
case CEL4RO64_type_jbyte:
case CEL4RO64_type_jchar:
case CEL4RO64_type_jshort:
case CEL4RO64_type_jint:
case CEL4RO64_type_jsize:
case CEL4RO64_type_uint32_ptr:
outgoingArgs[i] = argValues[i] & 0xFFFFFFFF;
break;
case CEL4RO64_type_jfloat:
floatArg = *(jfloat *)(&(argValues[i]));
J9VM_LE(floatArg);
break;
case CEL4RO64_type_jdouble:
doubleArg = *(jdouble *)(&(argValues[i]));
J9VM_LD(doubleArg);
break;
case CEL4RO64_type_jlong:
case CEL4RO64_type_jobject:
case CEL4RO64_type_jweak:
case CEL4RO64_type_jclass:
case CEL4RO64_type_jstring:
case CEL4RO64_type_jthrowable:
case CEL4RO64_type_jarray:
case CEL4RO64_type_jmethodID:
case CEL4RO64_type_jfieldID:
case CEL4RO64_type_JNIEnv64:
case CEL4RO64_type_JavaVM64:
outgoingArgs[i] = argValues[i];
break;
default:
break;
}
}
}
static void
populateReturnValue(J9_CEL4RO64_controlBlock *controlBlock, J9_CEL4RO64_ArgType returnType, void *returnStorage)
{
uint64_t GPR3returnValue = controlBlock->gpr3ReturnValue;
jfloat floatReturnValue;
jdouble doubleReturnValue;
switch(returnType) {
case CEL4RO64_type_jboolean:
*((jboolean *)returnStorage) = (jboolean)GPR3returnValue;
break;
case CEL4RO64_type_jbyte:
*((jbyte *)returnStorage) = (jbyte)GPR3returnValue;
break;
case CEL4RO64_type_jchar:
*((jchar *)returnStorage) = (jchar)GPR3returnValue;
break;
case CEL4RO64_type_jshort:
*((jshort *)returnStorage) = (jshort)GPR3returnValue;
break;
case CEL4RO64_type_jint:
case CEL4RO64_type_jsize:
*((jint *)returnStorage) = (jint)GPR3returnValue;
break;
case CEL4RO64_type_jfloat:
floatReturnValue = J9VM_STE();
*((jfloat *)returnStorage) = floatReturnValue;
break;
case CEL4RO64_type_jdouble:
doubleReturnValue = J9VM_STD();
*((jdouble *)returnStorage) = doubleReturnValue;
break;
case CEL4RO64_type_jlong:
case CEL4RO64_type_jobject:
case CEL4RO64_type_jweak:
case CEL4RO64_type_jclass:
case CEL4RO64_type_jstring:
case CEL4RO64_type_jthrowable:
case CEL4RO64_type_jarray:
case CEL4RO64_type_jmethodID:
case CEL4RO64_type_jfieldID:
case CEL4RO64_type_JNIEnv64:
case CEL4RO64_type_JavaVM64:
*((uint64_t*)returnStorage) = GPR3returnValue;
break;
case CEL4RO64_type_uint32_ptr:
*((uint32_t *)returnStorage) = (uint32_t)GPR3returnValue;
break;
default:
break;
}
}
uint32_t
j9_cel4ro64_call_function(
uint64_t functionDescriptor, J9_CEL4RO64_ArgType *argTypes, uint64_t *argValues, uint32_t numArgs,
J9_CEL4RO64_ArgType returnType, void *returnStorage)
{
uint32_t retcode = J9_CEL4RO64_RETCODE_OK;
uint32_t argumentAreaInBytes = (0 == numArgs) ? 0 : (sizeof(uint64_t) * numArgs + sizeof(uint32_t));
J9_CEL4RO64_controlBlock *controlBlock = NULL;
if (!j9_cel4ro64_isSupported()) {
fprintf(stderr, "CEL4RO64: %s\n", j9_cel4ro64_get_error_message(J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND));
return J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND;
}
controlBlock = (J9_CEL4RO64_controlBlock *)malloc(sizeof(J9_CEL4RO64_controlBlock) + argumentAreaInBytes);
if (NULL == controlBlock) {
retcode = J9_CEL4RO64_RETCODE_ERROR_STORAGE_ISSUE;
fprintf(stderr, "CEL4RO64: malloc failed: %s\n", j9_cel4ro64_get_error_message(retcode));
return retcode;
}
controlBlock->version = 1;
controlBlock->flags = J9_CEL4RO64_FLAG_EXECUTE_TARGET_FUNC;
controlBlock->moduleOffset = sizeof(J9_CEL4RO64_controlBlock);
controlBlock->functionOffset = sizeof(J9_CEL4RO64_controlBlock);
controlBlock->dllHandle = 0;
controlBlock->functionDescriptor = functionDescriptor;
if (0 == numArgs) {
controlBlock->argumentsOffset = 0;
} else {
uint64_t *argumentsArea = (uint64_t *)((char *)(controlBlock) + sizeof(J9_CEL4RO64_controlBlock));
controlBlock->argumentsOffset = sizeof(J9_CEL4RO64_controlBlock);
populateArguments(argumentsArea, argTypes, argValues, numArgs);
}
CEL4RO64_FNPTR(controlBlock);
retcode = controlBlock->retcode;
if ((J9_CEL4RO64_RETCODE_OK == retcode) && (CEL4RO64_type_void != returnType)) {
populateReturnValue(controlBlock, returnType, returnStorage);
}
free(controlBlock);
return retcode;
}
uint32_t
j9_cel4ro64_load_query_call_function(
const char* moduleName, const char* functionName, J9_CEL4RO64_ArgType *argTypes,
uint64_t *argValues, uint32_t numArgs, J9_CEL4RO64_ArgType returnType, void *returnStorage)
{
uint32_t retcode = J9_CEL4RO64_RETCODE_OK;
uint32_t IPBLength = 0;
uint32_t moduleNameLength = strlen(moduleName);
uint32_t functionNameLength = strlen(functionName);
uint32_t argsLength = sizeof(uint64_t) * numArgs + sizeof(uint32_t);
J9_CEL4RO64_infoBlock *infoBlock = NULL;
J9_CEL4RO64_controlBlock *controlBlock = NULL;
J9_CEL4RO64_module *moduleBlock = NULL;
J9_CEL4RO64_function *functionBlock = NULL;
if (!j9_cel4ro64_isSupported()) {
fprintf(stderr, "CEL4RO64: %s\n", j9_cel4ro64_get_error_message(J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND));
return J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND;
}
IPBLength = sizeof(J9_CEL4RO64_infoBlock) + moduleNameLength + functionNameLength + argsLength +
sizeof(moduleBlock->length) + sizeof(functionBlock->length);
infoBlock = (J9_CEL4RO64_infoBlock *) malloc(IPBLength);
if (NULL == infoBlock) {
retcode = J9_CEL4RO64_RETCODE_ERROR_STORAGE_ISSUE;
fprintf(stderr, "CEL4RO64: malloc failed: %s\n", j9_cel4ro64_get_error_message(retcode));
return retcode;
}
controlBlock = &(infoBlock->ro64ControlBlock);
controlBlock->version = 1;
controlBlock->flags = J9_CEL4RO64_FLAG_ALL_LOAD_QUERY_EXECUTE;
controlBlock->moduleOffset = sizeof(J9_CEL4RO64_controlBlock);
if (0 == moduleNameLength) {
controlBlock->functionOffset = controlBlock->moduleOffset;
} else {
controlBlock->functionOffset = controlBlock->moduleOffset + moduleNameLength + sizeof(moduleBlock->length);
}
if (0 == argsLength) {
controlBlock->argumentsOffset = 0;
} else if (0 == functionNameLength) {
controlBlock->argumentsOffset = controlBlock->functionOffset;
} else {
controlBlock->argumentsOffset = controlBlock->functionOffset + functionNameLength + sizeof(functionBlock->length);
}
moduleBlock = (J9_CEL4RO64_module *)((char *)(controlBlock) + controlBlock->moduleOffset);
infoBlock->ro64Module = moduleBlock;
moduleBlock->length = moduleNameLength;
strncpy(moduleBlock->moduleName, moduleName, moduleNameLength);
functionBlock = (J9_CEL4RO64_function *)((char *)(controlBlock) + controlBlock->functionOffset);
infoBlock->ro64Function = functionBlock;
functionBlock->length = functionNameLength;
strncpy(functionBlock->functionName, functionName, functionNameLength);
if (0 == numArgs) {
controlBlock->argumentsOffset = 0;
} else {
uint64_t *argumentsArea = (uint64_t *)((char *)(controlBlock) + controlBlock->argumentsOffset);
populateArguments(argumentsArea, argTypes, argValues, numArgs);
}
CEL4RO64_FNPTR(controlBlock);
retcode = controlBlock->retcode;
if ((J9_CEL4RO64_RETCODE_OK == retcode) && (CEL4RO64_type_void != returnType)) {
populateReturnValue(controlBlock, returnType, returnStorage);
}
free(infoBlock);
return retcode;
}
jboolean
j9_cel4ro64_isSupported(void)
{
return (CEL4RO64_CEEPCB_3164_MASK == (CEL4RO64_CEEPCBFLAG6_VALUE & CEL4RO64_CEEPCB_3164_MASK));
}
const char*
j9_cel4ro64_get_error_message(int retCode)
{
const char* errorMessage;
switch(retCode) {
case J9_CEL4RO64_RETCODE_OK:
errorMessage = "No errors detected.";
break;
case J9_CEL4RO64_RETCODE_ERROR_MULTITHREAD_INVOCATION:
errorMessage = "Multi-threaded invocation not supported.";
break;
case J9_CEL4RO64_RETCODE_ERROR_STORAGE_ISSUE:
errorMessage = "Storage issue detected.";
break;
case J9_CEL4RO64_RETCODE_ERROR_FAILED_AMODE64_ENV:
errorMessage = "Failed to initialize AMODE64 environment.";
break;
case J9_CEL4RO64_RETCODE_ERROR_FAILED_LOAD_TARGET_DLL:
errorMessage = "DLL module not found.";
break;
case J9_CEL4RO64_RETCODE_ERROR_FAILED_QUERY_TARGET_FUNC:
errorMessage = "Target function not found.";
break;
case J9_CEL4RO64_RETCODE_ERROR_LE_RUNTIME_SUPPORT_NOT_FOUND:
errorMessage = "CEL4RO64 runtime support not found.";
break;
default:
errorMessage = "Unexpected return code.";
break;
}
return errorMessage;
}