Merge "Adjust NativeAllocationRegistry for new accounting"
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 4d6b8c7e..d2f0317 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -19,6 +19,7 @@
 import dalvik.annotation.compat.UnsupportedAppUsage;
 import dalvik.annotation.optimization.FastNative;
 import java.lang.ref.FinalizerReference;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.function.Consumer;
@@ -67,6 +68,13 @@
 
     private int targetSdkVersion = SDK_VERSION_CUR_DEVELOPMENT;
 
+    // notifyNativeAllocationsInternal (below) should be called every notifyNativeInterval
+    // allocations. Initialized on demand to allow completely static class initialization.
+    private int notifyNativeInterval;
+
+    // Allocations since last call to native layer. See notifyNativeAllocation().
+    private final AtomicInteger allocationCount = new AtomicInteger(0);
+
     /**
      * Prevents this class from being instantiated.
      */
@@ -163,12 +171,14 @@
     @libcore.api.CorePlatformApi
     public float setTargetHeapUtilization(float newTarget) {
         if (newTarget <= 0.0f || newTarget >= 1.0f) {
-            throw new IllegalArgumentException(newTarget +
-                    " out of range (0,1)");
+            throw new IllegalArgumentException(newTarget + " out of range (0,1)");
         }
-        /* Synchronize to make sure that only one thread gets
-         * a given "old" value if both update at the same time.
-         * Allows for reliable save-and-restore semantics.
+        /* The native code assumes a value >= 0.1. Clamp it to that. */
+        if (newTarget < 0.1f) {
+            newTarget = 0.1f;
+        }
+        /* Synchronize to make sure that only one thread gets a given "old" value if both
+         * update at the same time.  Allows for reliable save-and-restore semantics.
          */
         synchronized (this) {
             float oldTarget = getTargetHeapUtilization();
@@ -375,18 +385,69 @@
      * function requests a concurrent GC. If the native bytes allocated exceeds a second higher
      * watermark, it is determined that the application is registering native allocations at an
      * unusually high rate and a GC is performed inside of the function to prevent memory usage
-     * from excessively increasing.
+     * from excessively increasing. Memory allocated via system malloc() should not be included
+     * in this count. If only malloced() memory is allocated, bytes should be zero.
+     * The argument must be the same as that later passed to registerNativeFree(), but may
+     * otherwise be approximate.
      */
     @UnsupportedAppUsage
     @libcore.api.CorePlatformApi
-    public native void registerNativeAllocation(int bytes);
+    public void registerNativeAllocation(int bytes) {
+        if (bytes == 0) {
+            notifyNativeAllocation();
+        } else {
+            registerNativeAllocationInternal(bytes);
+        }
+    }
+
+    private native void registerNativeAllocationInternal(int bytes);
 
     /**
      * Registers a native free by reducing the number of native bytes accounted for.
      */
     @UnsupportedAppUsage
     @libcore.api.CorePlatformApi
-    public native void registerNativeFree(int bytes);
+    public void registerNativeFree(int bytes) {
+        if (bytes != 0) {
+            registerNativeFreeInternal(bytes);
+        }
+    }
+
+    private native void registerNativeFreeInternal(int bytes);
+
+    /**
+     * Return the number of native objects that are reported by a single call to
+     * notifyNativeAllocation().
+     */
+    private static native int getNotifyNativeInterval();
+
+    /**
+     * Report a native malloc()-only allocation to the GC.
+     */
+    private void notifyNativeAllocation() {
+        // Minimize JNI calls by notifying once every notifyNativeInterval allocations.
+        // The native code cannot do anything without calling mallinfo(), which is too
+        // expensive to perform on every allocation. To avoid the JNI overhead on every
+        // allocation, we do the sampling here, rather than in native code.
+        // Initialize notifyNativeInterval carefully. Multiple initializations may race.
+        int myNotifyNativeInterval = notifyNativeInterval;
+        if (myNotifyNativeInterval == 0) {
+            // This can race. By Java rules, that's OK.
+            myNotifyNativeInterval = notifyNativeInterval = getNotifyNativeInterval();
+        }
+        // myNotifyNativeInterval is correct here. If another thread won the initial race,
+        // notifyNativeInterval may not be.
+        if (allocationCount.addAndGet(1) % myNotifyNativeInterval == 0) {
+            notifyNativeAllocationsInternal();
+        }
+    }
+
+    /**
+     * Report to the GC that roughly notifyNativeInterval native malloc()-based
+     * allocations have occurred since the last call to notifyNativeAllocationsInternal().
+     * Hints that we should check whether a GC is required.
+     */
+    private native void notifyNativeAllocationsInternal();
 
     /**
      * Wait for objects to be finalized.
diff --git a/luni/src/main/java/java/math/BigInt.java b/luni/src/main/java/java/math/BigInt.java
index 9faac81..de4cdd8 100644
--- a/luni/src/main/java/java/math/BigInt.java
+++ b/luni/src/main/java/java/math/BigInt.java
@@ -27,7 +27,7 @@
 final class BigInt {
 
     private static NativeAllocationRegistry registry = new NativeAllocationRegistry(
-            BigInt.class.getClassLoader(), NativeBN.getNativeFinalizer(), NativeBN.size());
+            BigInt.class.getClassLoader(), NativeBN.getNativeFinalizer());
 
     /* Fields used for the internal representation. */
     @ReachabilitySensitive
diff --git a/luni/src/main/java/java/math/NativeBN.java b/luni/src/main/java/java/math/NativeBN.java
index d269f2e..ab9b2e0 100644
--- a/luni/src/main/java/java/math/NativeBN.java
+++ b/luni/src/main/java/java/math/NativeBN.java
@@ -133,10 +133,4 @@
     public static native long getNativeFinalizer();
     // &BN_free
 
-    /** Returns the expected size of the native allocation for a BIGNUM.
-     */
-    public static long size() {
-        // 36 bytes is an empirically determined approximation.
-        return 36;
-    }
 }
diff --git a/luni/src/main/java/libcore/util/NativeAllocationRegistry.java b/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
index c1b4fe0..5c8e831 100644
--- a/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
+++ b/luni/src/main/java/libcore/util/NativeAllocationRegistry.java
@@ -65,13 +65,21 @@
      * native bytes this kind of native allocation takes up. Different
      * NativeAllocationRegistrys must be used to register native allocations
      * with different estimated sizes, even if they use the same
-     * <code>freeFunction</code>.
+     * <code>freeFunction</code>. This is used to help inform the garbage
+     * collector about the possible need for collection. Memory allocated with
+     * native malloc is implicitly included, and ideally should not be included in this
+     * argument. For malloc-based native allocations that are expected to be under
+     * 100Kbytes or so, the NativeAllocationRegistry(ClassLoader,long) constructor is
+     * preferred.
+     * <p>
      * @param classLoader  ClassLoader that was used to load the native
      *                     library freeFunction belongs to.
      * @param freeFunction address of a native function used to free this
      *                     kind of native allocation
      * @param size         estimated size in bytes of this kind of native
-     *                     allocation
+     *                     allocation. Should ideally exclude memory allocated by system
+     *                     malloc. However including it will simply double-count it,
+     *                     typically resulting in slightly increased GC frequency.
      * @throws IllegalArgumentException If <code>size</code> is negative
      */
     @libcore.api.CorePlatformApi
@@ -79,13 +87,20 @@
         if (size < 0) {
             throw new IllegalArgumentException("Invalid native allocation size: " + size);
         }
-
         this.classLoader = classLoader;
         this.freeFunction = freeFunction;
         this.size = size;
     }
 
     /**
+     * Equivalent to NativeAllocationRegistry(classLoader, freeFunction, 0).
+     * Should be used when all native memory is allocated via system malloc.
+     */
+    public NativeAllocationRegistry(ClassLoader classLoader, long freeFunction) {
+        this(classLoader, freeFunction, 0);
+    }
+
+    /**
      * Registers a new native allocation and associated Java object with the
      * runtime.
      * This NativeAllocationRegistry's <code>freeFunction</code> will
@@ -223,6 +238,8 @@
         }
     }
 
+    // Inform the garbage collector of the allocation. The size = 0 case is optimized in
+    // VMRuntime.
     // TODO: Change the runtime to support passing the size as a long instead
     // of an int. For now, we clamp the size to fit.
     private static void registerNativeAllocation(long size) {
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
index 47d8b80..0481722 100644
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ b/luni/src/main/native/java_util_regex_Matcher.cpp
@@ -158,16 +158,6 @@
     return reinterpret_cast<jlong>(&Matcher_free);
 }
 
-// Return a guess of the amount of native memory to be deallocated by a typical call to
-// Matcher_free().
-static jint Matcher_nativeSize(JNIEnv*, jclass) {
-    // This value can be tuned. 200 was found to cause performance issues (b/111141123) so 10000
-    // is being used instead. If the value is too small, there's no pressure to collect matchers,
-    // too large and we'll run GC too often.
-    // Also see b/111141123.
-    return 10000;
-}
-
 static jint Matcher_findImpl(JNIEnv* env, jclass, jlong addr, jint startIndex, jintArray offsets) {
     MatcherState* state = toMatcherState(addr);
     UBool result = state->matcher()->find(startIndex, state->status());
@@ -273,7 +263,6 @@
     NATIVE_METHOD(Matcher, hitEndImpl, "(J)Z"),
     NATIVE_METHOD(Matcher, lookingAtImpl, "(J[I)Z"),
     NATIVE_METHOD(Matcher, matchesImpl, "(J[I)Z"),
-    NATIVE_METHOD(Matcher, nativeSize, "()I"),
     NATIVE_METHOD(Matcher, openImpl, "(J)J"),
     NATIVE_METHOD(Matcher, requireEndImpl, "(J)Z"),
     NATIVE_METHOD(Matcher, setInputImpl, "(JLjava/lang/String;II)V"),
diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp
index f4d23cb..ac13346 100644
--- a/luni/src/main/native/java_util_regex_Pattern.cpp
+++ b/luni/src/main/native/java_util_regex_Pattern.cpp
@@ -75,12 +75,6 @@
     return reinterpret_cast<jlong>(&Pattern_free);
 }
 
-// Return a guess of the amount of native memory to be deallocated by a typical call to
-// Pattern_free().
-static jint Pattern_nativeSize(JNIEnv*, jclass) {
-    return 500;  // Very rough guess based on a quick look at the implementation.
-}
-
 static jlong Pattern_compileImpl(JNIEnv* env, jclass, jstring javaRegex, jint flags) {
     flags |= UREGEX_ERROR_ON_UNKNOWN_ESCAPES;
 
@@ -103,7 +97,6 @@
 static JNINativeMethod gMethods[] = {
     NATIVE_METHOD(Pattern, compileImpl, "(Ljava/lang/String;I)J"),
     NATIVE_METHOD(Pattern, getNativeFinalizer, "()J"),
-    NATIVE_METHOD(Pattern, nativeSize, "()I"),
 };
 
 void register_java_util_regex_Pattern(JNIEnv* env) {
diff --git a/ojluni/src/main/java/java/util/regex/Matcher.java b/ojluni/src/main/java/java/util/regex/Matcher.java
index e92cb9d..edeecf3 100644
--- a/ojluni/src/main/java/java/util/regex/Matcher.java
+++ b/ojluni/src/main/java/java/util/regex/Matcher.java
@@ -150,7 +150,7 @@
     private Runnable nativeFinalizer;
 
     private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
-            Matcher.class.getClassLoader(), getNativeFinalizer(), nativeSize());
+            Matcher.class.getClassLoader(), getNativeFinalizer());
 
     /**
      * The index of the last position appended in a substitution.
@@ -1227,7 +1227,6 @@
     private static native boolean hitEndImpl(long addr);
     private static native boolean lookingAtImpl(long addr, int[] offsets);
     private static native boolean matchesImpl(long addr, int[] offsets);
-    private static native int nativeSize();
     private static native long openImpl(long patternAddr);
     private static native boolean requireEndImpl(long addr);
     private static native void setInputImpl(long addr, String s, int start, int end);
diff --git a/ojluni/src/main/java/java/util/regex/Pattern.java b/ojluni/src/main/java/java/util/regex/Pattern.java
index 04f4f80..437382b 100644
--- a/ojluni/src/main/java/java/util/regex/Pattern.java
+++ b/ojluni/src/main/java/java/util/regex/Pattern.java
@@ -949,7 +949,7 @@
     transient long address;
 
     private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
-            Pattern.class.getClassLoader(), getNativeFinalizer(), nativeSize());
+            Pattern.class.getClassLoader(), getNativeFinalizer());
     // END Android-changed: reimplement matching logic natively via ICU.
 
     /**
@@ -1435,7 +1435,6 @@
 
     private static native long compileImpl(String regex, int flags);
     private static native long getNativeFinalizer();
-    private static native int nativeSize();
     // END Android-changed: reimplement matching logic natively via ICU.
 
     /**