char cbHandler(DCCallback* cb, DCArgs* args, DCValue* result, void* userdata) { int* ud = (int*)userdata; int arg1 = dcbArgInt (args); float arg2 = dcbArgFloat (args); short arg3 = dcbArgShort (args); double arg4 = dcbArgDouble (args); long long arg5 = dcbArgLongLong(args); printf("reached callback\n"); printf("userdata (should be 1337): %d\n", *ud); printf("1st argument (should be 123): %d\n", arg1); printf("2nd argument (should be 23.f): %f\n", arg2); printf("3rd argument (should be 3): %d\n", arg3); printf("4th argument (should be 1.82): %f\n", arg4); printf("5th argument (should be 9909): %lld\n", arg5); if(*ud == 1337) *ud = 1; if(arg1 == 123) ++*ud; if(arg2 == 23.f) ++*ud; if(arg3 == 3) ++*ud; if(arg4 == 1.82) ++*ud; if(arg5 == 9909) ++*ud; result->s = 1234; return 's'; }
char handler(DCCallback* that, DCArgs* input, DCValue* output, void* userdata) { const char* signature = (const char*) userdata; int pos = 0; char ch; signature = SignatureSkipCallPrefix(signature); for(;;) { ch = *signature++; if (ch == DC_SIGCHAR_ENDARG) break; Args[pos].L = 0xDEADC0DECAFEBABELL; switch(ch) { case DC_SIGCHAR_BOOL: Args[pos].B = dcbArgBool (input); break; case DC_SIGCHAR_CHAR: Args[pos].c = dcbArgChar (input); break; case DC_SIGCHAR_UCHAR: Args[pos].C = dcbArgUChar (input); break; case DC_SIGCHAR_SHORT: Args[pos].s = dcbArgShort (input); break; case DC_SIGCHAR_USHORT: Args[pos].S = dcbArgUShort (input); break; case DC_SIGCHAR_INT: Args[pos].i = dcbArgInt (input); break; case DC_SIGCHAR_UINT: Args[pos].I = dcbArgUInt (input); break; case DC_SIGCHAR_LONG: Args[pos].j = dcbArgLong (input); break; case DC_SIGCHAR_ULONG: Args[pos].J = dcbArgULong (input); break; case DC_SIGCHAR_LONGLONG: Args[pos].l = dcbArgLongLong (input); break; case DC_SIGCHAR_ULONGLONG:Args[pos].L = dcbArgULongLong(input); break; case DC_SIGCHAR_FLOAT: Args[pos].f = dcbArgFloat (input); break; case DC_SIGCHAR_DOUBLE: Args[pos].d = dcbArgDouble (input); break; case DC_SIGCHAR_POINTER: Args[pos].p = dcbArgPointer (input); break; } ++pos; } ch = *signature++; /* currently, no void result is supported by the suite */ GetReferenceResult(output, ch); switch(ch) { case DC_SIGCHAR_BOOL: return 'B'; case DC_SIGCHAR_CHAR: return 'c'; case DC_SIGCHAR_UCHAR: return 'C'; case DC_SIGCHAR_SHORT: return 's'; case DC_SIGCHAR_USHORT: return 'S'; case DC_SIGCHAR_INT: return 'i'; case DC_SIGCHAR_UINT: return 'I'; case DC_SIGCHAR_LONG: return 'j'; case DC_SIGCHAR_ULONG: return 'J'; case DC_SIGCHAR_LONGLONG: return 'l'; case DC_SIGCHAR_ULONGLONG:return 'l'; case DC_SIGCHAR_FLOAT: return 'f'; case DC_SIGCHAR_DOUBLE: return 'd'; case DC_SIGCHAR_POINTER: return 'p'; default: assert(0); return 'v'; } }
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; }
static char callback_handler(DCCallback *cb, DCArgs *cb_args, DCValue *cb_result, MVMNativeCallback *data) { CallbackInvokeData cid; MVMint32 num_roots, i; MVMRegister res; /* Build a callsite and arguments buffer. */ MVMThreadContext *tc = data->tc; MVMRegister *args = MVM_malloc(data->num_types * sizeof(MVMRegister)); num_roots = 0; for (i = 1; i < data->num_types; i++) { MVMObject *type = data->types[i]; MVMint16 typeinfo = data->typeinfos[i]; switch (typeinfo & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_CHAR: args[i - 1].i64 = dcbArgChar(cb_args); break; case MVM_NATIVECALL_ARG_SHORT: args[i - 1].i64 = dcbArgShort(cb_args); break; case MVM_NATIVECALL_ARG_INT: args[i - 1].i64 = dcbArgInt(cb_args); break; case MVM_NATIVECALL_ARG_LONG: args[i - 1].i64 = dcbArgLong(cb_args); break; case MVM_NATIVECALL_ARG_LONGLONG: args[i - 1].i64 = dcbArgLongLong(cb_args); break; case MVM_NATIVECALL_ARG_FLOAT: args[i - 1].n64 = dcbArgFloat(cb_args); break; case MVM_NATIVECALL_ARG_DOUBLE: args[i - 1].n64 = dcbArgDouble(cb_args); break; case MVM_NATIVECALL_ARG_ASCIISTR: case MVM_NATIVECALL_ARG_UTF8STR: case MVM_NATIVECALL_ARG_UTF16STR: args[i - 1].o = MVM_nativecall_make_str(tc, type, typeinfo, (char *)dcbArgPointer(cb_args)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CSTRUCT: args[i - 1].o = MVM_nativecall_make_cstruct(tc, type, dcbArgPointer(cb_args)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CPOINTER: args[i - 1].o = MVM_nativecall_make_cpointer(tc, type, dcbArgPointer(cb_args)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CARRAY: args[i - 1].o = MVM_nativecall_make_carray(tc, type, dcbArgPointer(cb_args)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; break; case MVM_NATIVECALL_ARG_CUNION: args[i - 1].o = MVM_nativecall_make_cunion(tc, type, dcbArgPointer(cb_args)); MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; 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. */ dcbArgPointer(cb_args); args[i - 1].o = type; MVM_gc_root_temp_push(tc, (MVMCollectable **)&(args[i - 1].o)); num_roots++; case MVM_NATIVECALL_ARG_UCHAR: args[i - 1].i64 = dcbArgUChar(cb_args); break; case MVM_NATIVECALL_ARG_USHORT: args[i - 1].i64 = dcbArgUShort(cb_args); break; case MVM_NATIVECALL_ARG_UINT: args[i - 1].i64 = dcbArgUInt(cb_args); break; case MVM_NATIVECALL_ARG_ULONG: args[i - 1].i64 = dcbArgULong(cb_args); break; case MVM_NATIVECALL_ARG_ULONGLONG: args[i - 1].i64 = dcbArgULongLong(cb_args); break; default: MVM_exception_throw_adhoc(tc, "Internal error: unhandled dyncall callback argument type"); } } /* Call into a nested interpreter (since we already are in one). Need to * save a bunch of state around each side of this. */ cid.invokee = data->target; cid.args = args; cid.cs = data->cs; { MVMuint8 **backup_interp_cur_op = tc->interp_cur_op; MVMuint8 **backup_interp_bytecode_start = tc->interp_bytecode_start; MVMRegister **backup_interp_reg_base = tc->interp_reg_base; MVMCompUnit **backup_interp_cu = tc->interp_cu; MVMFrame *backup_cur_frame = tc->cur_frame; MVMFrame *backup_thread_entry_frame = tc->thread_entry_frame; MVMuint32 backup_mark = MVM_gc_root_temp_mark(tc); jmp_buf backup_interp_jump; memcpy(backup_interp_jump, tc->interp_jump, sizeof(jmp_buf)); tc->cur_frame->return_value = &res; tc->cur_frame->return_type = MVM_RETURN_OBJ; MVM_interp_run(tc, &callback_invoke, &cid); tc->interp_cur_op = backup_interp_cur_op; tc->interp_bytecode_start = backup_interp_bytecode_start; tc->interp_reg_base = backup_interp_reg_base; tc->interp_cu = backup_interp_cu; tc->cur_frame = backup_cur_frame; tc->thread_entry_frame = backup_thread_entry_frame; memcpy(tc->interp_jump, backup_interp_jump, sizeof(jmp_buf)); MVM_gc_root_temp_mark_reset(tc, backup_mark); } /* Handle return value. */ if (res.o) { MVMContainerSpec const *contspec = STABLE(res.o)->container_spec; if (contspec && contspec->fetch_never_invokes) contspec->fetch(data->tc, res.o, &res); } switch (data->typeinfos[0] & MVM_NATIVECALL_ARG_TYPE_MASK) { case MVM_NATIVECALL_ARG_VOID: break; case MVM_NATIVECALL_ARG_CHAR: cb_result->c = MVM_nativecall_unmarshal_char(data->tc, res.o); break; case MVM_NATIVECALL_ARG_SHORT: cb_result->s = MVM_nativecall_unmarshal_short(data->tc, res.o); break; case MVM_NATIVECALL_ARG_INT: cb_result->i = MVM_nativecall_unmarshal_int(data->tc, res.o); break; case MVM_NATIVECALL_ARG_LONG: cb_result->j = MVM_nativecall_unmarshal_long(data->tc, res.o); break; case MVM_NATIVECALL_ARG_LONGLONG: cb_result->l = MVM_nativecall_unmarshal_longlong(data->tc, res.o); break; case MVM_NATIVECALL_ARG_FLOAT: cb_result->f = MVM_nativecall_unmarshal_float(data->tc, res.o); break; case MVM_NATIVECALL_ARG_DOUBLE: cb_result->d = MVM_nativecall_unmarshal_double(data->tc, res.o); break; case MVM_NATIVECALL_ARG_ASCIISTR: case MVM_NATIVECALL_ARG_UTF8STR: case MVM_NATIVECALL_ARG_UTF16STR: cb_result->Z = MVM_nativecall_unmarshal_string(data->tc, res.o, data->typeinfos[0], NULL); break; case MVM_NATIVECALL_ARG_CSTRUCT: cb_result->p = MVM_nativecall_unmarshal_cstruct(data->tc, res.o); break; case MVM_NATIVECALL_ARG_CPOINTER: cb_result->p = MVM_nativecall_unmarshal_cpointer(data->tc, res.o); break; case MVM_NATIVECALL_ARG_CARRAY: cb_result->p = MVM_nativecall_unmarshal_carray(data->tc, res.o); break; case MVM_NATIVECALL_ARG_CUNION: cb_result->p = MVM_nativecall_unmarshal_cunion(data->tc, res.o); break; case MVM_NATIVECALL_ARG_VMARRAY: cb_result->p = MVM_nativecall_unmarshal_vmarray(data->tc, res.o); break; case MVM_NATIVECALL_ARG_CALLBACK: cb_result->p = unmarshal_callback(data->tc, res.o, data->types[0]); break; case MVM_NATIVECALL_ARG_UCHAR: cb_result->c = MVM_nativecall_unmarshal_uchar(data->tc, res.o); break; case MVM_NATIVECALL_ARG_USHORT: cb_result->s = MVM_nativecall_unmarshal_ushort(data->tc, res.o); break; case MVM_NATIVECALL_ARG_UINT: cb_result->i = MVM_nativecall_unmarshal_uint(data->tc, res.o); break; case MVM_NATIVECALL_ARG_ULONG: cb_result->j = MVM_nativecall_unmarshal_ulong(data->tc, res.o); break; case MVM_NATIVECALL_ARG_ULONGLONG: cb_result->l = MVM_nativecall_unmarshal_ulonglong(data->tc, res.o); break; default: MVM_exception_throw_adhoc(data->tc, "Internal error: unhandled dyncall callback return type"); } /* Clean up. */ MVM_gc_root_temp_pop_n(tc, num_roots); MVM_free(args); /* Indicate what we're producing as a result. */ return get_signature_char(data->typeinfos[0]); }
DCushort dcbArgUShort (DCArgs* p) { return (DCushort) dcbArgShort(p); }
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; }