Skip to content
Snippets Groups Projects
Commit 28cfd5c0 authored by Lukas Stadler's avatar Lukas Stadler Committed by stepan
Browse files

change FFIProcessor to generate foreign access factories directly

parent d81131c3
No related branches found
No related tags found
No related merge requests found
Showing
with 299 additions and 83 deletions
......@@ -25,7 +25,7 @@ package com.oracle.truffle.r.ffi.impl.interop.pkginit;
import com.oracle.truffle.api.interop.MessageResolution;
import com.oracle.truffle.api.interop.Resolve;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.r.ffi.impl.common.UpCallUnwrap;
import com.oracle.truffle.r.ffi.impl.upcalls.UpCallUnwrap;
import com.oracle.truffle.r.runtime.ffi.DLL.DLLInfo;
@MessageResolution(receiverType = SetDotSymbolValuesCall.class)
......
......@@ -34,12 +34,12 @@ import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.r.ffi.impl.common.RFFIUtils;
import com.oracle.truffle.r.ffi.impl.common.UpCallUnwrap;
import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_CallFactory.ToNativeNodeGen;
import com.oracle.truffle.r.ffi.impl.llvm.TruffleLLVM_CallFactory.TruffleLLVM_InvokeCallNodeGen;
import com.oracle.truffle.r.ffi.impl.llvm.upcalls.BytesToNativeCharArrayCall;
import com.oracle.truffle.r.ffi.impl.llvm.upcalls.CharSXPToNativeArrayCall;
import com.oracle.truffle.r.ffi.impl.upcalls.Callbacks;
import com.oracle.truffle.r.ffi.impl.upcalls.UpCallUnwrap;
import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;
import com.oracle.truffle.r.runtime.RInternalError;
import com.oracle.truffle.r.runtime.RRuntime;
......
......@@ -28,6 +28,11 @@ import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.dsl.TypeSystemReference;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CADDRNodeGen;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CADRNodeGen;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CARNodeGen;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CDDRNodeGen;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodesFactory.CDRNodeGen;
import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode;
import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNamesAttributeNode;
import com.oracle.truffle.r.runtime.RInternalError;
......@@ -83,6 +88,10 @@ public final class ListAccessNodes {
protected Object car(@SuppressWarnings("unused") Object obj) {
throw RInternalError.unimplemented("CAR only works on pair lists, language objects, argument lists, and symbols");
}
public static CARNode create() {
return CARNodeGen.create();
}
}
@TypeSystemReference(RTypes.class)
......@@ -123,7 +132,10 @@ public final class ListAccessNodes {
@Fallback
protected Object cdr(@SuppressWarnings("unused") Object obj) {
throw RInternalError.unimplemented("CDR only works on pair lists, language objects, and argument lists");
}
public static CDRNode create() {
return CDRNodeGen.create();
}
}
......@@ -143,6 +155,10 @@ public final class ListAccessNodes {
protected Object cadr(@SuppressWarnings("unused") Object obj) {
throw RInternalError.unimplemented("CADR only works on pair lists and language objects");
}
public static CADRNode create() {
return CADRNodeGen.create();
}
}
@TypeSystemReference(RTypes.class)
......@@ -161,6 +177,10 @@ public final class ListAccessNodes {
protected Object caddr(@SuppressWarnings("unused") Object obj) {
throw RInternalError.unimplemented("CADDR only works on pair lists and language objects");
}
public static CADDRNode create() {
return CADDRNodeGen.create();
}
}
@TypeSystemReference(RTypes.class)
......@@ -179,7 +199,10 @@ public final class ListAccessNodes {
@Fallback
protected Object cddr(@SuppressWarnings("unused") Object obj) {
throw RInternalError.unimplemented("CDDR only works on pair lists and language objects");
}
public static CDDRNode create() {
return CDDRNodeGen.create();
}
}
}
......@@ -26,6 +26,10 @@ import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.dsl.TypeSystemReference;
import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.LENGTHNodeGen;
import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.RDoNewObjectNodeGen;
import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.RDoSlotAssignNodeGen;
import com.oracle.truffle.r.ffi.impl.nodes.MiscNodesFactory.RDoSlotNodeGen;
import com.oracle.truffle.r.nodes.access.AccessSlotNode;
import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
import com.oracle.truffle.r.nodes.access.UpdateSlotNode;
......@@ -102,6 +106,10 @@ public final class MiscNodes {
CompilerDirectives.transferToInterpreter();
throw RError.error(RError.SHOW_CALLER2, RError.Message.LENGTH_MISAPPLIED, SEXPTYPE.gnuRTypeForObject(obj).name());
}
public static LENGTHNode create() {
return LENGTHNodeGen.create();
}
}
@TypeSystemReference(RTypes.class)
......@@ -122,6 +130,10 @@ public final class MiscNodes {
Object doSlot(@SuppressWarnings("unused") Object o, Object name) {
throw RError.error(RError.SHOW_CALLER2, RError.Message.INVALID_ARGUMENT_OF_TYPE, "name", SEXPTYPE.gnuRTypeForObject(name).name());
}
public static RDoSlotNode create() {
return RDoSlotNodeGen.create();
}
}
@TypeSystemReference(RTypes.class)
......@@ -142,6 +154,10 @@ public final class MiscNodes {
Object doSlot(@SuppressWarnings("unused") Object o, Object name, @SuppressWarnings("unused") Object value) {
throw RError.error(RError.SHOW_CALLER2, RError.Message.INVALID_ARGUMENT_OF_TYPE, "name", SEXPTYPE.gnuRTypeForObject(name).name());
}
public static RDoSlotAssignNode create() {
return RDoSlotAssignNodeGen.create();
}
}
@TypeSystemReference(RTypes.class)
......@@ -157,6 +173,10 @@ public final class MiscNodes {
Object doNewObject(Object classDef) {
return newObjectNode.execute(classDef);
}
public static RDoNewObjectNode create() {
return RDoNewObjectNodeGen.create();
}
}
@TypeSystemReference(RTypes.class)
......
/*
* Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.r.ffi.impl.upcalls;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.interop.ForeignAccess.Factory;
import com.oracle.truffle.api.interop.ForeignAccess.Factory26;
import com.oracle.truffle.api.interop.Message;
import com.oracle.truffle.api.nodes.RootNode;
public abstract class AbstractDowncallForeign implements Factory26, Factory {
@Override
public CallTarget accessIsNull() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
}
@Override
public CallTarget accessIsExecutable() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(true));
}
@Override
public CallTarget accessIsBoxed() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
}
@Override
public CallTarget accessHasSize() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
}
@Override
public CallTarget accessGetSize() {
return null;
}
@Override
public CallTarget accessUnbox() {
return null;
}
@Override
public CallTarget accessRead() {
return null;
}
@Override
public CallTarget accessWrite() {
return null;
}
@Override
public CallTarget accessInvoke(int argumentsLength) {
return null;
}
@Override
public CallTarget accessNew(int argumentsLength) {
return null;
}
@Override
public CallTarget accessKeyInfo() {
return null;
}
@Override
public CallTarget accessKeys() {
return null;
}
@Override
public CallTarget accessIsPointer() {
return Truffle.getRuntime().createCallTarget(RootNode.createConstantNode(false));
}
@Override
public CallTarget accessAsPointer() {
return null;
}
@Override
public CallTarget accessToNative() {
return null;
}
@Override
public CallTarget accessMessage(Message unknown) {
return null;
}
}
......@@ -22,7 +22,19 @@
*/
package com.oracle.truffle.r.ffi.impl.upcalls;
import com.oracle.truffle.r.ffi.impl.nodes.ATTRIB;
import com.oracle.truffle.r.ffi.impl.nodes.AsCharNode;
import com.oracle.truffle.r.ffi.impl.nodes.AsIntegerNode;
import com.oracle.truffle.r.ffi.impl.nodes.AsLogicalNode;
import com.oracle.truffle.r.ffi.impl.nodes.AsRealNode;
import com.oracle.truffle.r.ffi.impl.nodes.CoerceVectorNode;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CADDRNode;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CADRNode;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CARNode;
import com.oracle.truffle.r.ffi.impl.nodes.ListAccessNodes.CDRNode;
import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes.LENGTHNode;
import com.oracle.truffle.r.ffi.processor.RFFICstring;
import com.oracle.truffle.r.ffi.processor.RFFIUpCallNode;
import com.oracle.truffle.r.runtime.data.RDoubleVector;
import com.oracle.truffle.r.runtime.data.RExternalPtr;
import com.oracle.truffle.r.runtime.data.RIntVector;
......@@ -60,14 +72,19 @@ public interface StdUpCallsRFFI {
RStringVector Rf_ScalarString(Object value);
@RFFIUpCallNode(AsIntegerNode.class)
int Rf_asInteger(Object x);
@RFFIUpCallNode(AsRealNode.class)
double Rf_asReal(Object x);
@RFFIUpCallNode(AsLogicalNode.class)
int Rf_asLogical(Object x);
@RFFIUpCallNode(AsCharNode.class)
Object Rf_asChar(Object x);
@RFFIUpCallNode(CoerceVectorNode.class)
Object Rf_coerceVector(Object x, int mode);
Object Rf_mkCharLenCE(@RFFICstring(convert = false) Object bytes, int len, int encoding);
......@@ -89,6 +106,7 @@ public interface StdUpCallsRFFI {
Object Rf_findVarInFrame3(Object envArg, Object symbolArg, int doGet);
@RFFIUpCallNode(ATTRIB.class)
Object ATTRIB(Object obj);
Object Rf_getAttrib(Object obj, Object name);
......@@ -127,6 +145,7 @@ public interface StdUpCallsRFFI {
int Rf_ncols(Object x);
@RFFIUpCallNode(LENGTHNode.class)
int LENGTH(Object x);
int /* void */ SET_STRING_ELT(Object x, long i, Object v);
......@@ -163,12 +182,16 @@ public interface StdUpCallsRFFI {
Object TAG(Object e);
@RFFIUpCallNode(CARNode.class)
Object CAR(Object e);
@RFFIUpCallNode(CDRNode.class)
Object CDR(Object e);
@RFFIUpCallNode(CADRNode.class)
Object CADR(Object e);
@RFFIUpCallNode(CADDRNode.class)
Object CADDR(Object e);
Object CDDR(Object e);
......
......@@ -20,7 +20,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.r.ffi.impl.common;
package com.oracle.truffle.r.ffi.impl.upcalls;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
......
......@@ -40,6 +40,7 @@ import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
......@@ -157,55 +158,27 @@ public final class FFIProcessor extends AbstractProcessor {
for (int i = 0; i < methods.length; i++) {
ExecutableElement m = methods[i];
generateCallClass(m);
generateMessageClass(m);
}
}
private void generateCallClass(ExecutableElement m) throws IOException {
String name = m.getSimpleName().toString();
String callName = name + "Call";
JavaFileObject fileObj = processingEnv.getFiler().createSourceFile("com.oracle.truffle.r.ffi.impl.upcalls." + callName);
Writer w = fileObj.openWriter();
w.append("// GENERATED; DO NOT EDIT\n");
w.append("package ").append("com.oracle.truffle.r.ffi.impl.upcalls").append(";\n\n");
w.append("import com.oracle.truffle.api.interop.ForeignAccess;\n");
w.append("import com.oracle.truffle.api.interop.TruffleObject;\n");
w.append("import com.oracle.truffle.r.runtime.data.RTruffleObject;\n");
w.append("// Checkstyle: stop method name check\n\n");
w.append("public final class ").append(callName).append(" implements RTruffleObject {\n");
w.append('\n');
w.append(" public final UpCallsRFFI upCallsImpl;\n");
w.append('\n');
w.append(" protected ").append(callName).append("(UpCallsRFFI upCallsImpl) {\n");
w.append(" this.upCallsImpl = upCallsImpl;\n");
w.append(" }\n");
w.append('\n');
w.append(" public static boolean isInstance(TruffleObject value) {\n");
w.append(" return value instanceof ").append(callName).append(";\n");
w.append(" }\n");
w.append('\n');
w.append(" @Override\n");
w.append(" public ForeignAccess getForeignAccess() {\n");
w.append(" return ").append(callName).append("MRForeign.ACCESS;\n");
w.append(" }\n");
w.append("}\n");
w.close();
}
private void generateMessageClass(ExecutableElement m) throws IOException {
String name = m.getSimpleName().toString();
String callName = name + "Call";
String returnType = getTypeName(m.getReturnType());
RFFIUpCallNode nodeAnnotation = m.getAnnotation(RFFIUpCallNode.class);
String node = null;
if (nodeAnnotation != null) {
try {
nodeAnnotation.value();
} catch (MirroredTypeException e) {
node = ((TypeElement) processingEnv.getTypeUtils().asElement(e.getTypeMirror())).getQualifiedName().toString();
}
}
// process arguments first to see if unwrap is necessary
List<? extends VariableElement> params = m.getParameters();
StringBuilder arguments = new StringBuilder();
boolean usesUnwrap = false;
// process arguments first to see if unwrap is necessary
int lparams = params.size();
for (int i = 0; i < lparams; i++) {
String is = Integer.toString(i);
int unwrapCount = 0;
for (int i = 0; i < params.size(); i++) {
if (i != 0) {
arguments.append(", ");
}
String paramTypeName = getTypeName(params.get(i).asType());
boolean isScalar = true;
boolean needCast = !paramTypeName.equals("java.lang.Object");
......@@ -213,60 +186,91 @@ public final class FFIProcessor extends AbstractProcessor {
arguments.append('(').append(paramTypeName).append(") ");
}
if (isScalar) {
usesUnwrap = true;
arguments.append("unwrap.unwrap(");
arguments.append("unwrap").append(unwrapCount).append(".unwrap(");
unwrapCount++;
}
arguments.append("arguments[").append(is).append("]");
arguments.append("arguments.get(").append(i).append(")");
if (isScalar) {
arguments.append(')');
}
if (i != lparams - 1) {
arguments.append(", ");
}
}
JavaFileObject fileObj = processingEnv.getFiler().createSourceFile("com.oracle.truffle.r.ffi.impl.upcalls." + callName + "MR");
String name = m.getSimpleName().toString();
String callName = name + "Call";
JavaFileObject fileObj = processingEnv.getFiler().createSourceFile("com.oracle.truffle.r.ffi.impl.upcalls." + callName);
Writer w = fileObj.openWriter();
w.append("// GENERATED; DO NOT EDIT\n");
w.append("package ").append("com.oracle.truffle.r.ffi.impl.upcalls").append(";\n\n");
w.append("import com.oracle.truffle.api.interop.MessageResolution;\n");
w.append("import com.oracle.truffle.api.interop.Resolve;\n");
w.append("import com.oracle.truffle.api.nodes.Node;\n");
if (usesUnwrap) {
w.append("import com.oracle.truffle.r.ffi.impl.common.UpCallUnwrap;\n");
w.append("\n");
w.append("package com.oracle.truffle.r.ffi.impl.upcalls;\n");
w.append("\n");
w.append("import java.util.List;\n");
w.append("\n");
w.append("import com.oracle.truffle.api.CallTarget;\n");
w.append("import com.oracle.truffle.api.Truffle;\n");
w.append("import com.oracle.truffle.api.frame.VirtualFrame;\n");
w.append("import com.oracle.truffle.api.interop.ForeignAccess;\n");
w.append("import com.oracle.truffle.api.interop.TruffleObject;\n");
w.append("import com.oracle.truffle.api.nodes.RootNode;\n");
w.append("import com.oracle.truffle.r.ffi.impl.upcalls.UpCallsRFFI;\n");
w.append("import com.oracle.truffle.r.runtime.data.RTruffleObject;\n");
w.append("\n");
w.append("// Checkstyle: stop method name check\n");
w.append("\n");
w.append("final class ").append(callName).append(" implements RTruffleObject {\n");
w.append('\n');
if (node == null) {
w.append(" private final UpCallsRFFI upCallsImpl;\n");
w.append('\n');
}
w.append("// Checkstyle: stop method name check\n\n");
w.append("@MessageResolution(receiverType = ").append(name).append("Call.class)\n");
w.append("public class ").append(callName).append("MR {\n");
w.append(" @Resolve(message = \"EXECUTE\")\n");
w.append(" public abstract static class ").append(callName).append("Execute extends Node {\n");
if (usesUnwrap) {
w.append("\n @Child private UpCallUnwrap unwrap = new UpCallUnwrap();\n\n");
w.append(" ").append(callName).append("(UpCallsRFFI upCallsImpl) {\n");
w.append(" assert upCallsImpl != null;\n");
if (node == null) {
w.append(" this.upCallsImpl = upCallsImpl;\n");
}
w.append(" }\n");
w.append('\n');
w.append(" private static final class ").append(callName).append("Factory extends AbstractDowncallForeign {\n");
w.append(" @Override\n");
w.append(" public boolean canHandle(TruffleObject obj) {\n");
w.append(" return obj instanceof ").append(callName).append(";\n");
w.append(" }\n");
w.append("\n");
w.append(" @Override\n");
w.append(" public CallTarget accessExecute(int argumentsLength) {\n");
w.append(" return Truffle.getRuntime().createCallTarget(new RootNode(null) {\n");
w.append("\n");
if (unwrapCount > 0) {
for (int i = 0; i < unwrapCount; i++) {
w.append(" @Child private UpCallUnwrap unwrap").append(Integer.toString(i)).append(" = new UpCallUnwrap();\n");
}
w.append("\n");
}
w.append(" protected ").append(returnType).append(" access(").append(callName).append(" receiver, ");
if (params.size() == 0) {
w.append("@SuppressWarnings(\"unused\") ");
if (node != null) {
w.append(" @Child private ").append(node).append(" node").append(" = ").append(node).append(".create();\n");
w.append("\n");
}
w.append("Object[] arguments) {\n");
w.append(" ").append("return").append(" receiver.upCallsImpl.").append(name).append("(");
w.append(arguments);
w.append(");\n");
w.append(" @Override\n");
w.append(" public Object execute(VirtualFrame frame) {\n");
w.append(" List<Object> arguments = ForeignAccess.getArguments(frame);\n");
w.append(" assert arguments.size() == ").append(Integer.toString(params.size())).append(" : \"wrong number of arguments passed to ").append(name).append("\";\n");
if (node != null) {
w.append(" return node.executeObject(").append(arguments).append(");\n");
} else {
w.append(" return ((").append(callName).append(") ForeignAccess.getReceiver(frame)).upCallsImpl.").append(name).append("(").append(arguments).append(");\n");
}
w.append(" }\n");
w.append(" });\n");
w.append(" }\n");
w.append(" }\n");
w.append("\n");
w.append(" @Resolve(message = \"IS_EXECUTABLE\")\n");
w.append(" public abstract static class ").append(callName).append("IsExecutable extends Node {\n");
w.append(" protected Object access(@SuppressWarnings(\"unused\") ").append(callName).append(" receiver) {\n");
w.append(" return true;\n");
w.append(" }\n");
w.append(" private static final ForeignAccess ACCESS = ForeignAccess.create(new ").append(callName).append("Factory(), null);\n");
w.append("\n");
w.append(" @Override\n");
w.append(" public ForeignAccess getForeignAccess() {\n");
w.append(" return ACCESS;\n");
w.append(" }\n");
w.append("}\n");
w.close();
}
private void generateCallbacks(ExecutableElement[] methods) throws IOException {
......
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.truffle.r.ffi.processor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* Tags upcall functions that have a corresponding node implementation.
*/
@Target({ElementType.METHOD})
public @interface RFFIUpCallNode {
Class<?> value();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment