From b00e2147a1cd1b9feb8e32a4b9cc239eaf53622c Mon Sep 17 00:00:00 2001
From: Florian Angerer <florian.angerer@oracle.com>
Date: Mon, 9 Oct 2017 10:30:48 +0200
Subject: [PATCH] Simulating R's precious list using a map with object count.

---
 .../ffi/impl/common/JavaUpCallsRFFIImpl.java  | 24 ++++++++++++++-----
 .../truffle/r/runtime/ffi/RFFIContext.java    |  5 +++-
 2 files changed, 22 insertions(+), 7 deletions(-)

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 afe1fbe86e..061fc37d80 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 d7c4b530de..407d1eae6f 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);
 
-- 
GitLab