Created
March 4, 2018 21:26
-
-
Save KonstantinBerkow/662944c52d51268ad5e35e21e0f83298 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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