TBR: v.io/x/jni: don't pass Go pointers into Java

Instead, we pass references (i.e., ints) which we convert
to Go pointers inside Go code.

MultiPart: 2/2

Change-Id: I6a9aeced22c083207fd67b96e700ec86d66c1007
diff --git a/impl/google/channel/jni.go b/impl/google/channel/jni.go
index 852fbf1..0e046ce 100644
--- a/impl/google/channel/jni.go
+++ b/impl/google/channel/jni.go
@@ -40,23 +40,23 @@
 }
 
 //export Java_io_v_impl_google_channel_InputChannelImpl_nativeRecv
-func Java_io_v_impl_google_channel_InputChannelImpl_nativeRecv(jenv *C.JNIEnv, jInputChannelImpl C.jobject, goRecvPtr C.jlong, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_channel_InputChannelImpl_nativeRecv(jenv *C.JNIEnv, jInputChannelImpl C.jobject, goRecvRef C.jlong, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	recv := *(*func() (jutil.Object, error))(jutil.NativePtr(goRecvPtr))
+	recv := *(*func() (jutil.Object, error))(jutil.GoRefValue(jutil.Ref(goRecvRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	jutil.DoAsyncCall(env, jCallback, recv)
 }
 
 //export Java_io_v_impl_google_channel_InputChannelImpl_nativeFinalize
-func Java_io_v_impl_google_channel_InputChannelImpl_nativeFinalize(jenv *C.JNIEnv, jInputChannelImpl C.jobject, goRecvPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goRecvPtr))
+func Java_io_v_impl_google_channel_InputChannelImpl_nativeFinalize(jenv *C.JNIEnv, jInputChannelImpl C.jobject, goRecvRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRecvRef))
 }
 
 //export Java_io_v_impl_google_channel_OutputChannelImpl_nativeSend
-func Java_io_v_impl_google_channel_OutputChannelImpl_nativeSend(jenv *C.JNIEnv, jOutputChannelClass C.jclass, goConvertPtr C.jlong, goSendPtr C.jlong, jItemObj C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_channel_OutputChannelImpl_nativeSend(jenv *C.JNIEnv, jOutputChannelClass C.jclass, goConvertRef C.jlong, goSendRef C.jlong, jItemObj C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	convert := *(*func(jutil.Object) (interface{}, error))(jutil.NativePtr(goConvertPtr))
-	send := *(*func(interface{}) error)(jutil.NativePtr(goSendPtr))
+	convert := *(*func(jutil.Object) (interface{}, error))(jutil.GoRefValue(jutil.Ref(goConvertRef)))
+	send := *(*func(interface{}) error)(jutil.GoRefValue(jutil.Ref(goSendRef)))
 	jItem := jutil.Object(uintptr(unsafe.Pointer(jItemObj)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	// NOTE(spetrovic): Conversion must be done outside of DoAsyncCall as it references a Java
@@ -72,9 +72,9 @@
 }
 
 //export Java_io_v_impl_google_channel_OutputChannelImpl_nativeClose
-func Java_io_v_impl_google_channel_OutputChannelImpl_nativeClose(jenv *C.JNIEnv, jOutputChannelClass C.jclass, goClosePtr C.jlong, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_channel_OutputChannelImpl_nativeClose(jenv *C.JNIEnv, jOutputChannelClass C.jclass, goCloseRef C.jlong, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	close := *(*func() error)(jutil.NativePtr(goClosePtr))
+	close := *(*func() error)(jutil.GoRefValue(jutil.Ref(goCloseRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	jutil.DoAsyncCall(env, jCallback, func() (jutil.Object, error) {
 		return jutil.NullObject, close()
@@ -82,8 +82,8 @@
 }
 
 //export Java_io_v_impl_google_channel_OutputChannelImpl_nativeFinalize
-func Java_io_v_impl_google_channel_OutputChannelImpl_nativeFinalize(jenv *C.JNIEnv, jOutputChannelClass C.jclass, goConvertPtr C.jlong, goSendPtr C.jlong, goClosePtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goConvertPtr))
-	jutil.GoUnref(jutil.NativePtr(goSendPtr))
-	jutil.GoUnref(jutil.NativePtr(goClosePtr))
+func Java_io_v_impl_google_channel_OutputChannelImpl_nativeFinalize(jenv *C.JNIEnv, jOutputChannelClass C.jclass, goConvertRef C.jlong, goSendRef C.jlong, goCloseRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goConvertRef))
+	jutil.GoDecRef(jutil.Ref(goSendRef))
+	jutil.GoDecRef(jutil.Ref(goCloseRef))
 }
diff --git a/impl/google/channel/util.go b/impl/google/channel/util.go
index c307ae6..9d79f7f 100644
--- a/impl/google/channel/util.go
+++ b/impl/google/channel/util.go
@@ -27,11 +27,12 @@
 	if err != nil {
 		return jutil.NullObject, err
 	}
-	jInputChannel, err := jutil.NewObject(env, jInputChannelImplClass, []jutil.Sign{contextSign, jutil.LongSign}, jContext, int64(jutil.PtrValue(&recv)))
+	ref := jutil.GoNewRef(&recv) // Un-refed when jInputChannel is finalized.
+	jInputChannel, err := jutil.NewObject(env, jInputChannelImplClass, []jutil.Sign{contextSign, jutil.LongSign}, jContext, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&recv) // Un-refed when jInputChannel is finalized.
 	return jInputChannel, nil
 }
 
@@ -42,12 +43,15 @@
 	if err != nil {
 		return jutil.NullObject, err
 	}
-	jOutputChannel, err := jutil.NewObject(env, jOutputChannelImplClass, []jutil.Sign{contextSign, jutil.LongSign, jutil.LongSign, jutil.LongSign}, jContext, int64(jutil.PtrValue(&convert)), int64(jutil.PtrValue(&send)), int64(jutil.PtrValue(&close)))
+	convertRef := jutil.GoNewRef(&convert) // Un-refed when jOutputChannel is finalized.
+	sendRef := jutil.GoNewRef(&send)       // Un-refed when jOutputChannel is finalized.
+	closeRef := jutil.GoNewRef(&close)     // Un-refed when jOutputChannel is finalized.
+	jOutputChannel, err := jutil.NewObject(env, jOutputChannelImplClass, []jutil.Sign{contextSign, jutil.LongSign, jutil.LongSign, jutil.LongSign}, jContext, int64(convertRef), int64(sendRef), int64(closeRef))
 	if err != nil {
+		jutil.GoDecRef(convertRef)
+		jutil.GoDecRef(sendRef)
+		jutil.GoDecRef(closeRef)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&convert) // Un-refed when jOutputChannel is finalized.
-	jutil.GoRef(&send)    // Un-refed when jOutputChannel is finalized.
-	jutil.GoRef(&close)   // Un-refed when jOutputChannel is finalized.
 	return jOutputChannel, nil
 }
diff --git a/impl/google/discovery/jni.go b/impl/google/discovery/jni.go
index 666c9f1..18dad7b 100644
--- a/impl/google/discovery/jni.go
+++ b/impl/google/discovery/jni.go
@@ -95,7 +95,7 @@
 }
 
 //export Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeAdvertise
-func Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeAdvertise(jenv *C.JNIEnv, _ C.jobject, dPtr C.jlong, jCtx C.jobject, jAdObj C.jobject, jVisibilityObj C.jobject, jCbObj C.jobject) {
+func Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeAdvertise(jenv *C.JNIEnv, _ C.jobject, goRef C.jlong, jCtx C.jobject, jAdObj C.jobject, jVisibilityObj C.jobject, jCbObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jCtx))))
 	if err != nil {
@@ -103,7 +103,7 @@
 		return
 	}
 
-	d := *(*discovery.T)(jutil.NativePtr(dPtr))
+	d := *(*discovery.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jAd := jutil.Object(uintptr(unsafe.Pointer(jAdObj)))
 	jVisibility := jutil.Object(uintptr(unsafe.Pointer(jVisibilityObj)))
 
@@ -151,7 +151,7 @@
 }
 
 //export Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeScan
-func Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeScan(jenv *C.JNIEnv, _ C.jobject, dPtr C.jlong, jCtx C.jobject, jQuery C.jstring) C.jobject {
+func Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeScan(jenv *C.JNIEnv, _ C.jobject, goRef C.jlong, jCtx C.jobject, jQuery C.jstring) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jCtx))))
 	if err != nil {
@@ -159,7 +159,7 @@
 		return nil
 	}
 
-	d := *(*discovery.T)(jutil.NativePtr(dPtr))
+	d := *(*discovery.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	query := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jQuery))))
 
 	scanCh, err := d.Scan(ctx, query)
@@ -193,12 +193,12 @@
 }
 
 //export Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeFinalize
-func Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeFinalize(jenv *C.JNIEnv, _ C.jobject, dPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(dPtr))
+func Java_io_v_impl_google_lib_discovery_DiscoveryImpl_nativeFinalize(jenv *C.JNIEnv, _ C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_lib_discovery_UpdateImpl_nativeAttachment
-func Java_io_v_impl_google_lib_discovery_UpdateImpl_nativeAttachment(jenv *C.JNIEnv, _ C.jobject, uPtr C.jlong, jCtx C.jobject, jName C.jstring, jCbObj C.jobject) {
+func Java_io_v_impl_google_lib_discovery_UpdateImpl_nativeAttachment(jenv *C.JNIEnv, _ C.jobject, goRef C.jlong, jCtx C.jobject, jName C.jstring, jCbObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jCtx))))
 	if err != nil {
@@ -206,7 +206,7 @@
 		return
 	}
 
-	update := *(*discovery.Update)(jutil.NativePtr(uPtr))
+	update := *(*discovery.Update)(jutil.GoRefValue(jutil.Ref(goRef)))
 	name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
 
 	jCb := jutil.Object(uintptr(unsafe.Pointer(jCbObj)))
@@ -230,8 +230,8 @@
 }
 
 //export Java_io_v_impl_google_lib_discovery_UpdateImpl_nativeFinalize
-func Java_io_v_impl_google_lib_discovery_UpdateImpl_nativeFinalize(jenv *C.JNIEnv, _ C.jobject, uPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(uPtr))
+func Java_io_v_impl_google_lib_discovery_UpdateImpl_nativeFinalize(jenv *C.JNIEnv, _ C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_lib_discovery_DiscoveryTestUtil_injectMockDiscovery
diff --git a/impl/google/discovery/plugins/jni.go b/impl/google/discovery/plugins/jni.go
index 85706ab..9f171c6 100644
--- a/impl/google/discovery/plugins/jni.go
+++ b/impl/google/discovery/plugins/jni.go
@@ -41,9 +41,9 @@
 }
 
 //export Java_io_v_android_impl_google_discovery_plugins_NativeScanHandler_nativeHandleUpdate
-func Java_io_v_android_impl_google_discovery_plugins_NativeScanHandler_nativeHandleUpdate(jenv *C.JNIEnv, _ C.jobject, chPtr C.jlong, jAdInfoObj C.jobject) {
+func Java_io_v_android_impl_google_discovery_plugins_NativeScanHandler_nativeHandleUpdate(jenv *C.JNIEnv, _ C.jobject, goRef C.jlong, jAdInfoObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	ch := (*(*chan<- *idiscovery.AdInfo)(jutil.NativePtr(chPtr)))
+	ch := (*(*chan<- *idiscovery.AdInfo)(jutil.GoRefValue(jutil.Ref(goRef))))
 
 	jAdInfo := jutil.Object(uintptr(unsafe.Pointer(jAdInfoObj)))
 
@@ -56,6 +56,6 @@
 }
 
 //export Java_io_v_android_impl_google_discovery_plugins_NativeScanHandler_nativeFinalize
-func Java_io_v_android_impl_google_discovery_plugins_NativeScanHandler_nativeFinalize(jenv *C.JNIEnv, _ C.jobject, chPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(chPtr))
+func Java_io_v_android_impl_google_discovery_plugins_NativeScanHandler_nativeFinalize(jenv *C.JNIEnv, _ C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
diff --git a/impl/google/discovery/plugins/plugin.go b/impl/google/discovery/plugins/plugin.go
index ef4451e..59ec56d 100644
--- a/impl/google/discovery/plugins/plugin.go
+++ b/impl/google/discovery/plugins/plugin.go
@@ -58,8 +58,10 @@
 	env, freeFunc := jutil.GetEnv()
 	defer freeFunc()
 
-	jNativeScanHandler, err := jutil.NewObject(env, jNativeScanHandlerClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&ch)))
+	chRef := jutil.GoNewRef(&ch) // Un-refed when jNativeScanHandler is finalized.
+	jNativeScanHandler, err := jutil.NewObject(env, jNativeScanHandlerClass, []jutil.Sign{jutil.LongSign}, int64(chRef))
 	if err != nil {
+		jutil.GoDecRef(chRef)
 		done()
 		return err
 	}
@@ -69,7 +71,6 @@
 		return err
 	}
 
-	jutil.GoRef(&ch) // Will be unrefed when jNativeScanHandler is finalized.
 	jNativeScanHandler = jutil.NewGlobalRef(env, jNativeScanHandler)
 	stop := func() {
 		env, freeFunc := jutil.GetEnv()
diff --git a/impl/google/discovery/util.go b/impl/google/discovery/util.go
index b776ea8..76ecc60 100644
--- a/impl/google/discovery/util.go
+++ b/impl/google/discovery/util.go
@@ -22,11 +22,12 @@
 
 // JavaDiscovery converts a Go discovery instance into a Java discovery instance.
 func JavaDiscovery(env jutil.Env, d discovery.T) (jutil.Object, error) {
-	jDiscovery, err := jutil.NewObject(env, jDiscoveryImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&d)))
+	ref := jutil.GoNewRef(&d) // Un-refed when jDiscovery is finalized.
+	jDiscovery, err := jutil.NewObject(env, jDiscoveryImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&d) // Will be unrefed when jDiscovery is finalized.
 	return jDiscovery, nil
 }
 
@@ -36,11 +37,12 @@
 	if err != nil {
 		return jutil.NullObject, err
 	}
-	jUpdate, err := jutil.NewObject(env, jUpdateImplClass, []jutil.Sign{jutil.LongSign, jutil.BoolSign, advertisementSign}, int64(jutil.PtrValue(&update)), update.IsLost(), jAd)
+	ref := jutil.GoNewRef(&update) // Un-refed when jUpdate is finalized.
+	jUpdate, err := jutil.NewObject(env, jUpdateImplClass, []jutil.Sign{jutil.LongSign, jutil.BoolSign, advertisementSign}, int64(ref), update.IsLost(), jAd)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&update) // Will be unrefed when jUpdate is finalized.
 	return jUpdate, nil
 }
 
diff --git a/impl/google/namespace/jni.go b/impl/google/namespace/jni.go
index a12d963..965376a 100644
--- a/impl/google/namespace/jni.go
+++ b/impl/google/namespace/jni.go
@@ -72,9 +72,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeGlob
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeGlob(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jPattern C.jstring, jOptions C.jobject) C.jobject {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeGlob(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jPattern C.jstring, jOptions C.jobject) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	ctx, cancel, pattern, opts, err := globArgs(env, jContext, jPattern, jOptions)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -130,9 +130,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeMount
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeMount(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring, jServer C.jstring, jDuration C.jobject, jOptions C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeMount(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring, jServer C.jstring, jDuration C.jobject, jOptions C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	context, name, server, duration, options, err := mountArgs(env, jContext, jName, jServer, jDuration, jOptions)
 	if err != nil {
@@ -156,9 +156,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeUnmount
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeUnmount(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring, jServer C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeUnmount(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring, jServer C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	name, server, context, options, err := unmountArgs(env, jName, jServer, jContext, jOptions)
 	if err != nil {
@@ -185,9 +185,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeDelete
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeDelete(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring, jDeleteSubtree C.jboolean, jOptions C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeDelete(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring, jDeleteSubtree C.jboolean, jOptions C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	context, options, name, deleteSubtree, err := deleteArgs(env, jContext, jOptions, jName, jDeleteSubtree)
 	if err != nil {
@@ -229,9 +229,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeResolve
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeResolve(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeResolve(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	context, name, options, err := resolveArgs(env, jName, jContext, jOptions)
 	if err != nil {
@@ -273,9 +273,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeResolveToMountTable
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeResolveToMountTable(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeResolveToMountTable(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	context, options, name, err := resolveToMountTableArgs(env, jContext, jOptions, jName)
 	if err != nil {
@@ -288,9 +288,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeFlushCacheEntry
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeFlushCacheEntry(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring) C.jboolean {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeFlushCacheEntry(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring) C.jboolean {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	context, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jContext))))
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -305,9 +305,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeSetRoots
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeSetRoots(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jNames C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeSetRoots(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jNames C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	names, err := jutil.GoStringList(env, jutil.Object(uintptr(unsafe.Pointer(jNames))))
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -335,9 +335,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeSetPermissions
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeSetPermissions(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring, jPermissions C.jobject, jVersion C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeSetPermissions(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring, jPermissions C.jobject, jVersion C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	context, permissions, name, version, options, err := setPermissionsArgs(env, jContext, jPermissions, jName, jVersion, jOptions)
 	if err != nil {
@@ -385,9 +385,9 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeGetPermissions
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeGetPermissions(jenv *C.JNIEnv, jNamespaceClass C.jclass, goNamespacePtr C.jlong, jContext C.jobject, jName C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeGetPermissions(jenv *C.JNIEnv, jNamespaceClass C.jclass, goRef C.jlong, jContext C.jobject, jName C.jstring, jOptions C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	n := *(*namespace.T)(jutil.NativePtr(goNamespacePtr))
+	n := *(*namespace.T)(jutil.GoRefValue(jutil.Ref(goRef)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	context, name, options, err := getPermissionsArgs(env, jContext, jName, jOptions)
 	if err != nil {
@@ -400,6 +400,6 @@
 }
 
 //export Java_io_v_impl_google_namespace_NamespaceImpl_nativeFinalize
-func Java_io_v_impl_google_namespace_NamespaceImpl_nativeFinalize(jenv *C.JNIEnv, jNamespace C.jobject, goNamespacePtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goNamespacePtr))
+func Java_io_v_impl_google_namespace_NamespaceImpl_nativeFinalize(jenv *C.JNIEnv, jNamespace C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
diff --git a/impl/google/namespace/util.go b/impl/google/namespace/util.go
index ae69298..99a0876 100644
--- a/impl/google/namespace/util.go
+++ b/impl/google/namespace/util.go
@@ -23,11 +23,12 @@
 	if namespace == nil {
 		return jutil.NullObject, nil
 	}
-	jNamespace, err := jutil.NewObject(env, jNamespaceImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&namespace)))
+	ref := jutil.GoNewRef(&namespace) // Un-refed when the Java NamespaceImpl is finalized.
+	jNamespace, err := jutil.NewObject(env, jNamespaceImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&namespace) // Un-refed when the Java NamespaceImpl is finalized.
 	return jNamespace, nil
 }
 
diff --git a/impl/google/rpc/dispatcher.go b/impl/google/rpc/dispatcher.go
index b173af0..0478a75 100644
--- a/impl/google/rpc/dispatcher.go
+++ b/impl/google/rpc/dispatcher.go
@@ -59,12 +59,12 @@
 	if len(result) != 2 {
 		return nil, nil, fmt.Errorf("lookup returned %d elems, want 2", len(result))
 	}
-	invoker := *(*rpc.Invoker)(jutil.NativePtr(result[0]))
-	jutil.GoUnref(jutil.NativePtr(result[0]))
+	invoker := *(*rpc.Invoker)(jutil.GoRefValue(jutil.Ref(result[0])))
+	jutil.GoDecRef(jutil.Ref(result[0]))
 	authorizer := security.Authorizer(nil)
 	if result[1] != 0 {
-		authorizer = *(*security.Authorizer)(jutil.NativePtr(result[1]))
-		jutil.GoUnref(jutil.NativePtr(result[1]))
+		authorizer = *(*security.Authorizer)(jutil.GoRefValue(jutil.Ref(result[1])))
+		jutil.GoDecRef(jutil.Ref(result[1]))
 	}
 	return invoker, authorizer, nil
 }
diff --git a/impl/google/rpc/jni.go b/impl/google/rpc/jni.go
index 243cc28..dce3089 100644
--- a/impl/google/rpc/jni.go
+++ b/impl/google/rpc/jni.go
@@ -192,26 +192,26 @@
 }
 
 //export Java_io_v_impl_google_rpc_ServerImpl_nativeAddName
-func Java_io_v_impl_google_rpc_ServerImpl_nativeAddName(jenv *C.JNIEnv, jServer C.jobject, goPtr C.jlong, jName C.jstring) {
+func Java_io_v_impl_google_rpc_ServerImpl_nativeAddName(jenv *C.JNIEnv, jServer C.jobject, goRef C.jlong, jName C.jstring) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
-	if err := (*(*rpc.Server)(jutil.NativePtr(goPtr))).AddName(name); err != nil {
+	if err := (*(*rpc.Server)(jutil.GoRefValue(jutil.Ref(goRef)))).AddName(name); err != nil {
 		jutil.JThrowV(env, err)
 		return
 	}
 }
 
 //export Java_io_v_impl_google_rpc_ServerImpl_nativeRemoveName
-func Java_io_v_impl_google_rpc_ServerImpl_nativeRemoveName(jenv *C.JNIEnv, jServer C.jobject, goPtr C.jlong, jName C.jstring) {
+func Java_io_v_impl_google_rpc_ServerImpl_nativeRemoveName(jenv *C.JNIEnv, jServer C.jobject, goRef C.jlong, jName C.jstring) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
-	(*(*rpc.Server)(jutil.NativePtr(goPtr))).RemoveName(name)
+	(*(*rpc.Server)(jutil.GoRefValue(jutil.Ref(goRef)))).RemoveName(name)
 }
 
 //export Java_io_v_impl_google_rpc_ServerImpl_nativeGetStatus
-func Java_io_v_impl_google_rpc_ServerImpl_nativeGetStatus(jenv *C.JNIEnv, jServer C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_impl_google_rpc_ServerImpl_nativeGetStatus(jenv *C.JNIEnv, jServer C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	status := (*(*rpc.Server)(jutil.NativePtr(goPtr))).Status()
+	status := (*(*rpc.Server)(jutil.GoRefValue(jutil.Ref(goRef)))).Status()
 	jStatus, err := JavaServerStatus(env, status)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -221,8 +221,8 @@
 }
 
 //export Java_io_v_impl_google_rpc_ServerImpl_nativeFinalize
-func Java_io_v_impl_google_rpc_ServerImpl_nativeFinalize(jenv *C.JNIEnv, jServer C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_impl_google_rpc_ServerImpl_nativeFinalize(jenv *C.JNIEnv, jServer C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 func decodeArgs(env jutil.Env, jVomArgs C.jobjectArray) ([]interface{}, error) {
@@ -241,9 +241,9 @@
 	return args, nil
 }
 
-func doStartCall(context *context.T, cancel func(), name, method string, opts []rpc.CallOpt, goPtr C.jlong, args []interface{}) (jutil.Object, error) {
+func doStartCall(context *context.T, cancel func(), name, method string, opts []rpc.CallOpt, goRef C.jlong, args []interface{}) (jutil.Object, error) {
 	// Invoke StartCall
-	call, err := (*(*rpc.Client)(jutil.NativePtr(goPtr))).StartCall(context, name, method, args, opts...)
+	call, err := (*(*rpc.Client)(jutil.GoRefValue(jutil.Ref(goRef)))).StartCall(context, name, method, args, opts...)
 	if err != nil {
 		return jutil.NullObject, err
 	}
@@ -263,7 +263,7 @@
 }
 
 //export Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall
-func Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall(jenv *C.JNIEnv, jClient C.jobject, goPtr C.jlong, jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jNameResolutionAuthorizerObj, jServerAuthorizerObj C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_rpc_ClientImpl_nativeStartCall(jenv *C.JNIEnv, jClient C.jobject, goRef C.jlong, jContext C.jobject, jName C.jstring, jMethod C.jstring, jVomArgs C.jobjectArray, jNameResolutionAuthorizerObj, jServerAuthorizerObj C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
 	method := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jMethod))))
@@ -298,22 +298,22 @@
 		opts = append(opts, options.ServerAuthorizer{auth})
 	}
 	jutil.DoAsyncCall(env, jCallback, func() (jutil.Object, error) {
-		return doStartCall(ctx, cancel, name, method, opts, goPtr, args)
+		return doStartCall(ctx, cancel, name, method, opts, goRef, args)
 	})
 }
 
 //export Java_io_v_impl_google_rpc_ClientImpl_nativeClose
-func Java_io_v_impl_google_rpc_ClientImpl_nativeClose(jenv *C.JNIEnv, jClient C.jobject, goPtr C.jlong) {
-	(*(*rpc.Client)(jutil.NativePtr(goPtr))).Close()
+func Java_io_v_impl_google_rpc_ClientImpl_nativeClose(jenv *C.JNIEnv, jClient C.jobject, goRef C.jlong) {
+	(*(*rpc.Client)(jutil.GoRefValue(jutil.Ref(goRef)))).Close()
 }
 
 //export Java_io_v_impl_google_rpc_ClientImpl_nativeFinalize
-func Java_io_v_impl_google_rpc_ClientImpl_nativeFinalize(jenv *C.JNIEnv, jClient C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_impl_google_rpc_ClientImpl_nativeFinalize(jenv *C.JNIEnv, jClient C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_rpc_StreamImpl_nativeSend
-func Java_io_v_impl_google_rpc_StreamImpl_nativeSend(jenv *C.JNIEnv, jStream C.jobject, goPtr C.jlong, jVomItem C.jbyteArray, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_rpc_StreamImpl_nativeSend(jenv *C.JNIEnv, jStream C.jobject, goRef C.jlong, jVomItem C.jbyteArray, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	vomItem := jutil.GoByteArray(env, jutil.Object(uintptr(unsafe.Pointer(jVomItem))))
@@ -322,17 +322,17 @@
 		if err != nil {
 			return jutil.NullObject, err
 		}
-		return jutil.NullObject, (*(*rpc.Stream)(jutil.NativePtr(goPtr))).Send(item)
+		return jutil.NullObject, (*(*rpc.Stream)(jutil.GoRefValue(jutil.Ref(goRef)))).Send(item)
 	})
 }
 
 //export Java_io_v_impl_google_rpc_StreamImpl_nativeRecv
-func Java_io_v_impl_google_rpc_StreamImpl_nativeRecv(jenv *C.JNIEnv, jStream C.jobject, goPtr C.jlong, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_rpc_StreamImpl_nativeRecv(jenv *C.JNIEnv, jStream C.jobject, goRef C.jlong, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	result := new(vdl.Value)
 	jutil.DoAsyncCall(env, jCallback, func() (jutil.Object, error) {
-		if err := (*(*rpc.Stream)(jutil.NativePtr(goPtr))).Recv(&result); err != nil {
+		if err := (*(*rpc.Stream)(jutil.GoRefValue(jutil.Ref(goRef)))).Recv(&result); err != nil {
 			if err == io.EOF {
 				// Java uses EndOfFile error to detect EOF.
 				err = verror.NewErrEndOfFile(nil)
@@ -356,27 +356,27 @@
 }
 
 //export Java_io_v_impl_google_rpc_StreamImpl_nativeFinalize
-func Java_io_v_impl_google_rpc_StreamImpl_nativeFinalize(jenv *C.JNIEnv, jStream C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_impl_google_rpc_StreamImpl_nativeFinalize(jenv *C.JNIEnv, jStream C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_rpc_ClientCallImpl_nativeCloseSend
-func Java_io_v_impl_google_rpc_ClientCallImpl_nativeCloseSend(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_rpc_ClientCallImpl_nativeCloseSend(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	jutil.DoAsyncCall(env, jCallback, func() (jutil.Object, error) {
-		return jutil.NullObject, (*(*rpc.ClientCall)(jutil.NativePtr(goPtr))).CloseSend()
+		return jutil.NullObject, (*(*rpc.ClientCall)(jutil.GoRefValue(jutil.Ref(goRef)))).CloseSend()
 	})
 }
 
-func doFinish(goPtr C.jlong, numResults int) (jutil.Object, error) {
+func doFinish(goRef C.jlong, numResults int) (jutil.Object, error) {
 	// Have all the results be decoded into *vdl.Value.
 	resultPtrs := make([]interface{}, numResults)
 	for i := 0; i < numResults; i++ {
 		value := new(vdl.Value)
 		resultPtrs[i] = &value
 	}
-	if err := (*(*rpc.ClientCall)(jutil.NativePtr(goPtr))).Finish(resultPtrs...); err != nil {
+	if err := (*(*rpc.ClientCall)(jutil.GoRefValue(jutil.Ref(goRef)))).Finish(resultPtrs...); err != nil {
 		// Invocation error.
 		return jutil.NullObject, err
 	}
@@ -403,24 +403,24 @@
 }
 
 //export Java_io_v_impl_google_rpc_ClientCallImpl_nativeFinish
-func Java_io_v_impl_google_rpc_ClientCallImpl_nativeFinish(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong, jNumResults C.jint, jCallbackObj C.jobject) {
+func Java_io_v_impl_google_rpc_ClientCallImpl_nativeFinish(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong, jNumResults C.jint, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	numResults := int(jNumResults)
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	jutil.DoAsyncCall(env, jCallback, func() (jutil.Object, error) {
-		return doFinish(goPtr, numResults)
+		return doFinish(goRef, numResults)
 	})
 }
 
 //export Java_io_v_impl_google_rpc_ClientCallImpl_nativeFinalize
-func Java_io_v_impl_google_rpc_ClientCallImpl_nativeFinalize(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_impl_google_rpc_ClientCallImpl_nativeFinalize(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_rpc_ServerCallImpl_nativeSecurity
-func Java_io_v_impl_google_rpc_ServerCallImpl_nativeSecurity(jenv *C.JNIEnv, jServerCallClass C.jclass, goPtr C.jlong) C.jobject {
+func Java_io_v_impl_google_rpc_ServerCallImpl_nativeSecurity(jenv *C.JNIEnv, jServerCallClass C.jclass, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	securityCall := (*(*rpc.ServerCall)(jutil.NativePtr(goPtr))).Security()
+	securityCall := (*(*rpc.ServerCall)(jutil.GoRefValue(jutil.Ref(goRef)))).Security()
 	if securityCall == nil {
 		return nil
 	}
@@ -433,16 +433,16 @@
 }
 
 //export Java_io_v_impl_google_rpc_ServerCallImpl_nativeSuffix
-func Java_io_v_impl_google_rpc_ServerCallImpl_nativeSuffix(jenv *C.JNIEnv, jServerCall C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_impl_google_rpc_ServerCallImpl_nativeSuffix(jenv *C.JNIEnv, jServerCall C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	jSuffix := jutil.JString(env, (*(*rpc.ServerCall)(jutil.NativePtr(goPtr))).Suffix())
+	jSuffix := jutil.JString(env, (*(*rpc.ServerCall)(jutil.GoRefValue(jutil.Ref(goRef)))).Suffix())
 	return C.jstring(unsafe.Pointer(jSuffix))
 }
 
 //export Java_io_v_impl_google_rpc_ServerCallImpl_nativeLocalEndpoint
-func Java_io_v_impl_google_rpc_ServerCallImpl_nativeLocalEndpoint(jenv *C.JNIEnv, jServerCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_impl_google_rpc_ServerCallImpl_nativeLocalEndpoint(jenv *C.JNIEnv, jServerCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	jEndpoint, err := jnaming.JavaEndpoint(env, (*(*rpc.ServerCall)(jutil.NativePtr(goPtr))).LocalEndpoint())
+	jEndpoint, err := jnaming.JavaEndpoint(env, (*(*rpc.ServerCall)(jutil.GoRefValue(jutil.Ref(goRef)))).LocalEndpoint())
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
@@ -451,9 +451,9 @@
 }
 
 //export Java_io_v_impl_google_rpc_ServerCallImpl_nativeRemoteEndpoint
-func Java_io_v_impl_google_rpc_ServerCallImpl_nativeRemoteEndpoint(jenv *C.JNIEnv, jServerCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_impl_google_rpc_ServerCallImpl_nativeRemoteEndpoint(jenv *C.JNIEnv, jServerCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	jEndpoint, err := jnaming.JavaEndpoint(env, (*(*rpc.ServerCall)(jutil.NativePtr(goPtr))).RemoteEndpoint())
+	jEndpoint, err := jnaming.JavaEndpoint(env, (*(*rpc.ServerCall)(jutil.GoRefValue(jutil.Ref(goRef)))).RemoteEndpoint())
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
@@ -462,9 +462,9 @@
 }
 
 //export Java_io_v_impl_google_rpc_ServerCallImpl_nativeGrantedBlessings
-func Java_io_v_impl_google_rpc_ServerCallImpl_nativeGrantedBlessings(jenv *C.JNIEnv, jServerCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_impl_google_rpc_ServerCallImpl_nativeGrantedBlessings(jenv *C.JNIEnv, jServerCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessings := (*(*rpc.ServerCall)(jutil.NativePtr(goPtr))).GrantedBlessings()
+	blessings := (*(*rpc.ServerCall)(jutil.GoRefValue(jutil.Ref(goRef)))).GrantedBlessings()
 	jBlessings, err := jsecurity.JavaBlessings(env, blessings)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -474,9 +474,9 @@
 }
 
 //export Java_io_v_impl_google_rpc_ServerCallImpl_nativeServer
-func Java_io_v_impl_google_rpc_ServerCallImpl_nativeServer(jenv *C.JNIEnv, jServerCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_impl_google_rpc_ServerCallImpl_nativeServer(jenv *C.JNIEnv, jServerCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	server := (*(*rpc.ServerCall)(jutil.NativePtr(goPtr))).Server()
+	server := (*(*rpc.ServerCall)(jutil.GoRefValue(jutil.Ref(goRef)))).Server()
 	jServer, err := JavaServer(env, server)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -486,17 +486,17 @@
 }
 
 //export Java_io_v_impl_google_rpc_ServerCallImpl_nativeFinalize
-func Java_io_v_impl_google_rpc_ServerCallImpl_nativeFinalize(jenv *C.JNIEnv, jServerCall C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_impl_google_rpc_ServerCallImpl_nativeFinalize(jenv *C.JNIEnv, jServerCall C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_rpc_StreamServerCallImpl_nativeFinalize
-func Java_io_v_impl_google_rpc_StreamServerCallImpl_nativeFinalize(jenv *C.JNIEnv, jStreamServerCall C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_impl_google_rpc_StreamServerCallImpl_nativeFinalize(jenv *C.JNIEnv, jStreamServerCall C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_rpc_AddressChooserImpl_nativeChoose
-func Java_io_v_impl_google_rpc_AddressChooserImpl_nativeChoose(jenv *C.JNIEnv, jAddressChooser C.jobject, goPtr C.jlong, jProtocol C.jstring, jCandidates C.jobjectArray) C.jobjectArray {
+func Java_io_v_impl_google_rpc_AddressChooserImpl_nativeChoose(jenv *C.JNIEnv, jAddressChooser C.jobject, goRef C.jlong, jProtocol C.jstring, jCandidates C.jobjectArray) C.jobjectArray {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	protocol := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jProtocol))))
 	candidates, err := GoNetworkAddressArray(env, jutil.Object(uintptr(unsafe.Pointer(jCandidates))))
@@ -504,7 +504,7 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	addrs, err := (*(*rpc.AddressChooser)(jutil.NativePtr(goPtr))).ChooseAddresses(protocol, candidates)
+	addrs, err := (*(*rpc.AddressChooser)(jutil.GoRefValue(jutil.Ref(goRef)))).ChooseAddresses(protocol, candidates)
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
@@ -518,8 +518,8 @@
 }
 
 //export Java_io_v_impl_google_rpc_AddressChooserImpl_nativeFinalize
-func Java_io_v_impl_google_rpc_AddressChooserImpl_nativeFinalize(jenv *C.JNIEnv, jAddressChooser C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_impl_google_rpc_AddressChooserImpl_nativeFinalize(jenv *C.JNIEnv, jAddressChooser C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_impl_google_rpc_ServerRPCHelper_nativeGoInvoker
@@ -530,8 +530,8 @@
 		jutil.JThrowV(env, err)
 		return C.jlong(0)
 	}
-	jutil.GoRef(&invoker) // Un-refed when the Go invoker is returned to the Go runtime
-	return C.jlong(jutil.PtrValue(&invoker))
+	ref := jutil.GoNewRef(&invoker) // Un-refed when the Go invoker is returned to the Go runtime
+	return C.jlong(ref)
 }
 
 //export Java_io_v_impl_google_rpc_ServerRPCHelper_nativeGoAuthorizer
@@ -542,6 +542,6 @@
 		jutil.JThrowV(env, err)
 		return C.jlong(0)
 	}
-	jutil.GoRef(&auth) // Un-refed when the Go authorizer is returned to the Go runtime
-	return C.jlong(jutil.PtrValue(&auth))
+	ref := jutil.GoNewRef(&auth) // Un-refed when the Go authorizer is returned to the Go runtime
+	return C.jlong(ref)
 }
diff --git a/impl/google/rpc/util.go b/impl/google/rpc/util.go
index c534de2..fba6838 100644
--- a/impl/google/rpc/util.go
+++ b/impl/google/rpc/util.go
@@ -24,11 +24,12 @@
 	if server == nil {
 		return jutil.NullObject, fmt.Errorf("Go Server value cannot be nil")
 	}
-	jServer, err := jutil.NewObject(env, jServerImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&server)))
+	ref := jutil.GoNewRef(&server) // Un-refed when the Java Server object is finalized.
+	jServer, err := jutil.NewObject(env, jServerImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&server) // Un-refed when the Java Server object is finalized.
 	return jServer, nil
 }
 
@@ -37,11 +38,12 @@
 	if client == nil {
 		return jutil.NullObject, nil
 	}
-	jClient, err := jutil.NewObject(env, jClientImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&client)))
+	ref := jutil.GoNewRef(&client) // Un-refed when the Java Client object is finalized.
+	jClient, err := jutil.NewObject(env, jClientImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&client) // Un-refed when the Java Client object is finalized.
 	return jClient, nil
 }
 
@@ -60,11 +62,12 @@
 		return jutil.NullObject, err
 	}
 	serverCallSign := jutil.ClassSign("io.v.v23.rpc.ServerCall")
-	jStreamServerCall, err := jutil.NewObject(env, jStreamServerCallImplClass, []jutil.Sign{jutil.LongSign, streamSign, serverCallSign}, int64(jutil.PtrValue(&call)), jStream, jServerCall)
+	ref := jutil.GoNewRef(&call) // Un-refed when the Java StreamServerCall object is finalized.
+	jStreamServerCall, err := jutil.NewObject(env, jStreamServerCallImplClass, []jutil.Sign{jutil.LongSign, streamSign, serverCallSign}, int64(ref), jStream, jServerCall)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&call) // Un-refed when the Java StreamServerCall object is finalized.
 	return jStreamServerCall, nil
 }
 
@@ -77,21 +80,23 @@
 	if err != nil {
 		return jutil.NullObject, err
 	}
-	jCall, err := jutil.NewObject(env, jClientCallImplClass, []jutil.Sign{contextSign, jutil.LongSign, streamSign}, jContext, int64(jutil.PtrValue(&call)), jStream)
+	ref := jutil.GoNewRef(&call) // Un-refed when the Java Call object is finalized.
+	jCall, err := jutil.NewObject(env, jClientCallImplClass, []jutil.Sign{contextSign, jutil.LongSign, streamSign}, jContext, int64(ref), jStream)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&call) // Un-refed when the Java Call object is finalized.
 	return jCall, nil
 }
 
 // javaStream converts the provided Go stream into a Java Stream object.
 func javaStream(env jutil.Env, jContext jutil.Object, stream rpc.Stream) (jutil.Object, error) {
-	jStream, err := jutil.NewObject(env, jStreamImplClass, []jutil.Sign{contextSign, jutil.LongSign}, jContext, int64(jutil.PtrValue(&stream)))
+	ref := jutil.GoNewRef(&stream) // Un-refed when the Java stream object is finalized.
+	jStream, err := jutil.NewObject(env, jStreamImplClass, []jutil.Sign{contextSign, jutil.LongSign}, jContext, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&stream) // Un-refed when the Java stream object is finalized.
 	return jStream, nil
 }
 
@@ -274,11 +279,12 @@
 
 // JavaServerCall converts a Go rpc.ServerCall into a Java ServerCall object.
 func JavaServerCall(env jutil.Env, serverCall rpc.ServerCall) (jutil.Object, error) {
-	jServerCall, err := jutil.NewObject(env, jServerCallImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&serverCall)))
+	ref := jutil.GoNewRef(&serverCall) // Un-refed when the Java ServerCall object is finalized.
+	jServerCall, err := jutil.NewObject(env, jServerCallImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&serverCall) // Un-refed when the Java ServerCall object is finalized.
 	return jServerCall, nil
 }
 
@@ -345,11 +351,12 @@
 // JavaAddressChooser converts a Go address chooser function into a Java
 // AddressChooser object.
 func JavaAddressChooser(env jutil.Env, chooser rpc.AddressChooser) (jutil.Object, error) {
-	jAddressChooser, err := jutil.NewObject(env, jAddressChooserImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&chooser)))
+	ref := jutil.GoNewRef(&chooser) // Un-refed when the Java AddressChooser object is finalized.
+	jAddressChooser, err := jutil.NewObject(env, jAddressChooserImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&chooser) // Un-refed when the Java AddressChooser object is finalized.
 	return jAddressChooser, nil
 }
 
diff --git a/util/call.go b/util/call.go
index 3c67f8b..55004d7 100644
--- a/util/call.go
+++ b/util/call.go
@@ -407,12 +407,14 @@
 // JavaNativeCallback creates a new Java Callback object that calls the provided Go functions
 // on success/failures.
 func JavaNativeCallback(env Env, success func(jResult Object), failure func(err error)) (Object, error) {
-	jCallback, err := NewObject(env, jNativeCallbackClass, []Sign{LongSign, LongSign}, int64(PtrValue(&success)), int64(PtrValue(&failure)))
+	succRef := GoNewRef(&success) // Un-refed when jCallback is finalized
+	failRef := GoNewRef(&failure) // Un-refed when jCallback is finalized
+	jCallback, err := NewObject(env, jNativeCallbackClass, []Sign{LongSign, LongSign}, int64(succRef), int64(failRef))
 	if err != nil {
+		GoDecRef(succRef)
+		GoDecRef(failRef)
 		return NullObject, err
 	}
-	GoRef(&success) // Un-refed when jCallback is finalized
-	GoRef(&failure) // Un-refed when jCallback is finalized
 	return jCallback, nil
 }
 
diff --git a/util/jni.go b/util/jni.go
index 82437ed..2a16c44 100644
--- a/util/jni.go
+++ b/util/jni.go
@@ -165,20 +165,20 @@
 }
 
 //export Java_io_v_util_NativeCallback_nativeOnSuccess
-func Java_io_v_util_NativeCallback_nativeOnSuccess(jenv *C.JNIEnv, jNativeCallback C.jobject, goSuccessPtr C.jlong, jResultObj C.jobject) {
+func Java_io_v_util_NativeCallback_nativeOnSuccess(jenv *C.JNIEnv, jNativeCallback C.jobject, goSuccessRef C.jlong, jResultObj C.jobject) {
 	jResult := Object(uintptr(unsafe.Pointer(jResultObj)))
-	(*(*func(Object))(NativePtr(goSuccessPtr)))(jResult)
+	(*(*func(Object))(GoRefValue(Ref(goSuccessRef))))(jResult)
 }
 
 //export Java_io_v_util_NativeCallback_nativeOnFailure
-func Java_io_v_util_NativeCallback_nativeOnFailure(jenv *C.JNIEnv, jNativeCallback C.jobject, goFailurePtr C.jlong, jVException C.jobject) {
+func Java_io_v_util_NativeCallback_nativeOnFailure(jenv *C.JNIEnv, jNativeCallback C.jobject, goFailureRef C.jlong, jVException C.jobject) {
 	env := Env(uintptr(unsafe.Pointer(jenv)))
 	err := GoError(env, Object(uintptr(unsafe.Pointer(jVException))))
-	(*(*func(error))(NativePtr(goFailurePtr)))(err)
+	(*(*func(error))(GoRefValue(Ref(goFailureRef))))(err)
 }
 
 //export Java_io_v_util_NativeCallback_nativeFinalize
-func Java_io_v_util_NativeCallback_nativeFinalize(jenv *C.JNIEnv, jNativeCallback C.jobject, goSuccessPtr C.jlong, goFailurePtr C.jlong) {
-	GoUnref(NativePtr(goSuccessPtr))
-	GoUnref(NativePtr(goFailurePtr))
+func Java_io_v_util_NativeCallback_nativeFinalize(jenv *C.JNIEnv, jNativeCallback C.jobject, goSuccessRef C.jlong, goFailureRef C.jlong) {
+	GoDecRef(Ref(goSuccessRef))
+	GoDecRef(Ref(goFailureRef))
 }
diff --git a/util/ref.go b/util/ref.go
index 806e6fb..7c154cc 100644
--- a/util/ref.go
+++ b/util/ref.go
@@ -59,24 +59,40 @@
 	return obj.IsNull() || C.GetObjectRefType(env.value(), obj.value()) == C.JNILocalRefType
 }
 
-// GoRef creates a new reference to the value addressed by the provided pointer.
-// The value will remain referenced until it is explicitly unreferenced using
-// goUnref().
-func GoRef(valptr interface{}) {
+// GoNewRef creates a new reference for the given Go pointer, setting its
+// reference count to 1.  The Go pointer isn't garbage collected as long as
+// the reference count remains greater than zero.  The reference counts can
+// be modified using GoIncRef and GoDecRef functions below.
+//
+// Note that it is legal to create multiple references for the same Go pointer:
+// the Go pointer will not be garbage collected as long as some reference's
+// ref count is greater than zero.
+func GoNewRef(valptr interface{}) Ref {
 	if !IsPointer(valptr) {
-		panic("must pass pointer value to goRef")
+		panic(fmt.Sprintf("Must pass pointer value to GoNewRef; instead got %v of type %T", valptr, valptr))
 	}
-	goRefs.ref(valptr)
+	return goRefs.newRef(valptr)
 }
 
-// GoUnref removes a previously added reference to the value addressed by the
-// provided pointer.  If the value hasn't been ref-ed (a bug?), this unref will
-// be a no-op.
-func GoUnref(valptr interface{}) {
-	if !IsPointer(valptr) {
-		panic("must pass pointer value to goUnref")
+// GoIncRef increments the reference count for the given reference by 1.
+func GoIncRef(ref Ref) {
+	goRefs.incRef(ref)
+}
+
+// GoDecRef decrements the reference count for the given reference by 1.
+func GoDecRef(ref Ref) {
+	goRefs.decRef(ref)
+}
+
+// GoRefValue returns the Go pointer associated with the given reference
+// as an unsafe.Pointer (so that it can be easily cast into its right type).
+func GoRefValue(ref Ref) unsafe.Pointer {
+	valptr := goRefs.getVal(ref)
+	v := reflect.ValueOf(valptr)
+	if v.Kind() != reflect.Ptr && v.Kind() != reflect.UnsafePointer {
+		panic(fmt.Sprintf("must pass pointer value to PtrValue, was %v ", v.Type()))
 	}
-	goRefs.unref(valptr)
+	return unsafe.Pointer(v.Pointer())
 }
 
 // IsPointer returns true iff the provided value is a pointer.
@@ -85,15 +101,6 @@
 	return v.Kind() == reflect.Ptr || v.Kind() == reflect.UnsafePointer
 }
 
-// PtrValue returns the value of the pointer as a uintptr.
-func PtrValue(ptr interface{}) uintptr {
-	v := reflect.ValueOf(ptr)
-	if v.Kind() != reflect.Ptr && v.Kind() != reflect.UnsafePointer {
-		panic(fmt.Sprintf("must pass pointer value to PtrValue, was %v ", v.Type()))
-	}
-	return v.Pointer()
-}
-
 // DerefOrDie dereferences the provided (pointer) value, or panic-s if the value
 // isn't of pointer type.
 func DerefOrDie(i interface{}) interface{} {
@@ -104,15 +111,6 @@
 	return v.Elem().Interface()
 }
 
-// NativePtr returns the value of the provided Go pointer as an unsafe.Pointer.
-// This function should only be used for converting Go pointers that have been
-// passed in to Java and then back into Go, and are of (local-package) type
-// C.jlong.
-func NativePtr(goPtr interface{}) unsafe.Pointer {
-	v := reflect.ValueOf(goPtr)
-	return unsafe.Pointer(uintptr(v.Int()))
-}
-
 // goRefs stores references to instances of various Go types, namely instances
 // that are referenced only by the Java code.  The only purpose of this store
 // is to prevent Go runtime from garbage collecting those instances.
@@ -126,50 +124,66 @@
 // newSafeRefCounter returns a new instance of a thread-safe reference counter.
 func newSafeRefCounter() *safeRefCounter {
 	return &safeRefCounter{
-		refs: make(map[uintptr]*refData),
+		seq:  1, // must be > 0, as 0 is a special value
+		refs: make(map[Ref]*refData),
 	}
 }
 
 // safeRefCounter is a thread-safe reference counter.
 type safeRefCounter struct {
-	lock sync.Mutex
-	refs map[uintptr]*refData
+	lock sync.RWMutex
+	seq  Ref
+	refs map[Ref]*refData
 }
 
-// ref increases the reference count to the given valptr by 1.
-func (c *safeRefCounter) ref(valptr interface{}) {
-	p := PtrValue(valptr)
+// newRef creates a new reference to a given Go pointer and sets its ref count to 1.
+func (c *safeRefCounter) newRef(valptr interface{}) Ref {
 	c.lock.Lock()
 	defer c.lock.Unlock()
-	ref, ok := c.refs[p]
+	ref := c.seq
+	c.seq++
+	c.refs[ref] = &refData{
+		instance: valptr,
+		count:    1,
+	}
+	return ref
+}
+
+// ref increases the reference count for the given reference by 1.
+func (c *safeRefCounter) incRef(ref Ref) {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+	data, ok := c.refs[ref]
 	if !ok {
-		c.refs[p] = &refData{
-			instance: valptr,
-			count:    1,
-		}
-	} else {
-		ref.count++
+		panic(fmt.Sprintf("Reference %d doesn't exist", ref))
+	}
+	data.count++
+}
+
+// unref decreases the reference count for the given reference by 1.
+func (c *safeRefCounter) decRef(ref Ref) {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+	data, ok := c.refs[ref]
+	if !ok {
+		panic(fmt.Sprintf("Reference %d doesn't exist", ref))
+	}
+	if data.count == 0 {
+		panic(fmt.Sprintf("Reference %d exists, but doesn't have a count of 0.", ref))
+	}
+	data.count--
+	if data.count == 0 {
+		delete(c.refs, ref)
 	}
 }
 
-// unref decreases the reference count of the given valptr by 1, returning
-// the new reference count value.
-func (c *safeRefCounter) unref(valptr interface{}) int {
-	c.lock.Lock()
-	defer c.lock.Unlock()
-	p := PtrValue(valptr)
-	ref, ok := c.refs[p]
+// getVal returns the value for the given reference.
+func (c *safeRefCounter) getVal(ref Ref) interface{} {
+	c.lock.RLock()
+	defer c.lock.RUnlock()
+	data, ok := c.refs[ref]
 	if !ok {
-		panic(fmt.Sprintf("Unrefing pointer %d of type %T that hasn't been refed before", int64(p), valptr))
+		panic(fmt.Sprintf("Reference %d doesn't exist.", ref))
 	}
-	count := ref.count
-	if count == 0 {
-		panic(fmt.Sprintf("Ref count for pointer %d of type %T is zero", int64(p), valptr))
-	}
-	if count > 1 {
-		ref.count--
-		return ref.count
-	}
-	delete(c.refs, p)
-	return 0
+	return data.instance
 }
diff --git a/util/type.go b/util/type.go
index eaf476a..fa3894f 100644
--- a/util/type.go
+++ b/util/type.go
@@ -34,11 +34,17 @@
 // package-local C.jclass type to Class and vice-versa.
 type Class uintptr
 
+// Ref represents a reference to a Go value that can be passed to the Java code
+// and then safely re-casted to a Go value back again.
+type Ref uint64
+
 const (
 	// NullObject represents an Object that holds a null C.jobject value.
 	NullObject = Object(0)
 	// NullClas represents a Class that holds a null C.jclass value.
 	NullClass = Class(0)
+	// NullRef represents a reference that points to nothing.
+	NullRef = Ref(0)
 )
 
 func (e Env) value() *C.JNIEnv {
diff --git a/util/util.go b/util/util.go
index 555c2bb..71b51ec 100644
--- a/util/util.go
+++ b/util/util.go
@@ -12,6 +12,7 @@
 	"fmt"
 	"log"
 	"runtime"
+	"sync"
 	"time"
 	"unicode"
 	"unicode/utf8"
@@ -35,6 +36,7 @@
 	// processing function passed to GoOptions. It indicates that the
 	// option being processed should be skipped.
 	SkipOption = skipOptionType{}
+	envs       = newEnvCounter()
 )
 
 func (skipOptionType) Error() string {
@@ -112,14 +114,14 @@
 	if newCapacity := PushLocalFrame(env, localRefCapacity); newCapacity < 0 {
 		panic("PushLocalFrame(" + string(localRefCapacity) + ") returned < 0 (was " + string(newCapacity) + ")")
 	}
-	// Reference-count *env.  This is necessary to make GetEnv() re-entrant:
+	// Count *env.  This is necessary to make GetEnv() re-entrant:
 	// same goroutine should be allowed to call GetEnv() multiple times and
 	// the OS thread should only be released after the last call to the free
 	// function.
-	envRefs.ref(jenv)
+	envs.inc(jenv)
 	return env, func() {
 		PopLocalFrame(env, NullObject)
-		if envRefs.unref(jenv) == 0 {
+		if envs.dec(jenv) == 0 {
 			// Last call to free the env out of possibly many successive
 			// GetEnv() calls by the same goroutine: it is now safe to release
 			// the thread.
@@ -744,3 +746,42 @@
 	}
 	return fid, nil
 }
+
+func newEnvCounter() *envCounter {
+	return &envCounter{
+		envs: make(map[*C.JNIEnv]*int),
+	}
+}
+
+// envCounter counts, for each JNI environment, how many times has it been
+// requested (by the same goroutine).
+type envCounter struct {
+	lock sync.Mutex
+	envs map[*C.JNIEnv]*int
+}
+
+func (c *envCounter) inc(jenv *C.JNIEnv) {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+	count, ok := c.envs[jenv]
+	if !ok {
+		count := int(1)
+		c.envs[jenv] = &count
+	} else {
+		(*count)++
+	}
+}
+
+func (c *envCounter) dec(jenv *C.JNIEnv) int {
+	c.lock.Lock()
+	defer c.lock.Unlock()
+	count, ok := c.envs[jenv]
+	if !ok {
+		panic("env entry with zero count")
+	}
+	(*count)--
+	if *count == 0 {
+		delete(c.envs, jenv)
+	}
+	return *count
+}
diff --git a/v23/context/jni.go b/v23/context/jni.go
index b048eb1..a9f1203 100644
--- a/v23/context/jni.go
+++ b/v23/context/jni.go
@@ -58,22 +58,22 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeCancel
-func Java_io_v_v23_context_VContext_nativeCancel(jenv *C.JNIEnv, jVContext C.jobject, goCancelPtr C.jlong) {
-	(*(*context.CancelFunc)(jutil.NativePtr(goCancelPtr)))()
+func Java_io_v_v23_context_VContext_nativeCancel(jenv *C.JNIEnv, jVContext C.jobject, goCancelRef C.jlong) {
+	(*(*context.CancelFunc)(jutil.GoRefValue(jutil.Ref(goCancelRef))))()
 }
 
 //export Java_io_v_v23_context_VContext_nativeIsCanceled
-func Java_io_v_v23_context_VContext_nativeIsCanceled(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong) C.jboolean {
-	if (*(*context.T)(jutil.NativePtr(goPtr))).Err() == nil {
+func Java_io_v_v23_context_VContext_nativeIsCanceled(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong) C.jboolean {
+	if (*(*context.T)(jutil.GoRefValue(jutil.Ref(goRef)))).Err() == nil {
 		return C.JNI_FALSE
 	}
 	return C.JNI_TRUE
 }
 
 //export Java_io_v_v23_context_VContext_nativeDeadline
-func Java_io_v_v23_context_VContext_nativeDeadline(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_context_VContext_nativeDeadline(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	d, ok := (*(*context.T)(jutil.NativePtr(goPtr))).Deadline()
+	d, ok := (*(*context.T)(jutil.GoRefValue(jutil.Ref(goRef)))).Deadline()
 	if !ok {
 		return nil
 	}
@@ -86,10 +86,10 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeOnDone
-func Java_io_v_v23_context_VContext_nativeOnDone(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong, jCallbackObj C.jobject) {
+func Java_io_v_v23_context_VContext_nativeOnDone(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
-	ctx := (*(*context.T)(jutil.NativePtr(goPtr)))
+	ctx := (*(*context.T)(jutil.GoRefValue(jutil.Ref(goRef))))
 	c := ctx.Done()
 	if c == nil {
 		jutil.CallbackOnFailure(env, jCallback, errors.New("Context isn't cancelable"))
@@ -110,10 +110,10 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeValue
-func Java_io_v_v23_context_VContext_nativeValue(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong, jKeySign C.jstring) C.jobject {
+func Java_io_v_v23_context_VContext_nativeValue(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong, jKeySign C.jstring) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	key := goContextKey(jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jKeySign)))))
-	value := (*(*context.T)(jutil.NativePtr(goPtr))).Value(key)
+	value := (*(*context.T)(jutil.GoRefValue(jutil.Ref(goRef)))).Value(key)
 	jValue, err := JavaContextValue(env, value)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -123,9 +123,9 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeWithCancel
-func Java_io_v_v23_context_VContext_nativeWithCancel(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_context_VContext_nativeWithCancel(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	ctx, cancelFunc := context.WithCancel((*context.T)(jutil.NativePtr(goPtr)))
+	ctx, cancelFunc := context.WithCancel((*context.T)(jutil.GoRefValue(jutil.Ref(goRef))))
 	jCtx, err := JavaContext(env, ctx, cancelFunc)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -135,14 +135,14 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeWithDeadline
-func Java_io_v_v23_context_VContext_nativeWithDeadline(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong, jDeadline C.jobject) C.jobject {
+func Java_io_v_v23_context_VContext_nativeWithDeadline(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong, jDeadline C.jobject) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	deadline, err := jutil.GoTime(env, jutil.Object(uintptr(unsafe.Pointer(jDeadline))))
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	ctx, cancelFunc := context.WithDeadline((*context.T)(jutil.NativePtr(goPtr)), deadline)
+	ctx, cancelFunc := context.WithDeadline((*context.T)(jutil.GoRefValue(jutil.Ref(goRef))), deadline)
 	jCtx, err := JavaContext(env, ctx, cancelFunc)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -152,14 +152,14 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeWithTimeout
-func Java_io_v_v23_context_VContext_nativeWithTimeout(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong, jTimeout C.jobject) C.jobject {
+func Java_io_v_v23_context_VContext_nativeWithTimeout(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong, jTimeout C.jobject) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	timeout, err := jutil.GoDuration(env, jutil.Object(uintptr(unsafe.Pointer(jTimeout))))
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	ctx, cancelFunc := context.WithTimeout((*context.T)(jutil.NativePtr(goPtr)), timeout)
+	ctx, cancelFunc := context.WithTimeout((*context.T)(jutil.GoRefValue(jutil.Ref(goRef))), timeout)
 	jCtx, err := JavaContext(env, ctx, cancelFunc)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -169,7 +169,7 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeWithValue
-func Java_io_v_v23_context_VContext_nativeWithValue(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong, goCancelPtr C.jlong, jKeySign C.jstring, jValue C.jobject) C.jobject {
+func Java_io_v_v23_context_VContext_nativeWithValue(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong, goCancelRef C.jlong, jKeySign C.jstring, jValue C.jobject) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	key := goContextKey(jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jKeySign)))))
 	value, err := GoContextValue(env, jutil.Object(uintptr(unsafe.Pointer(jValue))))
@@ -177,10 +177,10 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	ctx := context.WithValue((*context.T)(jutil.NativePtr(goPtr)), key, value)
+	ctx := context.WithValue((*context.T)(jutil.GoRefValue(jutil.Ref(goRef))), key, value)
 	var cancel context.CancelFunc
-	if goCancelPtr != 0 {
-		cancel = (*(*context.CancelFunc)(jutil.NativePtr(goCancelPtr)))
+	if goCancelRef != 0 {
+		cancel = (*(*context.CancelFunc)(jutil.GoRefValue(jutil.Ref(goCancelRef))))
 	}
 	jCtx, err := JavaContext(env, ctx, cancel)
 	if err != nil {
@@ -191,10 +191,10 @@
 }
 
 //export Java_io_v_v23_context_VContext_nativeFinalize
-func Java_io_v_v23_context_VContext_nativeFinalize(jenv *C.JNIEnv, jVContext C.jobject, goPtr C.jlong, goCancelPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
-	if goCancelPtr != 0 {
-		jutil.GoUnref(jutil.NativePtr(goCancelPtr))
+func Java_io_v_v23_context_VContext_nativeFinalize(jenv *C.JNIEnv, jVContext C.jobject, goRef C.jlong, goCancelRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
+	if jutil.Ref(goCancelRef) != jutil.NullRef {
+		jutil.GoDecRef(jutil.Ref(goCancelRef))
 	}
 
 }
diff --git a/v23/context/util.go b/v23/context/util.go
index b87b23c..05af4f9 100644
--- a/v23/context/util.go
+++ b/v23/context/util.go
@@ -27,18 +27,19 @@
 // If the provided cancel function is nil, Java VContext won't be
 // cancelable.
 func JavaContext(env jutil.Env, ctx *context.T, cancel context.CancelFunc) (jutil.Object, error) {
-	var cancelPtr int64
+	ctxRef := jutil.GoNewRef(ctx) // Un-refed when the Java context object is finalized.
+	cancelRef := jutil.NullRef
 	if cancel != nil {
-		cancelPtr = int64(jutil.PtrValue(&cancel))
+		cancelRef = jutil.GoNewRef(&cancel) // Un-refed when the Java context object is finalized.
 	}
-	jCtx, err := jutil.NewObject(env, jVContextClass, []jutil.Sign{jutil.LongSign, jutil.LongSign}, int64(jutil.PtrValue(ctx)), cancelPtr)
+	jCtx, err := jutil.NewObject(env, jVContextClass, []jutil.Sign{jutil.LongSign, jutil.LongSign}, int64(ctxRef), int64(cancelRef))
 	if err != nil {
+		jutil.GoDecRef(ctxRef)
+		if cancel != nil {
+			jutil.GoDecRef(cancelRef)
+		}
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(ctx) // Un-refed when the Java context object is finalized.
-	if cancel != nil {
-		jutil.GoRef(&cancel)
-	}
 	return jCtx, err
 }
 
@@ -48,19 +49,21 @@
 	if jContext.IsNull() {
 		return nil, nil, nil
 	}
-	goCtxPtr, err := jutil.CallLongMethod(env, jContext, "nativePtr", nil)
+	goCtxRefVal, err := jutil.CallLongMethod(env, jContext, "nativeRef", nil)
 	if err != nil {
 		return nil, nil, err
 	}
-	goCancelPtr, err := jutil.CallLongMethod(env, jContext, "nativeCancelPtr", nil)
+	goCtxRef := jutil.Ref(goCtxRefVal)
+	goCancelRefVal, err := jutil.CallLongMethod(env, jContext, "nativeCancelRef", nil)
 	if err != nil {
 		return nil, nil, err
 	}
+	goCancelRef := jutil.Ref(goCancelRefVal)
 	var cancel context.CancelFunc
-	if goCancelPtr != 0 {
-		cancel = *(*context.CancelFunc)(jutil.NativePtr(goCancelPtr))
+	if goCancelRef != jutil.NullRef {
+		cancel = *(*context.CancelFunc)(jutil.GoRefValue(goCancelRef))
 	}
-	return (*context.T)(jutil.NativePtr(goCtxPtr)), cancel, nil
+	return (*context.T)(jutil.GoRefValue(goCtxRef)), cancel, nil
 }
 
 // GoContextValue returns the Go Context value given the Java Context value.
diff --git a/v23/security/access/jni.go b/v23/security/access/jni.go
index 0cd9955..c8f49b4 100644
--- a/v23/security/access/jni.go
+++ b/v23/security/access/jni.go
@@ -48,19 +48,19 @@
 		jutil.JThrowV(env, err)
 		return C.jlong(0)
 	}
-	jutil.GoRef(&acl) // Un-refed when the AccessList object is finalized
-	return C.jlong(jutil.PtrValue(&acl))
+	ref := jutil.GoNewRef(&acl) // Un-refed when the AccessList object is finalized
+	return C.jlong(ref)
 }
 
 //export Java_io_v_v23_security_access_AccessList_nativeIncludes
-func Java_io_v_v23_security_access_AccessList_nativeIncludes(jenv *C.JNIEnv, jAccessList C.jobject, goPtr C.jlong, jBlessings C.jobjectArray) C.jboolean {
+func Java_io_v_v23_security_access_AccessList_nativeIncludes(jenv *C.JNIEnv, jAccessList C.jobject, goRef C.jlong, jBlessings C.jobjectArray) C.jboolean {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	blessings, err := jutil.GoStringArray(env, jutil.Object(uintptr(unsafe.Pointer(jBlessings))))
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return C.JNI_FALSE
 	}
-	ok := (*(*access.AccessList)(jutil.NativePtr(goPtr))).Includes(blessings...)
+	ok := (*(*access.AccessList)(jutil.GoRefValue(jutil.Ref(goRef)))).Includes(blessings...)
 	if ok {
 		return C.JNI_TRUE
 	}
@@ -68,7 +68,7 @@
 }
 
 //export Java_io_v_v23_security_access_AccessList_nativeAuthorize
-func Java_io_v_v23_security_access_AccessList_nativeAuthorize(jenv *C.JNIEnv, jAccessList C.jobject, goPtr C.jlong, jCtx C.jobject, jCall C.jobject) {
+func Java_io_v_v23_security_access_AccessList_nativeAuthorize(jenv *C.JNIEnv, jAccessList C.jobject, goRef C.jlong, jCtx C.jobject, jCall C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jCtx))))
 	if err != nil {
@@ -79,15 +79,15 @@
 	if err != nil {
 		jutil.JThrowV(env, err)
 	}
-	if err := (*(*access.AccessList)(jutil.NativePtr(goPtr))).Authorize(ctx, call); err != nil {
+	if err := (*(*access.AccessList)(jutil.GoRefValue(jutil.Ref(goRef)))).Authorize(ctx, call); err != nil {
 		jutil.JThrowV(env, err)
 		return
 	}
 }
 
 //export Java_io_v_v23_security_access_AccessList_nativeFinalize
-func Java_io_v_v23_security_access_AccessList_nativeFinalize(jenv *C.JNIEnv, jAccessList C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_access_AccessList_nativeFinalize(jenv *C.JNIEnv, jAccessList C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_v23_security_access_PermissionsAuthorizer_nativeCreate
@@ -108,9 +108,10 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jutil.GoRef(&authorizer) // Un-refed when the Java PermissionsAuthorizer is finalized
-	jAuthorizer, err := jutil.NewObject(env, jutil.Class(uintptr(unsafe.Pointer(jPermissionsAuthorizerClass))), []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&authorizer)))
+	ref := jutil.GoNewRef(&authorizer) // Un-refed when the Java PermissionsAuthorizer is finalized
+	jAuthorizer, err := jutil.NewObject(env, jutil.Class(uintptr(unsafe.Pointer(jPermissionsAuthorizerClass))), []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		jutil.JThrowV(env, err)
 		return nil
 	}
@@ -118,7 +119,7 @@
 }
 
 //export Java_io_v_v23_security_access_PermissionsAuthorizer_nativeAuthorize
-func Java_io_v_v23_security_access_PermissionsAuthorizer_nativeAuthorize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goPtr C.jlong, jContext C.jobject, jCall C.jobject) {
+func Java_io_v_v23_security_access_PermissionsAuthorizer_nativeAuthorize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goRef C.jlong, jContext C.jobject, jCall C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jContext))))
 	if err != nil {
@@ -130,13 +131,13 @@
 		jutil.JThrowV(env, err)
 		return
 	}
-	if err := (*(*security.Authorizer)(jutil.NativePtr(goPtr))).Authorize(ctx, call); err != nil {
+	if err := (*(*security.Authorizer)(jutil.GoRefValue(jutil.Ref(goRef)))).Authorize(ctx, call); err != nil {
 		jutil.JThrowV(env, err)
 		return
 	}
 }
 
 //export Java_io_v_v23_security_access_PermissionsAuthorizer_nativeFinalize
-func Java_io_v_v23_security_access_PermissionsAuthorizer_nativeFinalize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_access_PermissionsAuthorizer_nativeFinalize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
diff --git a/v23/security/authorizer.go b/v23/security/authorizer.go
index 15b1b3e..1b129eb 100644
--- a/v23/security/authorizer.go
+++ b/v23/security/authorizer.go
@@ -24,11 +24,12 @@
 		return nil, nil
 	}
 	if jutil.IsInstanceOf(env, jAuth, jPermissionsAuthorizerClass) {
-		ptr, err := jutil.JLongField(env, jAuth, "nativePtr")
+		// Called with our implementation of Authorizer, which maintains a Go reference - use it.
+		ref, err := jutil.JLongField(env, jAuth, "nativeRef")
 		if err != nil {
 			return nil, err
 		}
-		return *(*security.Authorizer)(jutil.NativePtr(ptr)), nil
+		return *(*security.Authorizer)(jutil.GoRefValue(jutil.Ref(ref))), nil
 	}
 	// Reference Java dispatcher; it will be de-referenced when the go
 	// dispatcher created below is garbage-collected (through the finalizer
diff --git a/v23/security/call.go b/v23/security/call.go
index 9d7dd60..4bbb922 100644
--- a/v23/security/call.go
+++ b/v23/security/call.go
@@ -26,11 +26,12 @@
 
 // JavaCall converts the provided Go (security) Call into a Java Call object.
 func JavaCall(env jutil.Env, call security.Call) (jutil.Object, error) {
-	jCall, err := jutil.NewObject(env, jCallImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&call)))
+	ref := jutil.GoNewRef(&call) // Un-refed when the Java CallImpl object is finalized.
+	jCall, err := jutil.NewObject(env, jCallImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&call) // Un-refed when the Java CallImpl object is finalized.
 	return jCall, nil
 }
 
@@ -41,12 +42,12 @@
 		return nil, nil
 	}
 	if jutil.IsInstanceOf(env, jCall, jCallImplClass) {
-		// Called with our implementation of Call, which maintains a Go pointer - use it.
-		goPtr, err := jutil.CallLongMethod(env, jCall, "nativePtr", nil)
+		// Called with our implementation of Call, which maintains a Go reference - use it.
+		ref, err := jutil.CallLongMethod(env, jCall, "nativeRef", nil)
 		if err != nil {
 			return nil, err
 		}
-		return (*(*security.Call)(jutil.NativePtr(goPtr))), nil
+		return (*(*security.Call)(jutil.GoRefValue(jutil.Ref(ref)))), nil
 	}
 	// Reference Java call; it will be de-referenced when the go call
 	// created below is garbage-collected (through the finalizer callback we
diff --git a/v23/security/jni.go b/v23/security/jni.go
index 51c182d..578c328 100644
--- a/v23/security/jni.go
+++ b/v23/security/jni.go
@@ -148,9 +148,9 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeTimestamp
-func Java_io_v_v23_security_CallImpl_nativeTimestamp(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_CallImpl_nativeTimestamp(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	t := (*(*security.Call)(jutil.NativePtr(goPtr))).Timestamp()
+	t := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).Timestamp()
 	jTime, err := jutil.JTime(env, t)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -160,17 +160,17 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeMethod
-func Java_io_v_v23_security_CallImpl_nativeMethod(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_CallImpl_nativeMethod(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	method := (*(*security.Call)(jutil.NativePtr(goPtr))).Method()
+	method := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).Method()
 	jMethod := jutil.JString(env, jutil.CamelCase(method))
 	return C.jstring(unsafe.Pointer(jMethod))
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeMethodTags
-func Java_io_v_v23_security_CallImpl_nativeMethodTags(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jobjectArray {
+func Java_io_v_v23_security_CallImpl_nativeMethodTags(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jobjectArray {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	tags := (*(*security.Call)(jutil.NativePtr(goPtr))).MethodTags()
+	tags := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).MethodTags()
 	jTags, err := jutil.JVDLValueArray(env, tags)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -180,16 +180,16 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeSuffix
-func Java_io_v_v23_security_CallImpl_nativeSuffix(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_CallImpl_nativeSuffix(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	jSuffix := jutil.JString(env, (*(*security.Call)(jutil.NativePtr(goPtr))).Suffix())
+	jSuffix := jutil.JString(env, (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).Suffix())
 	return C.jstring(unsafe.Pointer(jSuffix))
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeRemoteDischarges
-func Java_io_v_v23_security_CallImpl_nativeRemoteDischarges(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_CallImpl_nativeRemoteDischarges(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	remoteDischarges := (*(*security.Call)(jutil.NativePtr(goPtr))).RemoteDischarges()
+	remoteDischarges := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).RemoteDischarges()
 	jObjectMap, err := javaDischargeMap(env, remoteDischarges)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -199,9 +199,9 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeLocalDischarges
-func Java_io_v_v23_security_CallImpl_nativeLocalDischarges(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_CallImpl_nativeLocalDischarges(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	localDischarges := (*(*security.Call)(jutil.NativePtr(goPtr))).LocalDischarges()
+	localDischarges := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).LocalDischarges()
 	jObjectMap, err := javaDischargeMap(env, localDischarges)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -211,24 +211,24 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeLocalEndpoint
-func Java_io_v_v23_security_CallImpl_nativeLocalEndpoint(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_CallImpl_nativeLocalEndpoint(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	jEndpoint := jutil.JString(env, (*(*security.Call)(jutil.NativePtr(goPtr))).LocalEndpoint().String())
+	jEndpoint := jutil.JString(env, (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).LocalEndpoint().String())
 	return C.jstring(unsafe.Pointer(jEndpoint))
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeRemoteEndpoint
-func Java_io_v_v23_security_CallImpl_nativeRemoteEndpoint(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_CallImpl_nativeRemoteEndpoint(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	jEndpoint := jutil.JString(env, (*(*security.Call)(jutil.NativePtr(goPtr))).RemoteEndpoint().String())
+	jEndpoint := jutil.JString(env, (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).RemoteEndpoint().String())
 	return C.jstring(unsafe.Pointer(jEndpoint))
 
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeLocalPrincipal
-func Java_io_v_v23_security_CallImpl_nativeLocalPrincipal(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_CallImpl_nativeLocalPrincipal(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	principal := (*(*security.Call)(jutil.NativePtr(goPtr))).LocalPrincipal()
+	principal := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).LocalPrincipal()
 	jPrincipal, err := JavaPrincipal(env, principal)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -238,9 +238,9 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeLocalBlessings
-func Java_io_v_v23_security_CallImpl_nativeLocalBlessings(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_CallImpl_nativeLocalBlessings(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessings := (*(*security.Call)(jutil.NativePtr(goPtr))).LocalBlessings()
+	blessings := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).LocalBlessings()
 	jBlessings, err := JavaBlessings(env, blessings)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -250,9 +250,9 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeRemoteBlessings
-func Java_io_v_v23_security_CallImpl_nativeRemoteBlessings(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_CallImpl_nativeRemoteBlessings(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessings := (*(*security.Call)(jutil.NativePtr(goPtr))).RemoteBlessings()
+	blessings := (*(*security.Call)(jutil.GoRefValue(jutil.Ref(goRef)))).RemoteBlessings()
 	jBlessings, err := JavaBlessings(env, blessings)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -262,8 +262,8 @@
 }
 
 //export Java_io_v_v23_security_CallImpl_nativeFinalize
-func Java_io_v_v23_security_CallImpl_nativeFinalize(jenv *C.JNIEnv, jCall C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_CallImpl_nativeFinalize(jenv *C.JNIEnv, jCall C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativeCreate
@@ -296,12 +296,13 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(jutil.PtrValue(&principal)), signerObj, jutil.NullObject, jutil.NullObject)
+	ref := jutil.GoNewRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
+	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(ref), signerObj, jutil.NullObject, jutil.NullObject)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jutil.GoRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
 	return C.jobject(unsafe.Pointer(jPrincipal))
 }
 
@@ -333,12 +334,13 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(jutil.PtrValue(&principal)), signerObj, storeObj, rootsObj)
+	ref := jutil.GoNewRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
+	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(ref), signerObj, storeObj, rootsObj)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jutil.GoRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
 	return C.jobject(unsafe.Pointer(jPrincipal))
 }
 
@@ -382,17 +384,18 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(jutil.PtrValue(&principal)), signerObj, jutil.NullObject, jutil.NullObject)
+	ref := jutil.GoNewRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
+	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(ref), signerObj, jutil.NullObject, jutil.NullObject)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jutil.GoRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
 	return C.jobject(unsafe.Pointer(jPrincipal))
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativeBless
-func Java_io_v_v23_security_VPrincipalImpl_nativeBless(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goPtr C.jlong, jKey C.jobject, jWith C.jobject, jExtension C.jstring, jCaveat C.jobject, jAdditionalCaveats C.jobjectArray) C.jobject {
+func Java_io_v_v23_security_VPrincipalImpl_nativeBless(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goRef C.jlong, jKey C.jobject, jWith C.jobject, jExtension C.jstring, jCaveat C.jobject, jAdditionalCaveats C.jobjectArray) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	key, err := GoPublicKey(env, jutil.Object(uintptr(unsafe.Pointer(jKey))))
 	if err != nil {
@@ -415,7 +418,7 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	blessings, err := (*(*security.Principal)(jutil.NativePtr(goPtr))).Bless(key, with, extension, caveat, additionalCaveats...)
+	blessings, err := (*(*security.Principal)(jutil.GoRefValue(jutil.Ref(goRef)))).Bless(key, with, extension, caveat, additionalCaveats...)
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
@@ -429,7 +432,7 @@
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativeBlessSelf
-func Java_io_v_v23_security_VPrincipalImpl_nativeBlessSelf(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goPtr C.jlong, jName C.jstring, jCaveats C.jobjectArray) C.jobject {
+func Java_io_v_v23_security_VPrincipalImpl_nativeBlessSelf(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goRef C.jlong, jName C.jstring, jCaveats C.jobjectArray) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	name := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jName))))
 	caveats, err := GoCaveats(env, jutil.Object(uintptr(unsafe.Pointer(jCaveats))))
@@ -437,7 +440,7 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	blessings, err := (*(*security.Principal)(jutil.NativePtr(goPtr))).BlessSelf(name, caveats...)
+	blessings, err := (*(*security.Principal)(jutil.GoRefValue(jutil.Ref(goRef)))).BlessSelf(name, caveats...)
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
@@ -451,10 +454,10 @@
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativeSign
-func Java_io_v_v23_security_VPrincipalImpl_nativeSign(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goPtr C.jlong, jMessage C.jbyteArray) C.jobject {
+func Java_io_v_v23_security_VPrincipalImpl_nativeSign(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goRef C.jlong, jMessage C.jbyteArray) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	message := jutil.GoByteArray(env, jutil.Object(uintptr(unsafe.Pointer(jMessage))))
-	sig, err := (*(*security.Principal)(jutil.NativePtr(goPtr))).Sign(message)
+	sig, err := (*(*security.Principal)(jutil.GoRefValue(jutil.Ref(goRef)))).Sign(message)
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
@@ -468,9 +471,9 @@
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativePublicKey
-func Java_io_v_v23_security_VPrincipalImpl_nativePublicKey(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_VPrincipalImpl_nativePublicKey(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	key := (*(*security.Principal)(jutil.NativePtr(goPtr))).PublicKey()
+	key := (*(*security.Principal)(jutil.GoRefValue(jutil.Ref(goRef)))).PublicKey()
 	jKey, err := JavaPublicKey(env, key)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -480,9 +483,9 @@
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativeBlessingStore
-func Java_io_v_v23_security_VPrincipalImpl_nativeBlessingStore(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_VPrincipalImpl_nativeBlessingStore(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	store := (*(*security.Principal)(jutil.NativePtr(goPtr))).BlessingStore()
+	store := (*(*security.Principal)(jutil.GoRefValue(jutil.Ref(goRef)))).BlessingStore()
 	jStore, err := JavaBlessingStore(env, store)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -492,9 +495,9 @@
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativeRoots
-func Java_io_v_v23_security_VPrincipalImpl_nativeRoots(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_VPrincipalImpl_nativeRoots(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	roots := (*(*security.Principal)(jutil.NativePtr(goPtr))).Roots()
+	roots := (*(*security.Principal)(jutil.GoRefValue(jutil.Ref(goRef)))).Roots()
 	jRoots, err := JavaBlessingRoots(env, roots)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -504,8 +507,8 @@
 }
 
 //export Java_io_v_v23_security_VPrincipalImpl_nativeFinalize
-func Java_io_v_v23_security_VPrincipalImpl_nativeFinalize(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_VPrincipalImpl_nativeFinalize(jenv *C.JNIEnv, jVPrincipalImpl C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_v23_security_Blessings_nativeCreate
@@ -516,8 +519,8 @@
 		jutil.JThrowV(env, err)
 		return C.jlong(0)
 	}
-	jutil.GoRef(&blessings) // Un-refed when the Java Blessings object is finalized.
-	return C.jlong(jutil.PtrValue(&blessings))
+	ref := jutil.GoNewRef(&blessings) // Un-refed when the Java Blessings object is finalized.
+	return C.jlong(ref)
 }
 
 //export Java_io_v_v23_security_Blessings_nativeCreateUnion
@@ -542,9 +545,9 @@
 }
 
 //export Java_io_v_v23_security_Blessings_nativePublicKey
-func Java_io_v_v23_security_Blessings_nativePublicKey(jenv *C.JNIEnv, jBlessings C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_Blessings_nativePublicKey(jenv *C.JNIEnv, jBlessings C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	key := (*(*security.Blessings)(jutil.NativePtr(goPtr))).PublicKey()
+	key := (*(*security.Blessings)(jutil.GoRefValue(jutil.Ref(goRef)))).PublicKey()
 	jPublicKey, err := JavaPublicKey(env, key)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -554,9 +557,9 @@
 }
 
 //export Java_io_v_v23_security_Blessings_nativeSigningBlessings
-func Java_io_v_v23_security_Blessings_nativeSigningBlessings(jenv *C.JNIEnv, jBlessings C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_Blessings_nativeSigningBlessings(jenv *C.JNIEnv, jBlessings C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessings := security.SigningBlessings(*(*security.Blessings)(jutil.NativePtr(goPtr)))
+	blessings := security.SigningBlessings(*(*security.Blessings)(jutil.GoRefValue(jutil.Ref(goRef))))
 	jSigningBlessings, err := JavaBlessings(env, blessings)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -566,9 +569,9 @@
 }
 
 //export Java_io_v_v23_security_Blessings_nativeWireFormat
-func Java_io_v_v23_security_Blessings_nativeWireFormat(jenv *C.JNIEnv, jBlessings C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_Blessings_nativeWireFormat(jenv *C.JNIEnv, jBlessings C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	wire := security.MarshalBlessings(*(*security.Blessings)(jutil.NativePtr(goPtr)))
+	wire := security.MarshalBlessings(*(*security.Blessings)(jutil.GoRefValue(jutil.Ref(goRef))))
 	jWire, err := JavaWireBlessings(env, wire)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -578,12 +581,12 @@
 }
 
 //export Java_io_v_v23_security_Blessings_nativeFinalize
-func Java_io_v_v23_security_Blessings_nativeFinalize(jenv *C.JNIEnv, jBlessings C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_Blessings_nativeFinalize(jenv *C.JNIEnv, jBlessings C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_v23_security_BlessingRootsImpl_nativeAdd
-func Java_io_v_v23_security_BlessingRootsImpl_nativeAdd(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goPtr C.jlong, jRoot C.jobject, jPattern C.jobject) {
+func Java_io_v_v23_security_BlessingRootsImpl_nativeAdd(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goRef C.jlong, jRoot C.jobject, jPattern C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	root, err := JavaPublicKeyToDER(env, jutil.Object(uintptr(unsafe.Pointer(jRoot))))
 	if err != nil {
@@ -595,14 +598,14 @@
 		jutil.JThrowV(env, err)
 		return
 	}
-	if err := (*(*security.BlessingRoots)(jutil.NativePtr(goPtr))).Add(root, pattern); err != nil {
+	if err := (*(*security.BlessingRoots)(jutil.GoRefValue(jutil.Ref(goRef)))).Add(root, pattern); err != nil {
 		jutil.JThrowV(env, err)
 		return
 	}
 }
 
 //export Java_io_v_v23_security_BlessingRootsImpl_nativeRecognized
-func Java_io_v_v23_security_BlessingRootsImpl_nativeRecognized(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goPtr C.jlong, jRoot C.jobject, jBlessing C.jstring) {
+func Java_io_v_v23_security_BlessingRootsImpl_nativeRecognized(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goRef C.jlong, jRoot C.jobject, jBlessing C.jstring) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	root, err := JavaPublicKeyToDER(env, jutil.Object(uintptr(unsafe.Pointer(jRoot))))
 	if err != nil {
@@ -610,31 +613,31 @@
 		return
 	}
 	blessing := jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jBlessing))))
-	if err := (*(*security.BlessingRoots)(jutil.NativePtr(goPtr))).Recognized(root, blessing); err != nil {
+	if err := (*(*security.BlessingRoots)(jutil.GoRefValue(jutil.Ref(goRef)))).Recognized(root, blessing); err != nil {
 		jutil.JThrowV(env, err)
 	}
 }
 
 //export Java_io_v_v23_security_BlessingRootsImpl_nativeDebugString
-func Java_io_v_v23_security_BlessingRootsImpl_nativeDebugString(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_BlessingRootsImpl_nativeDebugString(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	debug := (*(*security.BlessingRoots)(jutil.NativePtr(goPtr))).DebugString()
+	debug := (*(*security.BlessingRoots)(jutil.GoRefValue(jutil.Ref(goRef)))).DebugString()
 	jDebug := jutil.JString(env, debug)
 	return C.jstring(unsafe.Pointer(jDebug))
 }
 
 //export Java_io_v_v23_security_BlessingRootsImpl_nativeToString
-func Java_io_v_v23_security_BlessingRootsImpl_nativeToString(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_BlessingRootsImpl_nativeToString(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	str := fmt.Sprintf("%v", (*(*security.BlessingRoots)(jutil.NativePtr(goPtr))))
+	str := fmt.Sprintf("%v", (*(*security.BlessingRoots)(jutil.GoRefValue(jutil.Ref(goRef)))))
 	jStr := jutil.JString(env, str)
 	return C.jstring(unsafe.Pointer(jStr))
 }
 
 //export Java_io_v_v23_security_BlessingRootsImpl_nativeDump
-func Java_io_v_v23_security_BlessingRootsImpl_nativeDump(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_BlessingRootsImpl_nativeDump(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	dump := (*(*security.BlessingRoots)(jutil.NativePtr(goPtr))).Dump()
+	dump := (*(*security.BlessingRoots)(jutil.GoRefValue(jutil.Ref(goRef)))).Dump()
 	result := make(map[jutil.Object][]jutil.Object)
 	for pattern, keys := range dump {
 		jBlessingPattern, err := JavaBlessingPattern(env, pattern)
@@ -661,12 +664,12 @@
 }
 
 //export Java_io_v_v23_security_BlessingRootsImpl_nativeFinalize
-func Java_io_v_v23_security_BlessingRootsImpl_nativeFinalize(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_BlessingRootsImpl_nativeFinalize(jenv *C.JNIEnv, jBlessingRootsImpl C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeSet
-func Java_io_v_v23_security_BlessingStoreImpl_nativeSet(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jBlessings C.jobject, jForPeers C.jobject) C.jobject {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeSet(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong, jBlessings C.jobject, jForPeers C.jobject) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	blessings, err := GoBlessings(env, jutil.Object(uintptr(unsafe.Pointer(jBlessings))))
 	if err != nil {
@@ -678,7 +681,7 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	oldBlessings, err := (*(*security.BlessingStore)(jutil.NativePtr(goPtr))).Set(blessings, forPeers)
+	oldBlessings, err := (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))).Set(blessings, forPeers)
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
@@ -692,14 +695,14 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeForPeer
-func Java_io_v_v23_security_BlessingStoreImpl_nativeForPeer(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jPeerBlessings C.jobjectArray) C.jobject {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeForPeer(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong, jPeerBlessings C.jobjectArray) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	peerBlessings, err := jutil.GoStringArray(env, jutil.Object(uintptr(unsafe.Pointer(jPeerBlessings))))
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	blessings := (*(*security.BlessingStore)(jutil.NativePtr(goPtr))).ForPeer(peerBlessings...)
+	blessings := (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))).ForPeer(peerBlessings...)
 	jBlessings, err := JavaBlessings(env, blessings)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -709,22 +712,22 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeSetDefaultBlessings
-func Java_io_v_v23_security_BlessingStoreImpl_nativeSetDefaultBlessings(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jBlessings C.jobject) {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeSetDefaultBlessings(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong, jBlessings C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	blessings, err := GoBlessings(env, jutil.Object(uintptr(unsafe.Pointer(jBlessings))))
 	if err != nil {
 		jutil.JThrowV(env, err)
 		return
 	}
-	if err := (*(*security.BlessingStore)(jutil.NativePtr(goPtr))).SetDefault(blessings); err != nil {
+	if err := (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))).SetDefault(blessings); err != nil {
 		jutil.JThrowV(env, err)
 	}
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeDefaultBlessings
-func Java_io_v_v23_security_BlessingStoreImpl_nativeDefaultBlessings(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeDefaultBlessings(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessings, _ := (*(*security.BlessingStore)(jutil.NativePtr(goPtr))).Default()
+	blessings, _ := (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))).Default()
 	jBlessings, err := JavaBlessings(env, blessings)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -734,9 +737,9 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativePublicKey
-func Java_io_v_v23_security_BlessingStoreImpl_nativePublicKey(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_BlessingStoreImpl_nativePublicKey(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	key := (*(*security.BlessingStore)(jutil.NativePtr(goPtr))).PublicKey()
+	key := (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))).PublicKey()
 	jKey, err := JavaPublicKey(env, key)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -746,9 +749,9 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativePeerBlessings
-func Java_io_v_v23_security_BlessingStoreImpl_nativePeerBlessings(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_BlessingStoreImpl_nativePeerBlessings(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessingsMap := (*(*security.BlessingStore)(jutil.NativePtr(goPtr))).PeerBlessings()
+	blessingsMap := (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))).PeerBlessings()
 	bmap := make(map[jutil.Object]jutil.Object)
 	for pattern, blessings := range blessingsMap {
 		jPattern, err := JavaBlessingPattern(env, pattern)
@@ -772,9 +775,9 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeCacheDischarge
-func Java_io_v_v23_security_BlessingStoreImpl_nativeCacheDischarge(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jDischarge C.jobject, jCaveat C.jobject, jImpetus C.jobject) {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeCacheDischarge(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong, jDischarge C.jobject, jCaveat C.jobject, jImpetus C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessingStore := *(*security.BlessingStore)(jutil.NativePtr(goPtr))
+	blessingStore := *(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))
 	discharge, err := GoDischarge(env, jutil.Object(uintptr(unsafe.Pointer(jDischarge))))
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -795,9 +798,9 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeClearDischarges
-func Java_io_v_v23_security_BlessingStoreImpl_nativeClearDischarges(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jDischarges C.jobject) {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeClearDischarges(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong, jDischarges C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessingStore := *(*security.BlessingStore)(jutil.NativePtr(goPtr))
+	blessingStore := *(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))
 	arr, err := jutil.GoObjectArray(env, jutil.Object(uintptr(unsafe.Pointer(jDischarges))))
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -816,9 +819,9 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeDischarge
-func Java_io_v_v23_security_BlessingStoreImpl_nativeDischarge(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong, jCaveat C.jobject, jImpetus C.jobject) C.jobject {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeDischarge(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong, jCaveat C.jobject, jImpetus C.jobject) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	blessingStore := *(*security.BlessingStore)(jutil.NativePtr(goPtr))
+	blessingStore := *(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))
 	caveat, err := GoCaveat(env, jutil.Object(uintptr(unsafe.Pointer(jCaveat))))
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -841,36 +844,36 @@
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeDebugString
-func Java_io_v_v23_security_BlessingStoreImpl_nativeDebugString(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeDebugString(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	debug := (*(*security.BlessingStore)(jutil.NativePtr(goPtr))).DebugString()
+	debug := (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))).DebugString()
 	jDebug := jutil.JString(env, debug)
 	return C.jstring(unsafe.Pointer(jDebug))
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeToString
-func Java_io_v_v23_security_BlessingStoreImpl_nativeToString(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong) C.jstring {
+func Java_io_v_v23_security_BlessingStoreImpl_nativeToString(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong) C.jstring {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	str := fmt.Sprintf("%s", (*(*security.BlessingStore)(jutil.NativePtr(goPtr))))
+	str := fmt.Sprintf("%s", (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(goRef)))))
 	jStr := jutil.JString(env, str)
 	return C.jstring(unsafe.Pointer(jStr))
 }
 
 //export Java_io_v_v23_security_BlessingStoreImpl_nativeFinalize
-func Java_io_v_v23_security_BlessingStoreImpl_nativeFinalize(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_BlessingStoreImpl_nativeFinalize(jenv *C.JNIEnv, jBlessingStoreImpl C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_v23_security_BlessingPattern_nativeCreate
 func Java_io_v_v23_security_BlessingPattern_nativeCreate(jenv *C.JNIEnv, jBlessingPatternClass C.jclass, jValue C.jstring) C.jlong {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	pattern := security.BlessingPattern(jutil.GoString(env, jutil.Object(uintptr(unsafe.Pointer(jValue)))))
-	jutil.GoRef(&pattern) // Un-refed when the BlessingPattern object is finalized.
-	return C.jlong(jutil.PtrValue(&pattern))
+	ref := jutil.GoNewRef(&pattern) // Un-refed when the BlessingPattern object is finalized.
+	return C.jlong(ref)
 }
 
 //export Java_io_v_v23_security_BlessingPattern_nativeIsMatchedBy
-func Java_io_v_v23_security_BlessingPattern_nativeIsMatchedBy(jenv *C.JNIEnv, jBlessingPattern C.jobject, goPtr C.jlong, jBlessings C.jobjectArray) C.jboolean {
+func Java_io_v_v23_security_BlessingPattern_nativeIsMatchedBy(jenv *C.JNIEnv, jBlessingPattern C.jobject, goRef C.jlong, jBlessings C.jobjectArray) C.jboolean {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	blessings, err := jutil.GoStringArray(env, jutil.Object(uintptr(unsafe.Pointer(jBlessings))))
 	if err != nil {
@@ -878,7 +881,7 @@
 		return C.JNI_FALSE
 	}
 
-	matched := (*(*security.BlessingPattern)(jutil.NativePtr(goPtr))).MatchedBy(blessings...)
+	matched := (*(*security.BlessingPattern)(jutil.GoRefValue(jutil.Ref(goRef)))).MatchedBy(blessings...)
 	if matched {
 		return C.JNI_TRUE
 	}
@@ -886,8 +889,8 @@
 }
 
 //export Java_io_v_v23_security_BlessingPattern_nativeIsValid
-func Java_io_v_v23_security_BlessingPattern_nativeIsValid(jenv *C.JNIEnv, jBlessingPattern C.jobject, goPtr C.jlong) C.jboolean {
-	valid := (*(*security.BlessingPattern)(jutil.NativePtr(goPtr))).IsValid()
+func Java_io_v_v23_security_BlessingPattern_nativeIsValid(jenv *C.JNIEnv, jBlessingPattern C.jobject, goRef C.jlong) C.jboolean {
+	valid := (*(*security.BlessingPattern)(jutil.GoRefValue(jutil.Ref(goRef)))).IsValid()
 	if valid {
 		return C.JNI_TRUE
 	}
@@ -895,9 +898,9 @@
 }
 
 //export Java_io_v_v23_security_BlessingPattern_nativeMakeNonExtendable
-func Java_io_v_v23_security_BlessingPattern_nativeMakeNonExtendable(jenv *C.JNIEnv, jBlessingPattern C.jobject, goPtr C.jlong) C.jobject {
+func Java_io_v_v23_security_BlessingPattern_nativeMakeNonExtendable(jenv *C.JNIEnv, jBlessingPattern C.jobject, goRef C.jlong) C.jobject {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
-	pattern := (*(*security.BlessingPattern)(jutil.NativePtr(goPtr))).MakeNonExtendable()
+	pattern := (*(*security.BlessingPattern)(jutil.GoRefValue(jutil.Ref(goRef)))).MakeNonExtendable()
 	jPattern, err := JavaBlessingPattern(env, pattern)
 	if err != nil {
 		jutil.JThrowV(env, err)
@@ -907,8 +910,8 @@
 }
 
 //export Java_io_v_v23_security_BlessingPattern_nativeFinalize
-func Java_io_v_v23_security_BlessingPattern_nativeFinalize(jenv *C.JNIEnv, jBlessingPattern C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_security_BlessingPattern_nativeFinalize(jenv *C.JNIEnv, jBlessingPattern C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
 
 //export Java_io_v_v23_security_PublicKeyThirdPartyCaveatValidator_nativeValidate
@@ -1070,9 +1073,10 @@
 	default:
 		return nil
 	}
-	jutil.GoRef(&auth) // Un-refed when the Java PermissionsAuthorizer is finalized
-	jAuthorizer, err := jutil.NewObject(env, jutil.Class(uintptr(unsafe.Pointer(jPermissionsAuthorizerClass))), []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&auth)))
+	ref := jutil.GoNewRef(&auth) // Un-refed when the Java PermissionsAuthorizer is finalized
+	jAuthorizer, err := jutil.NewObject(env, jutil.Class(uintptr(unsafe.Pointer(jPermissionsAuthorizerClass))), []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		jutil.JThrowV(env, err)
 		return nil
 	}
diff --git a/v23/security/principal.go b/v23/security/principal.go
index 626c53b..712cb6d 100644
--- a/v23/security/principal.go
+++ b/v23/security/principal.go
@@ -24,11 +24,12 @@
 	if principal == nil {
 		return jutil.NullObject, nil
 	}
-	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(jutil.PtrValue(&principal)), jutil.NullObject, jutil.NullObject, jutil.NullObject)
+	ref := jutil.GoNewRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
+	jPrincipal, err := jutil.NewObject(env, jVPrincipalImplClass, []jutil.Sign{jutil.LongSign, signerSign, blessingStoreSign, blessingRootsSign}, int64(ref), jutil.NullObject, jutil.NullObject, jutil.NullObject)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&principal) // Un-refed when the Java VPrincipalImpl is finalized.
 	return jPrincipal, nil
 }
 
@@ -38,12 +39,12 @@
 		return nil, nil
 	}
 	if jutil.IsInstanceOf(env, jPrincipal, jVPrincipalImplClass) {
-		// Called with our implementation of VPrincipal, which maintains a Go pointer - use it.
-		goPtr, err := jutil.CallLongMethod(env, jPrincipal, "nativePtr", nil)
+		// Called with our implementation of VPrincipal, which maintains a Go reference - use it.
+		ref, err := jutil.CallLongMethod(env, jPrincipal, "nativeRef", nil)
 		if err != nil {
 			return nil, err
 		}
-		return (*(*security.Principal)(jutil.NativePtr(goPtr))), nil
+		return (*(*security.Principal)(jutil.GoRefValue(jutil.Ref(ref)))), nil
 	}
 
 	// Reference Java VPrincipal; it will be de-referenced when the Go Principal
diff --git a/v23/security/roots.go b/v23/security/roots.go
index 28c058c..61120b5 100644
--- a/v23/security/roots.go
+++ b/v23/security/roots.go
@@ -20,11 +20,12 @@
 // JavaBlessingRoots creates an instance of Java BlessingRoots that uses the provided Go
 // BlessingRoots as its underlying implementation.
 func JavaBlessingRoots(env jutil.Env, roots security.BlessingRoots) (jutil.Object, error) {
-	jRoots, err := jutil.NewObject(env, jBlessingRootsImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&roots)))
+	ref := jutil.GoNewRef(&roots) // Un-refed when the Java BlessingRootsImpl is finalized.
+	jRoots, err := jutil.NewObject(env, jBlessingRootsImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&roots) // Un-refed when the Java BlessingRootsImpl is finalized.
 	return jRoots, nil
 }
 
@@ -35,12 +36,12 @@
 		return nil, nil
 	}
 	if jutil.IsInstanceOf(env, jBlessingRoots, jBlessingRootsImplClass) {
-		// Called with our implementation of BlessingRoots, which maintains a Go pointer - use it.
-		goPtr, err := jutil.CallLongMethod(env, jBlessingRoots, "nativePtr", nil)
+		// Called with our implementation of BlessingRoots, which maintains a Go reference - use it.
+		ref, err := jutil.CallLongMethod(env, jBlessingRoots, "nativeRef", nil)
 		if err != nil {
 			return nil, err
 		}
-		return (*(*security.BlessingRoots)(jutil.NativePtr(goPtr))), nil
+		return (*(*security.BlessingRoots)(jutil.GoRefValue(jutil.Ref(ref)))), nil
 	}
 	// Reference Java BlessingRoots; it will be de-referenced when the Go
 	// BlessingRoots created below is garbage-collected (through the finalizer
diff --git a/v23/security/store.go b/v23/security/store.go
index 4dc8e08..3cc5c98 100644
--- a/v23/security/store.go
+++ b/v23/security/store.go
@@ -21,11 +21,12 @@
 // JavaBlessingStore creates an instance of Java BlessingStore that uses the provided Go
 // BlessingStore as its underlying implementation.
 func JavaBlessingStore(env jutil.Env, store security.BlessingStore) (jutil.Object, error) {
-	jObj, err := jutil.NewObject(env, jBlessingStoreImplClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&store)))
+	ref := jutil.GoNewRef(&store) // Un-refed when the Java BlessingStoreImpl is finalized.
+	jObj, err := jutil.NewObject(env, jBlessingStoreImplClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&store) // Un-refed when the Java BlessingStoreImpl is finalized.
 	return jObj, nil
 }
 
@@ -36,12 +37,12 @@
 		return nil, nil
 	}
 	if jutil.IsInstanceOf(env, jBlessingStore, jBlessingStoreImplClass) {
-		// Called with our implementation of BlessingStore, which maintains a Go pointer - use it.
-		goPtr, err := jutil.JLongField(env, jBlessingStore, "nativePtr")
+		// Called with our implementation of BlessingStore, which maintains a Go reference - use it.
+		ref, err := jutil.JLongField(env, jBlessingStore, "nativeRef")
 		if err != nil {
 			return nil, err
 		}
-		return (*(*security.BlessingStore)(jutil.NativePtr(goPtr))), nil
+		return (*(*security.BlessingStore)(jutil.GoRefValue(jutil.Ref(ref)))), nil
 	}
 	// Reference Java BlessingStore; it will be de-referenced when the Go
 	// BlessingStore created below is garbage-collected (through the finalizer
diff --git a/v23/security/util.go b/v23/security/util.go
index b5b352c..d796481 100644
--- a/v23/security/util.go
+++ b/v23/security/util.go
@@ -19,11 +19,12 @@
 
 // JavaBlessings converts the provided Go Blessings into Java Blessings.
 func JavaBlessings(env jutil.Env, blessings security.Blessings) (jutil.Object, error) {
-	jBlessings, err := jutil.NewObject(env, jBlessingsClass, []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&blessings)))
+	ref := jutil.GoNewRef(&blessings) // Un-refed when the Java Blessings object is finalized.
+	jBlessings, err := jutil.NewObject(env, jBlessingsClass, []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&blessings) // Un-refed when the Java Blessings object is finalized.
 	return jBlessings, nil
 }
 
@@ -32,11 +33,11 @@
 	if jBlessings.IsNull() {
 		return security.Blessings{}, nil
 	}
-	goPtr, err := jutil.CallLongMethod(env, jBlessings, "nativePtr", nil)
+	ref, err := jutil.CallLongMethod(env, jBlessings, "nativeRef", nil)
 	if err != nil {
 		return security.Blessings{}, err
 	}
-	return (*(*security.Blessings)(jutil.NativePtr(goPtr))), nil
+	return (*(*security.Blessings)(jutil.GoRefValue(jutil.Ref(ref)))), nil
 }
 
 // GoBlessingsArray converts the provided Java Blessings array into a Go
@@ -136,11 +137,12 @@
 // JavaBlessingPattern converts the provided Go BlessingPattern into Java
 // BlessingPattern.
 func JavaBlessingPattern(env jutil.Env, pattern security.BlessingPattern) (jutil.Object, error) {
-	jPattern, err := jutil.NewObject(env, jBlessingPatternClass, []jutil.Sign{jutil.LongSign, jutil.StringSign}, int64(jutil.PtrValue(&pattern)), string(pattern))
+	ref := jutil.GoNewRef(&pattern) // Un-refed when the Java BlessingRootsImpl is finalized.
+	jPattern, err := jutil.NewObject(env, jBlessingPatternClass, []jutil.Sign{jutil.LongSign, jutil.StringSign}, int64(ref), string(pattern))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(&pattern) // Un-refed when the Java BlessingRootsImpl is finalized.
 	return jPattern, nil
 }
 
@@ -149,11 +151,11 @@
 	if jPattern.IsNull() {
 		return "", nil
 	}
-	goPtr, err := jutil.CallLongMethod(env, jPattern, "nativePtr", nil)
+	ref, err := jutil.CallLongMethod(env, jPattern, "nativeRef", nil)
 	if err != nil {
 		return "", err
 	}
-	return (*(*security.BlessingPattern)(jutil.NativePtr(goPtr))), nil
+	return (*(*security.BlessingPattern)(jutil.GoRefValue(jutil.Ref(ref)))), nil
 }
 
 // JavaPublicKey converts the provided Go PublicKey into Java PublicKey.
diff --git a/v23/services/groups/jni.go b/v23/services/groups/jni.go
index c671d0d..75cacf3 100644
--- a/v23/services/groups/jni.go
+++ b/v23/services/groups/jni.go
@@ -39,9 +39,10 @@
 		jutil.JThrowV(env, err)
 		return nil
 	}
-	jutil.GoRef(&authorizer) // Un-refed when the Java PermissionsAuthorizer is finalized
-	jAuthorizer, err := jutil.NewObject(env, jutil.Class(uintptr(unsafe.Pointer(jPermissionsAuthorizerClass))), []jutil.Sign{jutil.LongSign}, int64(jutil.PtrValue(&authorizer)))
+	ref := jutil.GoNewRef(&authorizer) // Un-refed when the Java PermissionsAuthorizer is finalized
+	jAuthorizer, err := jutil.NewObject(env, jutil.Class(uintptr(unsafe.Pointer(jPermissionsAuthorizerClass))), []jutil.Sign{jutil.LongSign}, int64(ref))
 	if err != nil {
+		jutil.GoDecRef(ref)
 		jutil.JThrowV(env, err)
 		return nil
 	}
@@ -49,7 +50,7 @@
 }
 
 //export Java_io_v_v23_services_groups_PermissionsAuthorizer_nativeAuthorize
-func Java_io_v_v23_services_groups_PermissionsAuthorizer_nativeAuthorize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goPtr C.jlong, jContext C.jobject, jCall C.jobject) {
+func Java_io_v_v23_services_groups_PermissionsAuthorizer_nativeAuthorize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goRef C.jlong, jContext C.jobject, jCall C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jContext))))
 	if err != nil {
@@ -61,13 +62,13 @@
 		jutil.JThrowV(env, err)
 		return
 	}
-	if err := (*(*security.Authorizer)(jutil.NativePtr(goPtr))).Authorize(ctx, call); err != nil {
+	if err := (*(*security.Authorizer)(jutil.GoRefValue(jutil.Ref(goRef)))).Authorize(ctx, call); err != nil {
 		jutil.JThrowV(env, err)
 		return
 	}
 }
 
 //export Java_io_v_v23_services_groups_PermissionsAuthorizer_nativeFinalize
-func Java_io_v_v23_services_groups_PermissionsAuthorizer_nativeFinalize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_services_groups_PermissionsAuthorizer_nativeFinalize(jenv *C.JNIEnv, jPermissionsAuthorizer C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
diff --git a/v23/syncbase/nosql/jni.go b/v23/syncbase/nosql/jni.go
index 8cad8db..8710a7d 100644
--- a/v23/syncbase/nosql/jni.go
+++ b/v23/syncbase/nosql/jni.go
@@ -82,11 +82,11 @@
 }
 
 //export Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeBeginBatch
-func Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeBeginBatch(jenv *C.JNIEnv, jDatabaseImpl C.jobject, goPtr C.jlong, jContext C.jobject, jBatchOptsObj C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeBeginBatch(jenv *C.JNIEnv, jDatabaseImpl C.jobject, goRef C.jlong, jContext C.jobject, jBatchOptsObj C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
 	jBatchOpts := jutil.Object(uintptr(unsafe.Pointer(jBatchOptsObj)))
-	jdb := (*jniDatabase)(jutil.NativePtr(goPtr))
+	jdb := (*jniDatabase)(jutil.GoRefValue(jutil.Ref(goRef)))
 	var batchOpts wire.BatchOptions
 	if err := jutil.GoVomCopy(env, jBatchOpts, jBatchOptionsClass, &batchOpts); err != nil {
 		jutil.CallbackOnFailure(env, jCallback, err)
@@ -115,10 +115,10 @@
 }
 
 //export Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeEnforceSchema
-func Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeEnforceSchema(jenv *C.JNIEnv, jDatabaseImpl C.jobject, goPtr C.jlong, jContext C.jobject, jCallbackObj C.jobject) {
+func Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeEnforceSchema(jenv *C.JNIEnv, jDatabaseImpl C.jobject, goRef C.jlong, jContext C.jobject, jCallbackObj C.jobject) {
 	env := jutil.Env(uintptr(unsafe.Pointer(jenv)))
 	jCallback := jutil.Object(uintptr(unsafe.Pointer(jCallbackObj)))
-	jdb := (*jniDatabase)(jutil.NativePtr(goPtr))
+	jdb := (*jniDatabase)(jutil.GoRefValue(jutil.Ref(goRef)))
 	ctx, _, err := jcontext.GoContext(env, jutil.Object(uintptr(unsafe.Pointer(jContext))))
 	if err != nil {
 		jutil.CallbackOnFailure(env, jCallback, err)
@@ -130,6 +130,6 @@
 }
 
 //export Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeFinalize
-func Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeFinalize(jenv *C.JNIEnv, jDatabaseImpl C.jobject, goPtr C.jlong) {
-	jutil.GoUnref(jutil.NativePtr(goPtr))
+func Java_io_v_v23_syncbase_nosql_DatabaseImpl_nativeFinalize(jenv *C.JNIEnv, jDatabaseImpl C.jobject, goRef C.jlong) {
+	jutil.GoDecRef(jutil.Ref(goRef))
 }
diff --git a/v23/syncbase/nosql/util.go b/v23/syncbase/nosql/util.go
index 703c73c..74db874 100644
--- a/v23/syncbase/nosql/util.go
+++ b/v23/syncbase/nosql/util.go
@@ -43,11 +43,12 @@
 
 func javaDatabase(env jutil.Env, jdb *jniDatabase) (jutil.Object, error) {
 	schemaSign := jutil.ClassSign("io.v.v23.syncbase.nosql.Schema")
-	jDatabase, err := jutil.NewObject(env, jDatabaseImplClass, []jutil.Sign{jutil.LongSign, jutil.StringSign, jutil.StringSign, jutil.StringSign, schemaSign}, int64(jutil.PtrValue(jdb)), jdb.parentFullName, jdb.FullName(), jdb.Name(), jdb.jSchema)
+	ref := jutil.GoNewRef(jdb) // Un-refed when jDatabase is finalized
+	jDatabase, err := jutil.NewObject(env, jDatabaseImplClass, []jutil.Sign{jutil.LongSign, jutil.StringSign, jutil.StringSign, jutil.StringSign, schemaSign}, int64(ref), jdb.parentFullName, jdb.FullName(), jdb.Name(), jdb.jSchema)
 	if err != nil {
+		jutil.GoDecRef(ref)
 		return jutil.NullObject, err
 	}
-	jutil.GoRef(jdb) // Un-refed when jDatabase is finalized
 	return jDatabase, nil
 }