Implement -Xjnigreflimit.

Change-Id: Iaa31cf4ea4f90fc76baa4472b67fe6c2cc0e0277
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 9480644..02c8513 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -24,6 +24,8 @@
 #include "stringpiece.h"
 #include "thread.h"
 
+namespace art {
+
 static const size_t kMonitorsInitial = 32; // Arbitrary.
 static const size_t kMonitorsMax = 4096; // Arbitrary sanity check.
 
@@ -33,13 +35,18 @@
 static const size_t kPinTableInitial = 16; // Arbitrary.
 static const size_t kPinTableMax = 1024; // Arbitrary sanity check.
 
-static const size_t kGlobalsInitial = 512; // Arbitrary.
-static const size_t kGlobalsMax = 51200; // Arbitrary sanity check.
+static size_t gGlobalsInitial = 512; // Arbitrary.
+static size_t gGlobalsMax = 51200; // Arbitrary sanity check.
 
 static const size_t kWeakGlobalsInitial = 16; // Arbitrary.
 static const size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check.
 
-namespace art {
+void SetJniGlobalsMax(size_t max) {
+  if (max != 0) {
+    gGlobalsMax = max;
+    gGlobalsInitial = std::min(gGlobalsInitial, gGlobalsMax);
+  }
+}
 
 /*
  * Add a local reference for an object to the current stack frame.  When
@@ -2662,7 +2669,7 @@
       pins_lock("JNI pin table lock"),
       pin_table("pin table", kPinTableInitial, kPinTableMax),
       globals_lock("JNI global reference table lock"),
-      globals(kGlobalsInitial, kGlobalsMax, kGlobal),
+      globals(gGlobalsInitial, gGlobalsMax, kGlobal),
       weak_globals_lock("JNI weak global reference table lock"),
       weak_globals(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
       libraries_lock("JNI shared libraries map lock"),
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 329a5af..09efd68 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -23,6 +23,7 @@
 class Method;
 class Thread;
 
+void SetJniGlobalsMax(size_t max);
 void JniAbort(const char* jni_function_name);
 void* FindNativeMethod(Thread* thread);
 
diff --git a/src/reference_table.cc b/src/reference_table.cc
index 1b20b52..2281eac 100644
--- a/src/reference_table.cc
+++ b/src/reference_table.cc
@@ -22,9 +22,8 @@
 
 namespace art {
 
-ReferenceTable::ReferenceTable(const char* name,
-    size_t initial_size, size_t max_size)
-        : name_(name), max_size_(max_size) {
+ReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max_size)
+    : name_(name), max_size_(max_size) {
   CHECK_LE(initial_size, max_size);
   entries_.reserve(initial_size);
 }
diff --git a/src/runtime.cc b/src/runtime.cc
index 31ba262..be9c8fa 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -177,6 +177,20 @@
   return 0;
 }
 
+size_t ParseIntegerOrDie(const StringPiece& s) {
+  StringPiece::size_type colon = s.find(':');
+  if (colon == StringPiece::npos) {
+    LOG(FATAL) << "Missing integer: " << s;
+  }
+  const char* begin = &s.data()[colon + 1];
+  char* end;
+  size_t result = strtoul(begin, &end, 10);
+  if (begin == end || *end != '\0') {
+    LOG(FATAL) << "Failed to parse integer in: " << s;
+  }
+  return result;
+}
+
 void LoadJniLibrary(JavaVMExt* vm, const char* name) {
   // TODO: OS_SHARED_LIB_FORMAT_STR
   std::string mapped_name(StringPrintf("lib%s.so", name));
@@ -212,6 +226,7 @@
 
   parsed->is_zygote_ = false;
 
+  parsed->jni_globals_max_ = 0;
   parsed->lock_profiling_threshold_ = 0;
   parsed->hook_is_sensitive_thread_ = NULL;
 
@@ -287,8 +302,10 @@
       for (size_t i = 0; i < verbose_options.size(); ++i) {
         parsed->verbose_.insert(verbose_options[i]);
       }
+    } else if (option.starts_with("-Xjnigreflimit:")) {
+      parsed->jni_globals_max_ = ParseIntegerOrDie(option);
     } else if (option.starts_with("-Xlockprofthreshold:")) {
-      parsed->lock_profiling_threshold_ = atoi(option.substr(strlen("-Xlockprofthreshold:")).data());
+      parsed->lock_profiling_threshold_ = ParseIntegerOrDie(option);
     } else if (option == "sensitiveThread") {
       parsed->hook_is_sensitive_thread_ = reinterpret_cast<bool (*)()>(options[i].second);
     } else if (option == "vfprintf") {
@@ -437,6 +454,7 @@
     LOG(INFO) << "Runtime::Init -verbose:startup enabled";
   }
 
+  SetJniGlobalsMax(options->jni_globals_max_);
   Monitor::Init(options->IsVerbose("monitor"), options->lock_profiling_threshold_, options->hook_is_sensitive_thread_);
 
   host_prefix_ = options->host_prefix_;
diff --git a/src/runtime.h b/src/runtime.h
index cbd47b8..b29523e 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -56,7 +56,8 @@
     size_t heap_initial_size_;
     size_t heap_maximum_size_;
     size_t stack_size_;
-    uint32_t lock_profiling_threshold_;
+    size_t jni_globals_max_;
+    size_t lock_profiling_threshold_;
     bool (*hook_is_sensitive_thread_)();
     jint (*hook_vfprintf_)(FILE* stream, const char* format, va_list ap);
     void (*hook_exit_)(jint status);