diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java index afe1fbe86e60e3a01bf8ecf1449578dbb6bce7e1..061fc37d8041dd88e6331abf4430ea91cd99bbc7 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java @@ -32,9 +32,10 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -1598,8 +1599,11 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @TruffleBoundary public void R_PreserveObject(Object obj) { guaranteeInstanceOf(obj, RObject.class); - HashSet<RObject> list = getContext().preserveList; - list.add((RObject) obj); + IdentityHashMap<RObject, AtomicInteger> preserveList = getContext().preserveList; + AtomicInteger prevCnt = preserveList.putIfAbsent((RObject) obj, new AtomicInteger(1)); + if (prevCnt != null) { + prevCnt.incrementAndGet(); + } } @Override @@ -1607,9 +1611,17 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { public void R_ReleaseObject(Object obj) { guaranteeInstanceOf(obj, RObject.class); RFFIContext context = getContext(); - HashSet<RObject> list = context.preserveList; - if (list.remove(obj)) { - context.registerReferenceUsedInNative(obj); + IdentityHashMap<RObject, AtomicInteger> preserveList = context.preserveList; + AtomicInteger atomicInteger = preserveList.get(obj); + if (atomicInteger != null) { + int decrementAndGet = atomicInteger.decrementAndGet(); + if (decrementAndGet == 0) { + // remove from "list" + preserveList.remove(obj); + context.registerReferenceUsedInNative(obj); + } + } else { + // TODO report ? } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java index d7c4b530deb07b92c8c632c3cfb218ff5de1603a..407d1eae6fca4c187f343ae3998ea3990c2feb4f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIContext.java @@ -23,7 +23,10 @@ package com.oracle.truffle.r.runtime.ffi; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.concurrent.atomic.AtomicInteger; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.TruffleObject; @@ -74,7 +77,7 @@ public abstract class RFFIContext extends RFFI { * FastR equivalent of GNUR's special dedicated global list that is GC root and so any vectors * added to it will be guaranteed to be preserved. */ - public final HashSet<RObject> preserveList = new HashSet<>(); + public final IdentityHashMap<RObject, AtomicInteger> preserveList = new IdentityHashMap<>(); public abstract TruffleObject lookupNativeFunction(NativeFunction function);