char __cdecl JavaToObjCCallHandler(DCCallback* callback, DCArgs* args, DCValue* result, void* userdata) { JavaToObjCCallInfo* info = (JavaToObjCCallInfo*)userdata; CallTempStruct* call; jobject instance = initCallHandler(args, &call, NULL, &info->fInfo); JNIEnv* env = call->env; BEGIN_TRY(env, call); call->pCallIOs = info->fInfo.fCallIOs; void* targetId = info->fNativeClass ? JLONG_TO_PTR(info->fNativeClass) : getNativeObjectPointer(env, instance, NULL); void* callback = //objc_msgSend_stret;// objc_msgSend; #if defined(DC__Arch_Intel_x86) switch (info->fInfo.fReturnType) { case eDoubleValue: case eFloatValue: callback = objc_msgSend_fpret; break; } #endif dcMode(call->vm, info->fInfo.fDCMode); dcArgPointer(call->vm, targetId); dcArgPointer(call->vm, info->fSelector); followArgs(call, args, info->fInfo.nParams, info->fInfo.fParamTypes, JNI_FALSE, JNI_TRUE)// TODO isVarArgs ?? && followCall(call, info->fInfo.fReturnType, result, callback, JNI_FALSE, JNI_FALSE); cleanupCallHandler(call); END_TRY_BASE(info->fInfo.fEnv, call, cleanupCallHandler(call););
void __cdecl CToJavaCallHandler_Sub(CallTempStruct* call, NativeToJavaCallbackCallInfo* info, DCArgs* args, DCValue* result) { dcMode(call->vm, JNI_CALL_MODE); //dcReset(call->vm); if (!info->fCallbackInstance) { throwException(call->env, "Trying to call a null callback instance !"); return; } dcArgPointer(call->vm, (DCpointer)call->env); dcArgPointer(call->vm, info->fCallbackInstance); dcArgPointer(call->vm, info->fInfo.fMethodID); if (info->fIsObjCBlock) dcbArgPointer(args); // consume the pointer to the block instance ; TODO use it to reuse native callbacks !!! if (info->fIsGenericCallback) { callGenericFunction(call, &info->fInfo, args, result, (void*)(*call->env)->CallObjectMethod); } else { callFunction(call, &info->fInfo, args, result, info->fJNICallFunction, CALLING_JAVA | IS_VAR_ARGS); } }
float forwardCaller(void* cb, float value) { DCCallVM* vm = dcNewCallVM(1024); dcReset(vm); dcArgPointer(vm, NULL); dcArgPointer(vm, NULL); dcArgPointer(vm, cb); dcArgFloat(vm, value); float res = dcCallFloat(vm, forwardFloatCall); dcFree(vm); return res; }
char __cdecl CToJavaCallHandler(DCCallback* callback, DCArgs* args, DCValue* result, void* userdata) { CallTempStruct* call; jthrowable exc; NativeToJavaCallbackCallInfo* info = (NativeToJavaCallbackCallInfo*)userdata; JNIEnv *env = GetEnv(); initCallHandler(NULL, &call, env); BEGIN_TRY(env, call); call->pCallIOs = info->fInfo.fCallIOs; dcMode(call->vm, JNI_CALL_MODE); if (!info->fCallbackInstance) { throwException(env, "Trying to call a null callback instance !"); cleanupCallHandler(call); return info->fInfo.fDCReturnType; } if (0) { float value = dcbArgFloat(args); float ret = (*call->env)->CallFloatMethod(call->env, info->fCallbackInstance, info->fMethod, value); result->f = ret; } else { dcArgPointer(call->vm, (DCpointer)call->env); dcArgPointer(call->vm, info->fCallbackInstance); dcArgPointer(call->vm, info->fMethod); if (info->fIsGenericCallback) { followArgsGenericJavaCallback(call, args, info->fInfo.nParams, info->fInfo.fParamTypes) && followCallGenericJavaCallback(call, info->fInfo.fReturnType, result, (void*)(*env)->CallObjectMethod); } else { followArgs(call, args, info->fInfo.nParams, info->fInfo.fParamTypes, JNI_TRUE, JNI_TRUE) && followCall(call, info->fInfo.fReturnType, result, info->fJNICallFunction, JNI_TRUE, JNI_FALSE); } exc = (*env)->ExceptionOccurred(env); if (exc) { (*env)->ExceptionDescribe(env); printStackTrace(env, exc); //(*env)->ExceptionClear(env); } } cleanupCallHandler(call); END_TRY_BASE(info->fInfo.fEnv, call, cleanupCallHandler(call););
int syscall_write(int fd, char* buf, size_t len) { dcReset(callvm); dcArgInt(callvm, fd); dcArgPointer(callvm, buf); dcArgInt(callvm, len); return dcCallInt(callvm, (DCpointer)(ptrdiff_t)SYS_write); }
void __cdecl CPPToJavaCallHandler_Sub(CallTempStruct* call, NativeToJavaCallbackCallInfo* info, DCArgs* args, DCValue* result) { void* cppObject; jobject javaObject; dcMode(call->vm, JNI_CALL_MODE); //dcReset(call->vm); if (info->fCallbackInstance) { throwException(call->env, "Not expecting a callback instance here !"); return; } cppObject = dcbArgPointer(args); javaObject = getJavaObjectForNativePointer(call->env, cppObject); dcArgPointer(call->vm, (DCpointer)call->env); dcArgPointer(call->vm, javaObject); dcArgPointer(call->vm, info->fInfo.fMethodID); callFunction(call, &info->fInfo, args, result, info->fJNICallFunction, CALLING_JAVA | IS_VAR_ARGS); }
void callSinglePointerArgVoidFunction(JNIEnv* env, void* constructor, void* thisPtr, int callMode) { CallTempStruct* call; initCallHandler(NULL, &call, env, NULL); dcMode(call->vm, callMode); //dcReset(call->vm); dcArgPointer(call->vm, thisPtr); dcCallVoid(call->vm, constructor); cleanupCallHandler(call); }
void dcArgStructUnroll(DCCallVM* vm, DCstruct* s, DCpointer value) { DCsize i; /*printf("UNROLLING STRUCT !\n");@@@*/ assert(s && value); for (i = 0; i < s->fieldCount; i++) { DCfield *f = s->pFields + i; DCpointer p = (char*)value + f->offset; switch(f->type) { case DC_SIGCHAR_STRUCT: dcArgStruct(vm, f->pSubStruct, p); break; case DC_SIGCHAR_BOOL: dcArgBool (vm, *(DCbool*)p); break; case DC_SIGCHAR_CHAR: case DC_SIGCHAR_UCHAR: dcArgChar (vm, *(DCchar*)p); break; case DC_SIGCHAR_SHORT: case DC_SIGCHAR_USHORT: dcArgShort (vm, *(DCshort*)p); break; case DC_SIGCHAR_INT: case DC_SIGCHAR_UINT: dcArgInt (vm, *(DCint*)p); break; case DC_SIGCHAR_LONG: case DC_SIGCHAR_ULONG: dcArgLong (vm, *(DCulong*)p); break; case DC_SIGCHAR_LONGLONG: case DC_SIGCHAR_ULONGLONG: dcArgLongLong (vm, *(DCulonglong*)p); break; case DC_SIGCHAR_FLOAT: dcArgFloat (vm, *(DCfloat*)p); break; case DC_SIGCHAR_DOUBLE: dcArgDouble (vm, *(DCdouble*)p); break; case DC_SIGCHAR_POINTER: case DC_SIGCHAR_STRING: dcArgPointer (vm, *(DCpointer**)p); break; default: assert(0); } } }
// Shareable implementation for argument binding used in ArgF and CallF below. static void dcArgF_impl(DCCallVM* vm, const DCsigchar** sigptr, va_list args) { DCsigchar ch; dcReset(vm); while((ch=*(*sigptr)++) != '\0' && ch != DC_SIGCHAR_ENDARG) { switch(ch) { case DC_SIGCHAR_BOOL: dcArgBool (vm, (DCbool) va_arg(args, DCint )); break; case DC_SIGCHAR_CHAR: dcArgChar (vm, (DCchar) va_arg(args, DCint )); break; case DC_SIGCHAR_UCHAR: dcArgChar (vm, (DCchar)(DCuchar) va_arg(args, DCint )); break; case DC_SIGCHAR_SHORT: dcArgShort (vm, (DCshort) va_arg(args, DCint )); break; case DC_SIGCHAR_USHORT: dcArgShort (vm, (DCshort)(DCushort)va_arg(args, DCint )); break; case DC_SIGCHAR_INT: dcArgInt (vm, (DCint) va_arg(args, DCint )); break; case DC_SIGCHAR_UINT: dcArgInt (vm, (DCint)(DCuint) va_arg(args, DCint )); break; case DC_SIGCHAR_LONG: dcArgLong (vm, (DClong) va_arg(args, DClong )); break; case DC_SIGCHAR_ULONG: dcArgLong (vm, (DCulong) va_arg(args, DClong )); break; case DC_SIGCHAR_LONGLONG: dcArgLongLong(vm, (DClonglong) va_arg(args, DClonglong)); break; case DC_SIGCHAR_ULONGLONG: dcArgLongLong(vm, (DCulonglong) va_arg(args, DClonglong)); break; case DC_SIGCHAR_FLOAT: dcArgFloat (vm, (DCfloat) va_arg(args, DCdouble )); break; case DC_SIGCHAR_DOUBLE: dcArgDouble (vm, (DCdouble) va_arg(args, DCdouble )); break; case DC_SIGCHAR_POINTER: dcArgPointer (vm, (DCpointer) va_arg(args, DCpointer )); break; case DC_SIGCHAR_STRING: dcArgPointer (vm, (DCpointer) va_arg(args, DCpointer )); break; } } }
void JavaToVirtualMethodCallHandler_Sub(CallTempStruct* call, VirtualMethodCallInfo* info, jobject instance, DCArgs* args, DCValue* result) { void* callbackFn; void* thisPtr; int nParams = info->fInfo.nParams; ValueType *pParamTypes = info->fInfo.fParamTypes; dcMode(call->vm, info->fInfo.fDCMode); //dcReset(call->vm); if (info->fHasThisPtrArg) { if (nParams == 0 || *pParamTypes != eSizeTValue) { throwException(call->env, "A C++ method must be bound with a method having a first argument of type long !"); return; } thisPtr = dcbArgPointer(args); if (!thisPtr) { throwException(call->env, "Calling a method on a NULL C++ class pointer !"); return; } nParams--; pParamTypes++; } else { thisPtr = getNativeObjectPointer(call->env, instance, info->fClass); if (!thisPtr) { throwException(call->env, "Failed to get the pointer to the target C++ instance of the method invocation !"); return; } //nParams--; //pParamTypes++; } callbackFn = getNthVirtualMethodFromThis(call->env, thisPtr, info->fVirtualTableOffset, info->fVirtualIndex); if (!callbackFn) { throwException(call->env, "Virtual method pointer found in virtual table is NULL !"); return; } dcArgPointer(call->vm, thisPtr); followArgs(call, args, nParams, pParamTypes, NO_FLAGS) && followCall(call, info->fInfo.fReturnType, result, callbackFn, NO_FLAGS); }
void JavaToCPPMethodCallHandler_Sub(CallTempStruct* call, FunctionCallInfo* info, jobject instance, DCArgs* args, DCValue* result) { void* thisPtr; dcMode(call->vm, info->fInfo.fDCMode); //dcReset(call->vm); thisPtr = getNativeObjectPointer(call->env, instance, info->fClass); if (!thisPtr) { throwException(call->env, "Failed to get the pointer to the target C++ instance of the method invocation !"); return; } dcArgPointer(call->vm, thisPtr); callFunction(call, &info->fInfo, args, result, info->fForwardedSymbol, 0); }
jboolean followArgs(CallTempStruct* call, DCArgs* args, int nTypes, ValueType* pTypes, jboolean toJava, jboolean isVarArgs) { JNIEnv* env = call->env; int iParam; //printf("ARGS : %d args\n", (int)nTypes); for (iParam = 0; iParam < nTypes; iParam++) { ValueType type = pTypes[iParam]; switch (type) { case eIntFlagSet: { jobject callIO = call && call->pCallIOs ? *(call->pCallIOs++) : NULL; if (toJava) { int flags = dcbArgInt(args); jobject obj = createPointerFromIO(env, JLONG_TO_PTR ((jlong)flags), callIO); dcArgPointer(call->vm, obj); } else { int arg = (jint)getFlagValue(env, (jobject)dcbArgPointer(args)); if (isVarArgs) dcArgPointer(call->vm, (void*)(ptrdiff_t)arg); else dcArgInt(call->vm, arg); } } break; case eIntValue: { int arg = dcbArgInt(args); if (isVarArgs) dcArgPointer(call->vm, (void*)(ptrdiff_t)arg); else dcArgInt(call->vm, arg); } break; #define ARG_BOXED_INTEGRAL(type, capitalized) \ { \ if (toJava) { \ type arg = (sizeof(type) == 4) ? (type)dcbArgInt(args) : (type)dcbArgLongLong(args); \ dcArgPointer(call->vm, Box ## capitalized(env, arg)); \ } else { \ jobject parg = dcbArgPointer(args); \ jlong arg = Unbox ## capitalized(env, parg); \ if (isVarArgs) \ dcArgPointer(call->vm, (void*)(ptrdiff_t)arg); \ else if (sizeof(type) == 4) \ dcArgInt(call->vm, (jint)arg); \ else \ dcArgLongLong(call->vm, (jlong)arg); \ } \ } #define ARG_UNBOXED_INTEGRAL(type, capitalized) \ { \ if (toJava) { \ type arg = (sizeof(type) == 4) ? (type)dcbArgInt(args) : (type)dcbArgLongLong(args); \ dcArgLongLong(call->vm, (jlong)arg); \ } else { \ jlong arg = dcbArgLongLong(args); \ if (isVarArgs) \ dcArgPointer(call->vm, (void*)(ptrdiff_t)arg); \ else if (sizeof(type) == 4) \ dcArgInt(call->vm, (jint)arg); \ else \ dcArgLongLong(call->vm, (jlong)arg); \ } \ } case eCLongValue: ARG_UNBOXED_INTEGRAL(long, CLong); break; case eSizeTValue: ARG_UNBOXED_INTEGRAL(size_t, SizeT); break; case eCLongObjectValue: ARG_BOXED_INTEGRAL(long, CLong); break; case eSizeTObjectValue: ARG_BOXED_INTEGRAL(size_t, SizeT); break; case eTimeTObjectValue: ARG_BOXED_INTEGRAL(time_t, TimeT); break; case eLongValue: dcArgLongLong(call->vm, dcbArgLongLong(args)); break; case eShortValue: { short arg = dcbArgShort(args); if (isVarArgs) dcArgPointer(call->vm, (void*)(ptrdiff_t)arg); else dcArgShort(call->vm, arg); } break; case eBooleanValue: case eByteValue: { char arg = dcbArgChar(args); if (isVarArgs) dcArgPointer(call->vm, (void*)(ptrdiff_t)arg); else dcArgChar(call->vm, arg); } break; case eFloatValue: { float arg = dcbArgFloat(args); if (isVarArgs) dcArgDouble(call->vm, arg); else dcArgFloat(call->vm, arg); } break; case eDoubleValue: dcArgDouble(call->vm, dcbArgDouble(args)); break; case ePointerValue: { void* ptr = dcbArgPointer(args); jobject callIO = call && call->pCallIOs ? *(call->pCallIOs++) : NULL; if (toJava) { ptr = createPointerFromIO(env, ptr, callIO); } else { ptr = ptr ? getPointerPeer(env, ptr) : NULL; // printf("ARG POINTER = %d\n", ptr); } dcArgPointer(call->vm, ptr); } break; case eWCharValue: switch (sizeof(wchar_t)) { case 1: dcArgChar(call->vm, dcbArgChar(args)); break; case 2: dcArgShort(call->vm, dcbArgShort(args)); break; case 4: dcArgInt(call->vm, dcbArgInt(args)); break; default: throwException(env, "Invalid wchar_t size for argument !"); return JNI_FALSE; } break; case eEllipsis: { if (toJava) { throwException(env, "Calling Java ellipsis is not supported yet !"); return JNI_FALSE; } else { jobjectArray arr = (jobjectArray)dcbArgPointer(args); jsize n = (*env)->GetArrayLength(env, arr), i; for (i = 0; i < n; i++) { jobject arg = (*env)->GetObjectArrayElement(env, arr, i); #define TEST_INSTANCEOF(cl, st) \ if ((*env)->IsInstanceOf(env, arg, cl)) st; if (arg == NULL) dcArgPointer(call->vm, getPointerPeer(env, (void*)NULL)); else // As per the C standard for varargs, all ints are promoted to ptrdiff_t and float is promoted to double : TEST_INSTANCEOF(gIntClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)UnboxInt(env, arg))) else TEST_INSTANCEOF(gLongClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)UnboxLong(env, arg))) else TEST_INSTANCEOF(gShortClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)UnboxShort(env, arg))) else TEST_INSTANCEOF(gByteClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)UnboxByte(env, arg))) else TEST_INSTANCEOF(gBooleanClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)(char)UnboxBoolean(env, arg))) else TEST_INSTANCEOF(gCharClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)(short)UnboxChar(env, arg))) else TEST_INSTANCEOF(gDoubleClass, dcArgDouble(call->vm, UnboxDouble(env, arg))) else TEST_INSTANCEOF(gFloatClass, dcArgDouble(call->vm, UnboxFloat(env, arg))) else TEST_INSTANCEOF(gCLongClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)(long)UnboxCLong(env, arg))) else TEST_INSTANCEOF(gSizeTClass, dcArgPointer(call->vm, (void*)(ptrdiff_t)UnboxSizeT(env, arg))) else TEST_INSTANCEOF(gPointerClass, dcArgPointer(call->vm, getPointerPeer(env, (void*)arg))) else { throwException(env, "Invalid value type in ellipsis"); return JNI_FALSE; } } } break; } default: throwException(env, "Invalid argument value type !"); return JNI_FALSE; } } if ((*env)->ExceptionCheck(env)) return JNI_FALSE; return JNI_TRUE; }
int invoke(char const* signature, void* t) { DCCallVM * p = (DCCallVM*) G_callvm; char const * sig = signature; char rtype; char atype; int pos = 0; int s = 0; clear_V(); rtype = *sig++; dcReset(p); while ( (atype = *sig++) != '\0') { pos++; switch(atype) { case 'c': dcArgChar (p,K_c[pos]); break; case 's': dcArgShort (p,K_s[pos]); break; case 'i': dcArgInt (p,K_i[pos]); break; case 'j': dcArgLong (p,K_j[pos]); break; case 'l': dcArgLongLong(p,K_l[pos]); break; case 'p': dcArgPointer (p,K_p[pos]); break; case 'f': dcArgFloat (p,K_f[pos]); break; case 'd': dcArgDouble (p,K_d[pos]); break; default: printf("unknown atype '%c' (1) ;", atype); return 0; } } switch(rtype) { case 'v': dcCallVoid(p,t); s=1; /*TODO:check that no return-arg was touched.*/ break; case 'c': s = (dcCallChar (p,t) == K_c[pos]) ; break; case 's': s = (dcCallShort (p,t) == K_s[pos]) ; break; case 'i': s = (dcCallInt (p,t) == K_i[pos]) ; break; case 'j': s = (dcCallLong (p,t) == K_j[pos]) ; break; case 'l': s = (dcCallLongLong(p,t) == K_l[pos]) ; break; case 'p': s = (dcCallPointer (p,t) == K_p[pos]) ; break; case 'f': s = (dcCallFloat (p,t) == K_f[pos]) ; break; case 'd': s = (dcCallDouble (p,t) == K_d[pos]) ; break; default: printf("unknown rtype '%c'", rtype); return 0; } if (!s) { printf("rval wrong;"); return 0; } /* test: */ sig = signature+1; pos = 1; while ( (atype = *sig++) != '\0') { switch(atype) { #if 0 #define X(CH,T,QCH) case QCH: s = (V_##CH[pos] == K_##CH[pos]); break; DEF_TYPES #undef X #endif case 'c': s = ( V_c[pos] == K_c[pos] ); if (!s) printf("'c':%d: %d != %d ; ", pos, V_c[pos], K_c[pos]); break; case 's': s = ( V_s[pos] == K_s[pos] ); if (!s) printf("'s':%d: %d != %d ; ", pos, V_s[pos], K_s[pos]); break; case 'i': s = ( V_i[pos] == K_i[pos] ); if (!s) printf("'i':%d: %d != %d ; ", pos, V_i[pos], K_i[pos]); break; case 'j': s = ( V_j[pos] == K_j[pos] ); if (!s) printf("'j':%d: %ld != %ld ; ", pos, V_j[pos], K_j[pos]); break; case 'l': s = ( V_l[pos] == K_l[pos] ); if (!s) printf("'l':%d: %lld != %lld ; ", pos, V_l[pos], K_l[pos]); break; case 'p': s = ( V_p[pos] == K_p[pos] ); if (!s) printf("'p':%d: %lld != %lld ; ", pos, (long long) V_p[pos], (long long) K_p[pos]); break; case 'f': s = ( V_f[pos] == K_f[pos] ); if (!s) printf("'f':%d: %f != %f ; ", pos, V_f[pos], K_f[pos]); break; case 'd': s = ( V_d[pos] == K_d[pos] ); if (!s) printf("'d':%d: %f != %f ; ", pos, V_d[pos], K_d[pos]); break; default: printf("unknown atype '%c' ; ", atype); return 0; } if (!s) { printf("arg mismatch at %d ; ", pos); return 0; } pos++; } return 1; }
/* libcall(const libname[], const funcname[], const typestring[], ...) * * Loads the DLL or shared library if not yet loaded (the name comparison is * case sensitive). * * typestring format: * Whitespace is permitted between the types, but not inside the type * specification. The string "ii[4]&u16s" is equivalent to "i i[4] &u16 s", * but the latter is easier on the eye. * * types: * i = signed integer, 16-bit in Windows 3.x, else 32-bit in Win32 and Linux * u = unsigned integer, 16-bit in Windows 3.x, else 32-bit in Win32 and Linux * f = IEEE floating point, 32-bit * p = packed string * s = unpacked string * The difference between packed and unpacked strings is only relevant when * the parameter is passed by reference (see below). * * pass-by-value and pass-by-reference: * By default, parameters are passed by value. To pass a parameter by * reference, prefix the type letter with an "&": * &i = signed integer passed by reference * i = signed integer passed by value * Same for '&u' versus 'u' and '&f' versus 'f'. * * Arrays are passed by "copy & copy-back". That is, libcall() allocates a * block of dynamic memory to copy the array into. On return from the foreign * function, libcall() copies the array back to the abstract machine. The * net effect is similar to pass by reference, but the foreign function does * not work in the AMX stack directly. During the copy and the copy-back * operations, libcall() may also transform the array elements, for example * between 16-bit and 32-bit elements. This is done because Pawn only * supports a single cell size, which may not fit the required integer size * of the foreign function. * * See "element ranges" for the syntax of passing an array. * * Strings may either be passed by copy, or by "copy & copy-back". When the * string is an output parameter (for the foreign function), the size of the * array that will hold the return string must be indicated between square * brackets behind the type letter (see "element ranges"). When the string * is "input only", this is not needed --libcall() will determine the length * of the input string itself. * * The tokens 'p' and 's' are equivalent, but 'p[10]' and 's[10]' are not * equivalent: the latter syntaxes determine whether the output from the * foreign function will be stored as a packed or an unpacked string. * * element sizes: * Add an integer behind the type letter; for example, 'i16' refers to a * 16-bit signed integer. Note that the value behind the type letter must * be either 8, 16 or 32. * * You should only use element size specifiers on the 'i' and 'u' types. That * is, do not use these specifiers on 'f', 's' and 'p'. * * element ranges: * For passing arrays, the size of the array may be given behind the type * letter and optional element size. The token 'u[4]' indicates an array of * four unsigned integers, which are typically 32-bit. The token 'i16[8]' * is an array of 8 signed 16-bit integers. Arrays are always passed by * "copy & copy-back" * * When compiled as Unicode, this library converts all strings to Unicode * strings. * * The calling convention for the foreign functions is assumed: * - "__stdcall" for Win32, * - "far pascal" for Win16 * - and the GCC default for Unix/Linux (_cdecl) * * C++ name mangling of the called function is not handled (there is no standard * convention for name mangling, so there is no portable way to convert C++ * function names to mangled names). Win32 name mangling (used by default by * Microsoft compilers on functions declared as __stdcall) is also not handled. * * Returns the value of the called function. */ static cell AMX_NATIVE_CALL n_libcall(AMX *amx, const cell *params) { const TCHAR *libname, *funcname, *typestring; MODLIST *item; int paramidx, typeidx, idx; PARAM ps[MAXPARAMS]; cell *cptr,result; LIBFUNC LibFunc; amx_StrParam(amx, params[1], libname); item = findlib(&ModRoot, amx, libname); if (item == NULL) item = addlib(&ModRoot, amx, libname); if (item == NULL) { amx_RaiseError(amx, AMX_ERR_NATIVE); return 0; } /* if */ /* library is loaded, get the function */ amx_StrParam(amx, params[2], funcname); LibFunc=(LIBFUNC)SearchProcAddress(item->inst, funcname); if (LibFunc==NULL) { amx_RaiseError(amx, AMX_ERR_NATIVE); return 0; } /* if */ #if defined HAVE_DYNCALL_H /* (re-)initialize the dyncall library */ if (dcVM==NULL) { dcVM=dcNewCallVM(4096); dcMode(dcVM,DC_CALL_C_X86_WIN32_STD); } /* if */ dcReset(dcVM); #endif /* decode the parameters */ paramidx=typeidx=0; amx_StrParam(amx, params[3], typestring); while (paramidx < MAXPARAMS && typestring[typeidx]!=__T('\0')) { /* skip white space */ while (typestring[typeidx]!=__T('\0') && typestring[typeidx]<=__T(' ')) typeidx++; if (typestring[typeidx]==__T('\0')) break; /* save "pass-by-reference" token */ ps[paramidx].type=0; if (typestring[typeidx]==__T('&')) { ps[paramidx].type=BYREF; typeidx++; } /* if */ /* store type character */ ps[paramidx].type |= (unsigned char)typestring[typeidx]; typeidx++; /* set default size, then check for an explicit size */ #if defined __WIN32__ || defined _WIN32 || defined WIN32 ps[paramidx].size=32; #elif defined _Windows ps[paramidx].size=16; #endif if (_istdigit(typestring[typeidx])) { ps[paramidx].size=(unsigned char)_tcstol(&typestring[typeidx],NULL,10); while (_istdigit(typestring[typeidx])) typeidx++; } /* if */ /* set default range, then check for an explicit range */ ps[paramidx].range=1; if (typestring[typeidx]=='[') { ps[paramidx].range=_tcstol(&typestring[typeidx+1],NULL,10); while (typestring[typeidx]!=']' && typestring[typeidx]!='\0') typeidx++; ps[paramidx].type |= BYREF; /* arrays are always passed by reference */ typeidx++; /* skip closing ']' too */ } /* if */ /* get pointer to parameter */ cptr=amx_Address(amx,params[paramidx+4]); switch (ps[paramidx].type) { case 'i': /* signed integer */ case 'u': /* unsigned integer */ case 'f': /* floating point */ assert(ps[paramidx].range==1); ps[paramidx].v.val=(int)*cptr; break; case 'i' | BYREF: case 'u' | BYREF: case 'f' | BYREF: ps[paramidx].v.ptr=cptr; if (ps[paramidx].range>1) { /* convert array and pass by address */ ps[paramidx].v.ptr = fillarray(amx, &ps[paramidx], cptr); } /* if */ break; case 'p': case 's': case 'p' | BYREF: case 's' | BYREF: if (ps[paramidx].type=='s' || ps[paramidx].type=='p') { int len; /* get length of input string */ amx_StrLen(cptr,&len); len++; /* include '\0' */ /* check max. size */ if (len<ps[paramidx].range) len=ps[paramidx].range; ps[paramidx].range=len; } /* if */ ps[paramidx].v.ptr=malloc(ps[paramidx].range*sizeof(TCHAR)); if (ps[paramidx].v.ptr==NULL) return amx_RaiseError(amx, AMX_ERR_NATIVE); amx_GetString((char *)ps[paramidx].v.ptr,cptr,sizeof(TCHAR)>1,UNLIMITED); break; default: /* invalid parameter type */ return amx_RaiseError(amx, AMX_ERR_NATIVE); } /* switch */ paramidx++; } /* while */ if ((params[0]/sizeof(cell)) - 3 != (size_t)paramidx) return amx_RaiseError(amx, AMX_ERR_NATIVE); /* format string does not match number of parameters */ #if defined HAVE_DYNCALL_H for (idx = 0; idx < paramidx; idx++) { if ((ps[idx].type=='i' || ps[idx].type=='u' || ps[idx].type=='f') && ps[idx].range==1) { switch (ps[idx].size) { case 8: dcArgChar(dcVM,(unsigned char)(ps[idx].v.val & 0xff)); break; case 16: dcArgShort(dcVM,(unsigned short)(ps[idx].v.val & 0xffff)); break; default: dcArgLong(dcVM,ps[idx].v.val); } /* switch */ } else { dcArgPointer(dcVM,ps[idx].v.ptr); } /* if */ } /* for */ result=(cell)dcCallPointer(dcVM,(void*)LibFunc); #else /* HAVE_DYNCALL_H */ /* push the parameters to the stack (left-to-right in 16-bit; right-to-left * in 32-bit) */ #if defined __WIN32__ || defined _WIN32 || defined WIN32 for (idx=paramidx-1; idx>=0; idx--) { #else for (idx=0; idx<paramidx; idx++) { #endif if ((ps[idx].type=='i' || ps[idx].type=='u' || ps[idx].type=='f') && ps[idx].range==1) { switch (ps[idx].size) { case 8: push((unsigned char)(ps[idx].v.val & 0xff)); break; case 16: push((unsigned short)(ps[idx].v.val & 0xffff)); break; default: push(ps[idx].v.val); } /* switch */ } else { push(ps[idx].v.ptr); } /* if */ } /* for */ /* call the function; all parameters are already pushed to the stack (the * function should remove the parameters from the stack) */ result=LibFunc(); #endif /* HAVE_DYNCALL_H */ /* store return values and free allocated memory */ for (idx=0; idx<paramidx; idx++) { switch (ps[idx].type) { case 'p': case 's': free(ps[idx].v.ptr); break; case 'p' | BYREF: case 's' | BYREF: cptr=amx_Address(amx,params[idx+4]); amx_SetString(cptr,(char *)ps[idx].v.ptr,ps[idx].type==('p'|BYREF),sizeof(TCHAR)>1,UNLIMITED); free(ps[idx].v.ptr); break; case 'i': case 'u': case 'f': assert(ps[idx].range==1); break; case 'i' | BYREF: case 'u' | BYREF: case 'f' | BYREF: cptr=amx_Address(amx,params[idx+4]); if (ps[idx].range==1) { /* modify directly in the AMX (no memory block was allocated */ switch (ps[idx].size) { case 8: *cptr= (ps[idx].type==('i' | BYREF)) ? (long)((signed char)*cptr) : (*cptr & 0xff); break; case 16: *cptr= (ps[idx].type==('i' | BYREF)) ? (long)((short)*cptr) : (*cptr & 0xffff); break; } /* switch */ } else { int i; for (i=0; i<ps[idx].range; i++) { switch (ps[idx].size) { case 8: *cptr= (ps[idx].type==('i' | BYREF)) ? ((signed char*)ps[idx].v.ptr)[i] : ((unsigned char*)ps[idx].v.ptr)[i]; break; case 16: *cptr= (ps[idx].type==('i' | BYREF)) ? ((short*)ps[idx].v.ptr)[i] : ((unsigned short*)ps[idx].v.ptr)[i]; break; default: *cptr= (ps[idx].type==('i' | BYREF)) ? ((long*)ps[idx].v.ptr)[i] : ((unsigned long*)ps[idx].v.ptr)[i]; } /* switch */ } /* for */ free((char *)ps[idx].v.ptr); } /* if */ break; default: assert(0); } /* switch */ } /* for */ return result; } /* bool: libfree(const libname[]="") * When the name is an empty string, this function frees all libraries (for this * abstract machine). The name comparison is case sensitive. * Returns true if one or more libraries were freed. */ static cell AMX_NATIVE_CALL n_libfree(AMX *amx, const cell *params) { const TCHAR *libname; amx_StrParam(amx,params[1],libname); return freelib(&ModRoot,amx,libname) > 0; } #else /* HAVE_DYNCALL_H || WIN32_FFI */ static cell AMX_NATIVE_CALL n_libcall(AMX *amx, const cell *params) { (void)amx; (void)params; return 0; }
static PyObject* pydc_call(PyObject* self, PyObject* in_args) { PyObject* pcobj_funcptr; const char* signature; PyObject* args; int l; const char* ptr; char ch; int pos; void* pfunc; if ( !PyArg_ParseTuple(in_args,"OsO", &pcobj_funcptr, &signature, &args) ) return PyErr_Format(PyExc_RuntimeError, "argument mismatch"); pfunc = PyCObject_AsVoidPtr(pcobj_funcptr); if ( !pfunc ) return PyErr_Format( PyExc_RuntimeError, "function pointer is NULL" ); l = PyTuple_Size(args); ptr = signature; pos = 0; dcReset(gpCall); while ( (ch = *ptr) != '\0' && ch != ')' ) { PyObject* po; int index = pos+1; if (pos > l) return PyErr_Format( PyExc_RuntimeError, "expecting more arguments" ); po = PyTuple_GetItem(args,pos); switch(ch) { case DC_SIGCHAR_BOOL: { DCbool b; if ( !PyBool_Check(po) ) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting a bool", index ); b = (Py_True == po) ? DC_TRUE : DC_FALSE; dcArgBool(gpCall, b); } break; case DC_SIGCHAR_CHAR: { DCchar c; if ( PyString_Check(po) ) { // Py_ssize_t l; size_t l; char* s; l = PyString_GET_SIZE(po); if (l != 1) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting a string with length of 1 (a char string)", index ); s = PyString_AsString(po); c = (DCchar) s[0]; } else if ( PyInt_Check(po) ) { long l; l = PyInt_AsLong(po); if ( (l > CHAR_MAX) || (l < CHAR_MIN)) return PyErr_Format( PyExc_RuntimeError, "value out of range at argument %d - expecting a char code", index ); c = (DCchar) l; } else return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting a char", index ); dcArgChar(gpCall, c); } break; case DC_SIGCHAR_SHORT: { DCshort s; long v; if ( !PyInt_Check(po) ) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting a short int", index ); v = PyInt_AS_LONG(po); if ( (v < SHRT_MIN) || (v > SHRT_MAX) ) return PyErr_Format( PyExc_RuntimeError, "value out of range at argument %d - expecting a short value", index ); s = (DCshort) v; dcArgShort(gpCall, s); } break; case DC_SIGCHAR_INT: { long v; if ( !PyInt_Check(po) ) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting an int", index ); v = PyInt_AS_LONG(po); dcArgInt(gpCall, (DCint) v ); } break; case DC_SIGCHAR_LONG: { long v; if ( !PyInt_Check(po) ) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting an int", index ); v = PyInt_AsLong(po); } break; case DC_SIGCHAR_LONGLONG: { PY_LONG_LONG pl; DClonglong dl; if ( !PyLong_Check(po) ) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting a long long", index ); pl = PyLong_AsLongLong(po); dl = (DClonglong) pl; dcArgLongLong(gpCall, dl ); } break; case DC_SIGCHAR_FLOAT: { DCfloat f; if (!PyFloat_Check(po)) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expeecting a float", index ); f = (float) PyFloat_AsDouble(po); dcArgFloat(gpCall, f); } break; case DC_SIGCHAR_DOUBLE: { double d; if (!PyFloat_Check(po)) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expeecting a float", index ); d = PyFloat_AsDouble(po); dcArgDouble(gpCall, d); } break; case DC_SIGCHAR_POINTER: { DCpointer ptr; if ( PyString_Check(po) ) { ptr = (DCpointer) PyString_AsString(po); } else if ( PyLong_Check(po) ) { ptr = (DCpointer) ( (DCint) PyLong_AsLongLong(po) ); } else { return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting a promoting pointer-type (int,string)", index ); } dcArgPointer(gpCall, ptr ); } break; case 'S': { char* p; if (!PyString_Check(po) ) return PyErr_Format( PyExc_RuntimeError, "argument mismatch at pos %d - expecting a string", index ); p = PyString_AsString(po); dcArgPointer(gpCall, (DCpointer) p ); } break; default: return PyErr_Format( PyExc_RuntimeError, "unknown signature character '%c'", ch); } ++pos; ++ptr; } if (pos != l) return PyErr_Format( PyExc_RuntimeError, "too many arguments"); if (ch == '\0') return PyErr_Format( PyExc_RuntimeError, "return value missing in signature"); ch = *++ptr; switch(ch) { case DC_SIGCHAR_VOID: dcCallVoid(gpCall, pfunc); Py_RETURN_NONE; case DC_SIGCHAR_BOOL: return Py_BuildValue("i", dcCallBool(gpCall, pfunc) ); case DC_SIGCHAR_INT: return Py_BuildValue("i", dcCallInt(gpCall, pfunc) ); case DC_SIGCHAR_LONGLONG: return Py_BuildValue("L", (unsigned long long) dcCallLongLong(gpCall, pfunc) ); case DC_SIGCHAR_FLOAT: return Py_BuildValue("f", dcCallFloat(gpCall, pfunc) ); case DC_SIGCHAR_DOUBLE: return Py_BuildValue("d", dcCallDouble(gpCall, pfunc) ); case 's': return Py_BuildValue("s", dcCallPointer(gpCall, pfunc) ); case DC_SIGCHAR_POINTER: return Py_BuildValue("p", dcCallPointer(gpCall, pfunc) ); default: return PyErr_Format( PyExc_RuntimeError, "invalid return type signature" ); } }
MVMObject * MVM_nativecall_invoke(MVMThreadContext *tc, MVMObject *res_type, MVMObject *site, MVMObject *args) { MVMObject *result = NULL; char **free_strs = NULL; void **free_rws = NULL; MVMint16 num_strs = 0; MVMint16 num_rws = 0; MVMint16 i; /* Get native call body, so we can locate the call info. Read out all we * shall need, since later we may allocate a result and and move it. */ MVMNativeCallBody *body = MVM_nativecall_get_nc_body(tc, site); MVMint16 num_args = body->num_args; MVMint16 *arg_types = body->arg_types; MVMint16 ret_type = body->ret_type; void *entry_point = body->entry_point; /* Create and set up call VM. */ DCCallVM *vm = dcNewCallVM(8192); dcMode(vm, body->convention); /* Process arguments. */ for (i = 0; i < num_args; i++) { MVMObject *value = MVM_repr_at_pos_o(tc, args, i); switch (arg_types[i] & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_CHAR: handle_arg("integer", cont_i, DCchar, i64, dcArgChar, MVM_nativecall_unmarshal_char); break; case MVM_NATIVECALL_ARG_SHORT: handle_arg("integer", cont_i, DCshort, i64, dcArgShort, MVM_nativecall_unmarshal_short); break; case MVM_NATIVECALL_ARG_INT: handle_arg("integer", cont_i, DCint, i64, dcArgInt, MVM_nativecall_unmarshal_int); break; case MVM_NATIVECALL_ARG_LONG: handle_arg("integer", cont_i, DClong, i64, dcArgLong, MVM_nativecall_unmarshal_long); break; case MVM_NATIVECALL_ARG_LONGLONG: handle_arg("integer", cont_i, DClonglong, i64, dcArgLongLong, MVM_nativecall_unmarshal_longlong); break; case MVM_NATIVECALL_ARG_FLOAT: handle_arg("number", cont_n, DCfloat, n64, dcArgFloat, MVM_nativecall_unmarshal_float); break; case MVM_NATIVECALL_ARG_DOUBLE: handle_arg("number", cont_n, DCdouble, n64, dcArgDouble, MVM_nativecall_unmarshal_double); break; case MVM_NATIVECALL_ARG_ASCIISTR: case MVM_NATIVECALL_ARG_UTF8STR: case MVM_NATIVECALL_ARG_UTF16STR: { MVMint16 free = 0; char *str = MVM_nativecall_unmarshal_string(tc, value, arg_types[i], &free); if (free) { if (!free_strs) free_strs = (char**)MVM_malloc(num_args * sizeof(char *)); free_strs[num_strs] = str; num_strs++; } dcArgPointer(vm, str); } break; case MVM_NATIVECALL_ARG_CSTRUCT: dcArgPointer(vm, MVM_nativecall_unmarshal_cstruct(tc, value)); break; case MVM_NATIVECALL_ARG_CPOINTER: dcArgPointer(vm, MVM_nativecall_unmarshal_cpointer(tc, value)); break; case MVM_NATIVECALL_ARG_CARRAY: dcArgPointer(vm, MVM_nativecall_unmarshal_carray(tc, value)); break; case MVM_NATIVECALL_ARG_CUNION: dcArgPointer(vm, MVM_nativecall_unmarshal_cunion(tc, value)); break; case MVM_NATIVECALL_ARG_VMARRAY: dcArgPointer(vm, MVM_nativecall_unmarshal_vmarray(tc, value)); break; case MVM_NATIVECALL_ARG_CALLBACK: dcArgPointer(vm, unmarshal_callback(tc, value, body->arg_info[i])); break; case MVM_NATIVECALL_ARG_UCHAR: handle_arg("integer", cont_i, DCuchar, i64, dcArgChar, MVM_nativecall_unmarshal_uchar); break; case MVM_NATIVECALL_ARG_USHORT: handle_arg("integer", cont_i, DCushort, i64, dcArgShort, MVM_nativecall_unmarshal_ushort); break; case MVM_NATIVECALL_ARG_UINT: handle_arg("integer", cont_i, DCuint, i64, dcArgInt, MVM_nativecall_unmarshal_uint); break; case MVM_NATIVECALL_ARG_ULONG: handle_arg("integer", cont_i, DCulong, i64, dcArgLong, MVM_nativecall_unmarshal_ulong); break; case MVM_NATIVECALL_ARG_ULONGLONG: handle_arg("integer", cont_i, DCulonglong, i64, dcArgLongLong, MVM_nativecall_unmarshal_ulonglong); break; default: MVM_exception_throw_adhoc(tc, "Internal error: unhandled dyncall argument type"); } } /* Call and process return values. */ MVMROOT(tc, args, { MVMROOT(tc, res_type, { switch (ret_type & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_VOID: dcCallVoid(vm, entry_point); result = res_type; break; case MVM_NATIVECALL_ARG_CHAR: result = MVM_nativecall_make_int(tc, res_type, dcCallChar(vm, entry_point)); break; case MVM_NATIVECALL_ARG_SHORT: result = MVM_nativecall_make_int(tc, res_type, dcCallShort(vm, entry_point)); break; case MVM_NATIVECALL_ARG_INT: result = MVM_nativecall_make_int(tc, res_type, dcCallInt(vm, entry_point)); break; case MVM_NATIVECALL_ARG_LONG: result = MVM_nativecall_make_int(tc, res_type, dcCallLong(vm, entry_point)); break; case MVM_NATIVECALL_ARG_LONGLONG: result = MVM_nativecall_make_int(tc, res_type, dcCallLongLong(vm, entry_point)); break; case MVM_NATIVECALL_ARG_FLOAT: result = MVM_nativecall_make_num(tc, res_type, dcCallFloat(vm, entry_point)); break; case MVM_NATIVECALL_ARG_DOUBLE: result = MVM_nativecall_make_num(tc, res_type, dcCallDouble(vm, entry_point)); break; case MVM_NATIVECALL_ARG_ASCIISTR: case MVM_NATIVECALL_ARG_UTF8STR: case MVM_NATIVECALL_ARG_UTF16STR: result = MVM_nativecall_make_str(tc, res_type, body->ret_type, (char *)dcCallPointer(vm, entry_point)); break; case MVM_NATIVECALL_ARG_CSTRUCT: result = MVM_nativecall_make_cstruct(tc, res_type, dcCallPointer(vm, body->entry_point)); break; case MVM_NATIVECALL_ARG_CPOINTER: result = MVM_nativecall_make_cpointer(tc, res_type, dcCallPointer(vm, body->entry_point)); break; case MVM_NATIVECALL_ARG_CARRAY: result = MVM_nativecall_make_carray(tc, res_type, dcCallPointer(vm, body->entry_point)); break; case MVM_NATIVECALL_ARG_CUNION: result = MVM_nativecall_make_cunion(tc, res_type, dcCallPointer(vm, body->entry_point)); break; case MVM_NATIVECALL_ARG_CALLBACK: /* TODO: A callback -return- value means that we have a C method * that needs to be wrapped similarly to a is native(...) Perl 6 * sub. */ dcCallPointer(vm, body->entry_point); result = res_type; break; case MVM_NATIVECALL_ARG_UCHAR: result = MVM_nativecall_make_uint(tc, res_type, (DCuchar)dcCallChar(vm, entry_point)); break; case MVM_NATIVECALL_ARG_USHORT: result = MVM_nativecall_make_uint(tc, res_type, (DCushort)dcCallShort(vm, entry_point)); break; case MVM_NATIVECALL_ARG_UINT: result = MVM_nativecall_make_uint(tc, res_type, (DCuint)dcCallInt(vm, entry_point)); break; case MVM_NATIVECALL_ARG_ULONG: result = MVM_nativecall_make_uint(tc, res_type, (DCulong)dcCallLong(vm, entry_point)); break; case MVM_NATIVECALL_ARG_ULONGLONG: result = MVM_nativecall_make_uint(tc, res_type, (DCulonglong)dcCallLongLong(vm, entry_point)); break; default: MVM_exception_throw_adhoc(tc, "Internal error: unhandled dyncall return type"); } }); });
SEXP r_dcCall(SEXP sCallVM, SEXP sFuncPtr, SEXP sSignature, SEXP sArgs) { DCCallVM* pvm; void* funcPtr; const char* signature; const char* ptr; int i,l,protect_count; SEXP r; pvm = R_ExternalPtrAddr(sCallVM); if (!pvm) error("callvm is null"); funcPtr = R_ExternalPtrAddr(sFuncPtr); if (!funcPtr) error("funcptr is null"); signature = CHAR(STRING_ELT(sSignature,0) ); if (!signature) error("signature is null"); dcReset(pvm); ptr = signature; l = LENGTH(sArgs); i = 0; protect_count = 0; for(;;) { char ch = *ptr++; SEXP arg; if (ch == '\0') error("invalid signature - no return type specified"); if (ch == ')') break; if (i >= l) error("not enough arguments for given signature (arg length = %d %d %c)", l,i,ch ); arg = VECTOR_ELT(sArgs,i); switch(ch) { case DC_SIGCHAR_BOOL: { DCbool value; if ( isLogical(arg) ) { value = ( LOGICAL(arg)[0] == 0 ) ? DC_FALSE : DC_TRUE; } else { value = LOGICAL( coerceVector(arg, LGLSXP) )[0] ? DC_FALSE : DC_TRUE; } dcArgBool(pvm, value ); break; } case DC_SIGCHAR_INT: { int value; if ( isInteger(arg) ) { value = INTEGER(arg)[0]; } else { value = INTEGER( coerceVector(arg, INTSXP) )[0]; } dcArgInt(pvm, value); break; } case DC_SIGCHAR_FLOAT: { dcArgFloat( pvm, (float) REAL( coerceVector(arg, REALSXP) )[0] ); break; } case DC_SIGCHAR_DOUBLE: { double value; if ( isReal(arg) ) { value = REAL(arg)[0]; } else { value = REAL( coerceVector(arg,REALSXP) )[0]; } dcArgDouble( pvm, value ); break; } /* case DC_SIGCHAR_LONG: { PROTECT(arg = coerceVector(arg, REALSXP) ); dcArgLong( pvm, (DClong) ( REAL(arg)[0] ) ); UNPROTECT(1); break; } */ case DC_SIGCHAR_STRING: { DCpointer ptr; if (arg == R_NilValue) ptr = (DCpointer) 0; else if (isString(arg)) ptr = (DCpointer) CHAR( STRING_ELT(arg,0) ); else { if (protect_count) UNPROTECT(protect_count); error("invalid value for C string argument"); break; } } case DC_SIGCHAR_POINTER: { DCpointer ptr; if ( arg == R_NilValue ) ptr = (DCpointer) 0; else if (isString(arg) ) ptr = (DCpointer) CHAR( STRING_ELT(arg,0) ); else if (isReal(arg) ) ptr = (DCpointer) REAL(arg); else if (isInteger(arg) ) ptr = (DCpointer) INTEGER(arg); else if (isLogical(arg) ) ptr = (DCpointer) LOGICAL(arg); else if (TYPEOF(arg) == EXTPTRSXP) ptr = R_ExternalPtrAddr(arg); else { if (protect_count) UNPROTECT(protect_count); error("invalid signature"); break; } dcArgPointer(pvm, ptr); break; } } ++i; } if ( i != l ) { if (protect_count) UNPROTECT(protect_count); error ("signature claims to have %d arguments while %d arguments are given", i, l); } switch(*ptr) { case DC_SIGCHAR_BOOL: PROTECT( r = allocVector(LGLSXP, 1) ); protect_count++; LOGICAL(r)[0] = ( dcCallBool(pvm, funcPtr) == DC_FALSE ) ? FALSE : TRUE; UNPROTECT(protect_count); return r; case DC_SIGCHAR_CHAR: PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; INTEGER(r)[0] = dcCallChar(pvm, funcPtr); UNPROTECT(protect_count); return r; case DC_SIGCHAR_SHORT: PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; INTEGER(r)[0] = dcCallShort(pvm, funcPtr); UNPROTECT(protect_count); return r; case DC_SIGCHAR_LONG: PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; INTEGER(r)[0] = dcCallLong(pvm, funcPtr); UNPROTECT(protect_count); return r; case DC_SIGCHAR_INT: PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; INTEGER(r)[0] = dcCallInt(pvm, funcPtr); UNPROTECT(protect_count); return r; case DC_SIGCHAR_LONGLONG: PROTECT( r = allocVector(REALSXP, 1) ); protect_count++; REAL(r)[0] = (double) ( dcCallLong(pvm, funcPtr) ); UNPROTECT(protect_count); return r; case DC_SIGCHAR_FLOAT: PROTECT( r = allocVector(REALSXP, 1) ); protect_count++; REAL(r)[0] = (double) ( dcCallFloat(pvm, funcPtr) ); UNPROTECT(protect_count); return r; case DC_SIGCHAR_DOUBLE: PROTECT( r = allocVector(REALSXP, 1) ); protect_count++; REAL(r)[0] = dcCallDouble(pvm, funcPtr); UNPROTECT(protect_count); return r; case DC_SIGCHAR_POINTER: PROTECT( r = R_MakeExternalPtr( dcCallPointer(pvm,funcPtr), R_NilValue, R_NilValue ) ); protect_count++; UNPROTECT(protect_count); return r; case DC_SIGCHAR_VOID: dcCallVoid(pvm,funcPtr); if (protect_count) UNPROTECT(protect_count); break; default: { if (protect_count) UNPROTECT(protect_count); error("invalid return type signature"); } break; } return R_NilValue; }
jboolean followArgsGenericJavaCallback(CallTempStruct* call, DCArgs* args, int nTypes, ValueType* pTypes) { JNIEnv* env = call->env; int iParam; jobjectArray arr = (*env)->NewObjectArray(env, nTypes, gObjectClass, NULL); for (iParam = 0; iParam < nTypes; iParam++) { ValueType type = pTypes[iParam]; jobject arg = NULL; switch (type) { case eIntFlagSet: arg = BoxInt(env, (jint)getFlagValue(env, (jobject)dcbArgPointer(args))); break; case eIntValue: arg = BoxInt(env, dcbArgInt(args)); break; case eCLongValue: { jlong v; if (sizeof(long) == 4) v = dcbArgLong(args); else v = dcbArgLongLong(args); arg = BoxCLong(env, v); break; } case eSizeTValue: { jlong v; if (sizeof(size_t) == 4) v = dcbArgInt(args); else v = dcbArgLongLong(args); arg = BoxSizeT(env, v); break; } case eLongValue: arg = BoxLong(env, dcbArgLongLong(args)); break; case eShortValue: arg = BoxShort(env, dcbArgShort(args)); break; case eBooleanValue: case eByteValue: arg = BoxByte(env, dcbArgChar(args)); break; case eFloatValue: arg = BoxFloat(env, dcbArgFloat(args)); break; case eDoubleValue: arg = BoxDouble(env, dcbArgDouble(args)); break; case ePointerValue: { jobject callIO = call && call->pCallIOs ? *(call->pCallIOs++) : NULL; void* ptr = dcbArgPointer(args); arg = createPointerFromIO(env, ptr, callIO); } break; case eWCharValue: switch (sizeof(wchar_t)) { case 1: arg = BoxChar(env, dcbArgChar(args)); break; case 2: arg = BoxChar(env, dcbArgShort(args)); break; case 4: arg = BoxInt(env, dcbArgInt(args)); break; default: throwException(env, "Invalid wchar_t size for argument !"); return JNI_FALSE; } break; default: throwException(env, "Invalid argument value type !"); return JNI_FALSE; } (*env)->SetObjectArrayElement(env, arr, iParam, arg); } dcArgPointer(call->vm, arr); if ((*env)->ExceptionCheck(env)) return JNI_FALSE; return JNI_TRUE; }