Skip to content

Instantly share code, notes, and snippets.

@KonstantinBerkow
Created March 4, 2018 21:26
Show Gist options
  • Save KonstantinBerkow/662944c52d51268ad5e35e21e0f83298 to your computer and use it in GitHub Desktop.
Save KonstantinBerkow/662944c52d51268ad5e35e21e0f83298 to your computer and use it in GitHub Desktop.
//
// Created by Konstantin Berkow on 3/4/18.
//
#include "lookup_cache.h"
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
OK = 0,
FAILED_LOCAL = 1,
FAILED_GLOBAL = 2
} ClassLookupResult;
static ClassLookupResult initClass(JNIEnv* env, jclass* class, const char* className) {
jclass localRef = (*env)->FindClass(env, className);
if (!localRef) { // pending exception we can rest
return FAILED_LOCAL;
}
jclass globalRef = (*env)->NewGlobalRef(env, localRef);
(*env)->DeleteLocalRef(env, localRef);
if (!globalRef) {
return FAILED_GLOBAL;
}
*class = globalRef;
return OK;
}
static void emergencyRelease(JNIEnv* env, LookupHolder* holder, const jclass classes[], int count) {
if (!holder) {
return;
}
for (int i = 0; i < count; ++i) {
(*env)->DeleteGlobalRef(env, classes[i]);
}
free(holder);
}
static void throwNoMemoryException(JNIEnv* env, const char* className) {
static const char* const errorPrefix = "Failed to create global reference for class ";
const size_t errorTextLen = strlen(errorPrefix) + strlen(className) + 1;
char* const errorText = malloc(sizeof(char) * errorTextLen);
strcpy(errorText, errorPrefix);
strcat(errorText, className);
jclass clazz = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
if (clazz) {
(*env)->ThrowNew(env, clazz, errorText);
(*env)->DeleteLocalRef(env, clazz);
}
free(errorText);
}
LookupHolder* initLookup(JNIEnv* env) {
LookupHolder* holder = malloc(sizeof(LookupHolder));
const jclass classes[] = {holder->Object, holder->String};
const char* const classNames[] = {"java/lang/Object", "java/lang/String"};
const int count = (sizeof(classNames) / sizeof(classNames[0]));
for (int i = 0; i < count; ++i) {
const char* const name = classNames[i];
switch (initClass(env, classes[i], name)) {
case OK:
break;
case FAILED_LOCAL:
// jvm exception pending
// cleanup initialized refs
emergencyRelease(env, holder, classes, i);
return NULL;
case FAILED_GLOBAL:
// cleanup initialized refs
emergencyRelease(env, holder, classes, i);
// raise our exception
throwNoMemoryException(env, name);
return NULL;
}
}
// (*env)->GetMethodID(env, holder->Object, "toString", "()Ljava/lang/String;");
return holder;
}
void releaseLookup(JNIEnv* env, LookupHolder* holder) {
if (!holder) {
return;
}
(*env)->DeleteGlobalRef(env, holder->Object);
(*env)->DeleteGlobalRef(env, holder->String);
free(holder);
}
#ifdef __cplusplus
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment