diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java index f53da4a554de3776f26857d0dbc47ace227c45ba..81632089f04e3f910b51f984c761a6d3d5de4a5a 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.engine.interop; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; @@ -39,10 +40,12 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.engine.interop.REnvironmentMRFactory.REnvironmentKeyInfoImplNodeGen; import com.oracle.truffle.r.engine.interop.REnvironmentMRFactory.REnvironmentReadImplNodeGen; +import com.oracle.truffle.r.engine.interop.REnvironmentMRFactory.REnvironmentRemoveImplNodeGen; import com.oracle.truffle.r.engine.interop.REnvironmentMRFactory.REnvironmentWriteImplNodeGen; import com.oracle.truffle.r.nodes.access.vector.ElementAccessMode; import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode; import com.oracle.truffle.r.nodes.access.vector.ReplaceVectorNode; +import com.oracle.truffle.r.nodes.builtin.base.Rm; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RObject; import com.oracle.truffle.r.runtime.env.REnvironment; @@ -73,6 +76,15 @@ public class REnvironmentMR { } } + @Resolve(message = "REMOVE") + public abstract static class REnvironmentRemoveNode extends Node { + @Child private REnvironmentRemoveImplNode removeNode = REnvironmentRemoveImplNodeGen.create(); + + protected Object access(VirtualFrame frame, REnvironment receiver, Object identifier) { + return removeNode.execute(frame, receiver, identifier); + } + } + @Resolve(message = "KEYS") public abstract static class REnvironmentKeysNode extends Node { @@ -201,6 +213,41 @@ public class REnvironmentMR { } } + abstract static class REnvironmentRemoveImplNode extends Node { + + private final ConditionProfile unknownIdentifier = ConditionProfile.createBinaryProfile(); + + protected abstract Object execute(VirtualFrame frame, TruffleObject receiver, Object identifier); + + @Specialization + protected Object access(VirtualFrame frame, REnvironment receiver, String identifier, + @Cached("createKeyInfoNode()") REnvironmentKeyInfoImplNode keyInfo) { + int info = keyInfo.execute(receiver, identifier); + if (unknownIdentifier.profile(!KeyInfo.isExisting(info))) { + throw UnknownIdentifierException.raise("" + identifier); + } + return remove(receiver, identifier); + } + + @TruffleBoundary + private boolean remove(REnvironment receiver, String identifier) { + try { + return Rm.removeFromEnv(receiver, identifier, true); + } catch (REnvironment.PutException ex) { + return false; + } + } + + @Fallback + protected Object access(@SuppressWarnings("unused") TruffleObject receiver, Object identifier) { + throw UnknownIdentifierException.raise("" + identifier); + } + + protected REnvironmentKeyInfoImplNode createKeyInfoNode() { + return REnvironmentKeyInfoImplNodeGen.create(); + } + } + abstract static class REnvironmentKeyInfoImplNode extends Node { protected abstract int execute(REnvironment receiver, Object identifier); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java index f7433458c16cbc4acddd19d78abe95026e7e0015..bcdcb01f5c980b569483a2761eb3c6875d8dbccd 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Rm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -77,7 +77,7 @@ public abstract class Rm extends RBuiltinNode.Arg3 { return RNull.instance; } - private static boolean removeFromEnv(REnvironment envir, String key, boolean inherits) throws PutException { + public static boolean removeFromEnv(REnvironment envir, String key, boolean inherits) throws PutException { REnvironment curEnv = envir; while (curEnv != REnvironment.emptyEnv()) { try { diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REnvironmentMRTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REnvironmentMRTest.java index 6c55cf3c64e699cd8112d8c844a23c29c1ec1098..7312f09e9032840b159cd9458d775fa77dcc2808 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REnvironmentMRTest.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/interop/REnvironmentMRTest.java @@ -128,6 +128,21 @@ public class REnvironmentMRTest extends AbstractMRTest { assertFalse(KeyInfo.isInternal(info)); } + @Test + public void testRemove() throws Exception { + assertInteropException(() -> ForeignAccess.sendRemove(Message.REMOVE.createNode(), createEmptyTruffleObject(), "nnoonnee"), UnknownIdentifierException.class); + + REnvironment e = (REnvironment) createTruffleObjects()[0]; + assertInteropException(() -> ForeignAccess.sendRemove(Message.REMOVE.createNode(), e, "nnoonnee"), UnknownIdentifierException.class); + + assertEquals("aaa", ForeignAccess.sendRead(Message.READ.createNode(), e, "s")); + assertEquals(true, ForeignAccess.sendRemove(Message.REMOVE.createNode(), e, "s")); + assertInteropException(() -> ForeignAccess.sendRead(Message.READ.createNode(), e, "s"), UnknownIdentifierException.class); + + e.lock(true); + assertEquals(false, ForeignAccess.sendRemove(Message.REMOVE.createNode(), e, "i")); + } + @Override protected TruffleObject[] createTruffleObjects() throws Exception { Source src = Source.newBuilder("R", "e <- new.env(); e$s <- 'aaa'; e$i <- 123L; e$d <- 123.1; e$b <- TRUE; e$fn <- function() {}; e$n <- NULL; e$l <- 666; lockBinding('l', e); e", diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java index a08bb5bcb29dee37e8d069f979b2041abbff924c..d6e9c827b8c1402b42d3cb2555870c936979928f 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java @@ -361,7 +361,7 @@ public final class FastRSession implements RSession { } public static void execInContext(Context context, Callable<Object> c) { - execInContext(context, c, (Class<?>) null); + execInContext(context, c, (Class<?>[]) null); } // TODO: export/importSymbol