Skip to content
Browse files

Implement nqp::nativecallrefresh() and related logic.

This is a first rough version that simply clears all the caches, all the time,
whenever a refresh is required. That's probably going to be a bit slow, as we
refresh all function arguments after the call, to guard for functions that
modify their arguments.

A better version of this would only invalidate the cached objects that are
actually different from the pointer in C memory.

As of this commit, we pass all the NativeCall tests.
  • Loading branch information...
1 parent 17bf0fd commit 9635b9f522f8084a3e20fbffbcd152dc06ba4706 @arnsholt arnsholt committed
View
2 src/vm/jvm/QAST/Compiler.nqp
@@ -2476,7 +2476,7 @@ QAST::OperationsJAST.map_classlib_core_op('backendconfig', $TYPE_OPS, 'jvmgetcon
QAST::OperationsJAST.map_classlib_core_op('initnativecall', $TYPE_NATIVE_OPS, 'init', [], $RT_INT);
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);
-QAST::OperationsJAST.map_classlib_core_op('nativecallrefresh', $TYPE_NATIVE_OPS, 'refresh', [$RT_OBJ], $RT_INT);
+QAST::OperationsJAST.map_classlib_core_op('nativecallrefresh', $TYPE_NATIVE_OPS, 'refresh', [$RT_OBJ], $RT_INT, :tc);
class QAST::CompilerJAST {
# Responsible for handling issues around code references, building the
View
12 src/vm/jvm/runtime/org/perl6/nqp/runtime/NativeCallOps.java
@@ -33,6 +33,7 @@
import org.perl6.nqp.sixmodel.reprs.NativeCall.ArgType;
import org.perl6.nqp.sixmodel.reprs.NativeCallInstance;
import org.perl6.nqp.sixmodel.reprs.NativeCallBody;
+import org.perl6.nqp.sixmodel.reprs.Refreshable;
public final class NativeCallOps {
public static long init() {
@@ -91,6 +92,10 @@ public static SixModelObject call(SixModelObject returns, SixModelObject callObj
/* The actual foreign function call. */
Object returned = call.entry_point.invoke(javaType(tc, call.ret_type, returns), cArgs);
+ for (int i = 0; i < arguments.elems(tc); i++) {
+ refresh(arguments.at_pos_boxed(tc, i), tc);
+ }
+
/* Wrap returned in the appropriate REPR type. */
return toNQPType(tc, call.ret_type, returns, returned);
}
@@ -100,7 +105,12 @@ public static SixModelObject call(SixModelObject returns, SixModelObject callObj
}
}
- public static long refresh(SixModelObject obj) {
+ public static long refresh(SixModelObject obj, ThreadContext tc) {
+ obj = Ops.decont(obj, tc);
+ if(!(obj instanceof Refreshable)) return 1L;
+
+ ((Refreshable) obj).refresh(tc);
+
return 1L;
}
View
53 src/vm/jvm/runtime/org/perl6/nqp/sixmodel/reprs/CArrayInstance.java
@@ -17,7 +17,7 @@
import org.perl6.nqp.sixmodel.reprs.CArrayREPRData.ElemKind;
import org.perl6.nqp.sixmodel.reprs.NativeCall.ArgType;
-public class CArrayInstance extends SixModelObject {
+public class CArrayInstance extends SixModelObject implements Refreshable {
public Pointer storage;
public SixModelObject[] child_objs;
public boolean managed;
@@ -213,4 +213,55 @@ private SixModelObject makeObject(ThreadContext tc, Pointer ptr) {
/* And a dummy return statement to placate Java's flow analysis. */
return null;
}
+
+ public void refresh(ThreadContext tc) {
+ CArrayREPRData repr_data = (CArrayREPRData) st.REPRData;
+
+ // No need to refresh if we don't have any cached children.
+ if (child_objs == null) return;
+
+ if (repr_data.elem_kind == ElemKind.CARRAY || repr_data.elem_kind == ElemKind.CSTRUCT) {
+ refreshComplex(tc);
+ }
+ else {
+ refreshSimple(tc);
+ }
+ }
+
+ /**
+ * Refresh logic for CArray of complex (CArray or CStruct) types.
+ */
+ private void refreshComplex(ThreadContext tc) {
+ for (int i = 0; i < child_objs.length; i++) {
+ SixModelObject child = child_objs[i];
+
+ // No cache for this element? Go to next.
+ if (child == null) continue;
+
+ /* Invalidate cache and recursively refresh child too. Future
+ * versions here should only invalidate the cache if C memory has
+ * a different pointer than the cached object.
+ */
+ child_objs[i] = null;
+ NativeCallOps.refresh(child, tc);
+ }
+ }
+
+ /**
+ * Refresh logic for CArray of simple (CPointer) types.
+ */
+ private void refreshSimple(ThreadContext tc) {
+ for (int i = 0; i < child_objs.length; i++) {
+ SixModelObject child = child_objs[i];
+
+ // No cache for this element? Go to next.
+ if (child == null) continue;
+
+ /* Invalidate cache. Future versions here should only invalidate
+ * the cache if C memory has a different pointer than the cached
+ * object.
+ */
+ child_objs[i] = null;
+ }
+ }
}
View
23 src/vm/jvm/runtime/org/perl6/nqp/sixmodel/reprs/CStructInstance.java
@@ -1,6 +1,7 @@
package org.perl6.nqp.sixmodel.reprs;
import java.util.HashMap;
+import java.util.Map.Entry;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
@@ -14,7 +15,7 @@
import org.perl6.nqp.sixmodel.reprs.CStructREPRData.AttrInfo;
import org.perl6.nqp.sixmodel.reprs.NativeCall.ArgType;
-public class CStructInstance extends SixModelObject {
+public class CStructInstance extends SixModelObject implements Refreshable {
public Structure storage;
/* XXX: Using a hash to store members is probably not an optimal solution.
* Dynamically generating subclasses that have the appropriate members and
@@ -112,4 +113,24 @@ public void get_attribute_native(ThreadContext tc, SixModelObject class_handle,
ExceptionHandling.dieInternal(tc, String.format("CStruct.get_attribute_native: Can't handle %s", info.argType));
}
}
+
+ public void refresh(ThreadContext tc) {
+ CStructREPRData repr_data = (CStructREPRData) st.REPRData;
+
+ // Recursively refresh our members.
+ for (Entry<String, SixModelObject> entry: memberCache.entrySet()) {
+ ArgType argType = repr_data.fieldTypes.get(entry.getKey()).argType;
+ SixModelObject child = entry.getValue();
+ if (argType == ArgType.CARRAY || argType == ArgType.CSTRUCT) {
+ NativeCallOps.refresh(child, tc);
+ }
+ }
+
+ /* This is the take a hammer to it approach. Just dump the entire
+ * cache and rebuild everything on next read. Future versions should
+ * compare the pointer in C memory and the one in the object in the
+ * loop above and only dump the entries where the two are different.
+ */
+ memberCache.clear();
+ }
}
View
7 src/vm/jvm/runtime/org/perl6/nqp/sixmodel/reprs/Refreshable.java
@@ -0,0 +1,7 @@
+package org.perl6.nqp.sixmodel.reprs;
+
+import org.perl6.nqp.runtime.ThreadContext;
+
+public interface Refreshable {
+ public void refresh(ThreadContext tc);
+}

0 comments on commit 9635b9f

Please sign in to comment.
Something went wrong with that request. Please try again.