Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Basic call handling and converting between NQP and JNA types.
This means that we support int, num, str and cpointer as arguments and return
values, which in turn means that we pass the basic sanity tests in the NQP
test suite.
  • Loading branch information
arnsholt committed Sep 9, 2013
1 parent a83bf2b commit 6567e57
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/vm/jvm/QAST/Compiler.nqp
Expand Up @@ -2462,8 +2462,8 @@ QAST::OperationsJAST.map_classlib_core_op('jvmgetconfig', $TYPE_OPS, 'jvmgetconf

# Native call ops
QAST::OperationsJAST.map_classlib_core_op('initnativecall', $TYPE_NATIVE_OPS, 'init', [], $RT_INT);
QAST::OperationsJAST.map_classlib_core_op('nativecall', $TYPE_NATIVE_OPS, 'call', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ);
QAST::OperationsJAST.map_classlib_core_op('buildnativecall', $TYPE_NATIVE_OPS, 'build', [$RT_OBJ, $RT_STR, $RT_STR, $RT_STR, $RT_OBJ, $RT_OBJ], $RT_INT, :tc);
QAST::OperationsJAST.map_classlib_core_op('nativecall', $TYPE_NATIVE_OPS, 'call', [$RT_OBJ, $RT_OBJ, $RT_OBJ], $RT_OBJ, :tc);

class QAST::CompilerJAST {
# Responsible for handling issues around code references, building the
Expand Down
136 changes: 134 additions & 2 deletions src/vm/jvm/runtime/org/perl6/nqp/runtime/NativeCallOps.java
@@ -1,9 +1,11 @@
package org.perl6.nqp.runtime;

import com.sun.jna.NativeLibrary;
import com.sun.jna.Pointer;

import org.perl6.nqp.sixmodel.SixModelObject;

import org.perl6.nqp.sixmodel.reprs.CPointerInstance;
import org.perl6.nqp.sixmodel.reprs.NativeCallInstance;
import org.perl6.nqp.sixmodel.reprs.NativeCallInstance.ArgType;

Expand Down Expand Up @@ -36,8 +38,23 @@ public static long build(SixModelObject target, String libname, String symbol, S
return 1L;
}

public static SixModelObject call(SixModelObject returns, SixModelObject call, SixModelObject arguments) {
return null;
public static SixModelObject call(SixModelObject returns, SixModelObject callObject, SixModelObject arguments, ThreadContext tc) {
NativeCallInstance call = getNativeCallInstance(callObject);

/* Convert arguments into array of appropriate objects. */
int n = (int) arguments.elems(tc);
/* TODO: Make sure n == call.arg_types.length? */
Object[] cArgs = new Object[n];
for (int i = 0; i < n; i++) {
/* TODO: Converting sixmodel objects to appropriate JNA types. */
cArgs[i] = toJNAType(tc, arguments.at_pos_boxed(tc, i), call.arg_types[i]);
}

/* The actual foreign function call. */
Object returned = call.entry_point.invoke(javaType(tc, call.ret_type), cArgs);

/* Wrap returned in the appropriate REPR type. */
return toNQPType(tc, call.ret_type, returns, returned);
}

private static NativeCallInstance getNativeCallInstance(SixModelObject target) {
Expand All @@ -52,6 +69,121 @@ private static NativeCallInstance getNativeCallInstance(SixModelObject target) {
return call;
}

private static Class javaType(ThreadContext tc, ArgType target) {
switch (target) {
case VOID:
return Void.class;
case CHAR:
return Byte.class;
case SHORT:
return Short.class;
case INT:
return Integer.class;
case LONG:
return Long.class;
case FLOAT:
return Float.class;
case DOUBLE:
return Double.class;
case ASCIISTR:
case UTF8STR:
case UTF16STR:
/* TODO: Handle encodings. */
return String.class;
case CPOINTER:
return Pointer.class;
default:
ExceptionHandling.dieInternal(tc, String.format("Don't know correct Java class for %s arguments yet", target));
}

/* And a dummy return to placate the Java flow analysis. */
return null;
}

private static Object toJNAType(ThreadContext tc, SixModelObject o, ArgType target) {
switch (target) {
case CHAR:
return new Byte((byte) o.get_int(tc));
case SHORT:
return new Short((short) o.get_int(tc));
case INT:
return new Integer((int) o.get_int(tc));
case LONG:
return new Long((long) o.get_int(tc));
case FLOAT:
return new Float((float) o.get_num(tc));
case DOUBLE:
return new Double((double) o.get_num(tc));
case ASCIISTR:
case UTF8STR:
case UTF16STR:
/* TODO: Handle encodings. */
return o.get_str(tc);
case CPOINTER:
return ((CPointerInstance) o).pointer;
default:
ExceptionHandling.dieInternal(tc, String.format("Don't know how to convert %s arguments to JNA yet", target));
}

/* And a dummy return to placate the Java flow analysis. */
return null;
}

private static SixModelObject toNQPType(ThreadContext tc, ArgType target, SixModelObject type, Object o) {
SixModelObject nqpobj = null;
if (target != ArgType.VOID)
nqpobj = type.st.REPR.allocate(tc, type.st);

switch (target) {
case VOID:
return type;
case CHAR: {
byte val = ((Byte) o).byteValue();
nqpobj.set_int(tc, val);
break;
}
case SHORT: {
short val = ((Short) o).shortValue();
nqpobj.set_int(tc, val);
break;
}
case INT: {
int val = ((Integer) o).intValue();
nqpobj.set_int(tc, val);
break;
}
case LONG: {
long val = ((Long) o).longValue();
nqpobj.set_int(tc, val);
break;
}
case FLOAT: {
float val = ((Float) o).floatValue();
nqpobj.set_num(tc, val);
break;
}
case DOUBLE: {
double val = ((Double) o).floatValue();
nqpobj.set_num(tc, val);
break;
}
case ASCIISTR:
case UTF8STR:
case UTF16STR:
/* TODO: Handle encodings. */
nqpobj.set_str(tc, (String) o);
case CPOINTER: {
CPointerInstance cpointer = (CPointerInstance) nqpobj;
cpointer.pointer = (Pointer) o;
break;
}
default:
ExceptionHandling.dieInternal(tc, String.format("Don't know how to convert %s arguments to NQP yet", target));
}

return nqpobj;
}

private static ArgType getArgType(ThreadContext tc, SixModelObject info, boolean isReturn) {
String type_name = info.at_key_boxed(tc, "type").get_str(tc);

Expand Down
@@ -1,7 +1,9 @@
package org.perl6.nqp.sixmodel.reprs;

import com.sun.jna.Pointer;

import org.perl6.nqp.sixmodel.SixModelObject;

public class CPointerInstance extends SixModelObject {
/* Nothing here yet. */
public Pointer pointer;
}

0 comments on commit 6567e57

Please sign in to comment.