diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java index bd7f56a661f746b98a2bfa1689381bfd7778fef1..ee74036ba299c2a123f3cd6a74c7fdc23a9f8bf4 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java @@ -307,49 +307,90 @@ public abstract class ExtractVectorNode extends RBaseNode { } } - protected static ReadElementNode createReadElement() { + static ReadElementNode createReadElement() { return new ReadElementNode(); } - static final class ReadElementNode extends RBaseNode { + abstract static class AccessElementNode extends RBaseNode { - @Child private Node foreignRead = com.oracle.truffle.api.interop.Message.READ.createNode(); - @Child private Node keyInfoNode = com.oracle.truffle.api.interop.Message.KEY_INFO.createNode(); - @Child private Node hasSizeNode = com.oracle.truffle.api.interop.Message.HAS_SIZE.createNode(); - @Child private CastStringNode castNode = CastStringNode.create(); - @Child private FirstStringNode firstString = createFirstString(); + @Child private Node hasSizeNode; + @Child private CastStringNode castNode; + @Child private FirstStringNode firstString; private final ConditionProfile isIntProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile isDoubleProfile = ConditionProfile.createBinaryProfile(); - public Object execute(Object position, TruffleObject object) throws InteropException { + protected final Object extractPosition(Object position) { Object pos = position; if (isIntProfile.profile(pos instanceof Integer)) { pos = ((int) pos) - 1; } else if (isDoubleProfile.profile(pos instanceof Double)) { pos = ((double) pos) - 1; } else if (pos instanceof RAbstractDoubleVector) { - pos = ((RAbstractDoubleVector) pos).getDataAt(0) - 1; + RAbstractDoubleVector vector = (RAbstractDoubleVector) pos; + if (vector.getLength() == 0) { + throw error(RError.Message.GENERIC, "invalid index during foreign access"); + } + pos = vector.getDataAt(0) - 1; } else if (pos instanceof RAbstractIntVector) { - pos = ((RAbstractIntVector) pos).getDataAt(0) - 1; + RAbstractIntVector vector = (RAbstractIntVector) pos; + if (vector.getLength() == 0) { + throw error(RError.Message.GENERIC, "invalid index during foreign access"); + } + pos = vector.getDataAt(0) - 1; } else if (pos instanceof RAbstractStringVector) { + if (castNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + castNode = insert(CastStringNode.create()); + } + if (firstString == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + firstString = insert(createFirstString()); + } pos = firstString.executeString(castNode.doCast(pos)); } else if (!(pos instanceof String)) { throw error(RError.Message.GENERIC, "invalid index during foreign access"); } + return pos; + } + protected final boolean hasSize(TruffleObject object) { + if (hasSizeNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + hasSizeNode = insert(com.oracle.truffle.api.interop.Message.HAS_SIZE.createNode()); + } + return ForeignAccess.sendHasSize(hasSizeNode, object); + } + } + + static final class ReadElementNode extends AccessElementNode { + + @Child private Node foreignRead = com.oracle.truffle.api.interop.Message.READ.createNode(); + @Child private Node classForeignRead; + @Child private Node keyInfoNode; + + public Object execute(Object position, TruffleObject object) throws InteropException { + Object pos = extractPosition(position); + if (keyInfoNode == null) { + try { + return ForeignAccess.sendRead(foreignRead, object, pos); + } catch (InteropException e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + keyInfoNode = insert(com.oracle.truffle.api.interop.Message.KEY_INFO.createNode()); + } + } int info = ForeignAccess.sendKeyInfo(keyInfoNode, object, pos); - if (KeyInfo.isReadable(info) || ForeignAccess.sendHasSize(hasSizeNode, object)) { + if (KeyInfo.isReadable(info) || hasSize(object)) { return ForeignAccess.sendRead(foreignRead, object, pos); } else if (pos instanceof String && !KeyInfo.isExisting(info) && JavaInterop.isJavaObject(Object.class, object)) { - TruffleObject clazz = toJavaClass(object); - info = ForeignAccess.sendKeyInfo(keyInfoNode, clazz, pos); - if (KeyInfo.isReadable(info)) { - return ForeignAccess.sendRead(foreignRead, clazz, pos); + if (classForeignRead == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + classForeignRead = insert(com.oracle.truffle.api.interop.Message.READ.createNode()); } + return ForeignAccess.sendRead(classForeignRead, toJavaClass(object), pos); } + CompilerDirectives.transferToInterpreter(); throw error(RError.Message.GENERIC, "invalid index/identifier during foreign access: " + pos); - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java index 7c9a69fd4becbae952b07825bd1ffae34f93574a..86bfe74041bc4c902f63d135acd8d3261005a66c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java @@ -36,7 +36,7 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; -import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode.AccessElementNode; import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode.ExtractSingleName; import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode.ReadElementNode; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; @@ -44,7 +44,6 @@ import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; -import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.FirstStringNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; @@ -61,10 +60,7 @@ import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.env.REnvironment.PutException; @@ -304,48 +300,38 @@ public abstract class ReplaceVectorNode extends RBaseNode { return new WriteElementNode(); } - static final class WriteElementNode extends RBaseNode { + static final class WriteElementNode extends AccessElementNode { - @Child private Node keyInfoNode = com.oracle.truffle.api.interop.Message.KEY_INFO.createNode(); - @Child private Node hasSizeNode = com.oracle.truffle.api.interop.Message.HAS_SIZE.createNode(); + @Child private Node keyInfoNode; @Child private Node foreignWrite = com.oracle.truffle.api.interop.Message.WRITE.createNode(); + @Child private Node classForeignWrite; @Child private R2Foreign r2Foreign = R2Foreign.create(); - @Child private CastStringNode castNode = CastStringNode.create(); - @Child private FirstStringNode firstString = ExtractVectorNode.createFirstString(); - - private final ConditionProfile isIntProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile isDoubleProfile = ConditionProfile.createBinaryProfile(); private void execute(Object position, TruffleObject object, Object writtenValue) throws InteropException { - Object pos = position; - if (isIntProfile.profile(pos instanceof Integer)) { - pos = ((int) pos) - 1; - } else if (isDoubleProfile.profile(pos instanceof Double)) { - pos = ((double) pos) - 1; - } else if (pos instanceof RAbstractDoubleVector) { - pos = ((RAbstractDoubleVector) pos).getDataAt(0) - 1; - } else if (pos instanceof RAbstractIntVector) { - pos = ((RAbstractIntVector) pos).getDataAt(0) - 1; - } else if (pos instanceof RAbstractStringVector) { - String string = firstString.executeString(castNode.doCast(pos)); - pos = string; - } else if (!(pos instanceof String)) { - throw error(RError.Message.GENERIC, "invalid index during foreign access"); + Object pos = extractPosition(position); + Object value = r2Foreign.execute(writtenValue); + if (keyInfoNode == null) { + try { + ForeignAccess.sendWrite(foreignWrite, object, pos, value); + return; + } catch (InteropException e) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + keyInfoNode = insert(com.oracle.truffle.api.interop.Message.KEY_INFO.createNode()); + } } - int info = ForeignAccess.sendKeyInfo(keyInfoNode, object, pos); - if (KeyInfo.isWritable(info) || ForeignAccess.sendHasSize(hasSizeNode, object) || - (pos instanceof String && !JavaInterop.isJavaObject(Object.class, object))) { - ForeignAccess.sendWrite(foreignWrite, object, pos, r2Foreign.execute(writtenValue)); + if (KeyInfo.isWritable(info) || hasSize(object)) { + ForeignAccess.sendWrite(foreignWrite, object, pos, value); return; } else if (pos instanceof String && !KeyInfo.isExisting(info) && JavaInterop.isJavaObject(Object.class, object)) { - TruffleObject clazz = toJavaClass(object); - info = ForeignAccess.sendKeyInfo(keyInfoNode, clazz, pos); - if (KeyInfo.isWritable(info)) { - ForeignAccess.sendWrite(foreignWrite, clazz, pos, r2Foreign.execute(writtenValue)); - return; + if (classForeignWrite == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + classForeignWrite = insert(com.oracle.truffle.api.interop.Message.WRITE.createNode()); } + ForeignAccess.sendWrite(classForeignWrite, toJavaClass(object), pos, value); + return; } + CompilerDirectives.transferToInterpreter(); throw error(RError.Message.GENERIC, "invalid index/identifier during foreign access: " + pos); } }