Skip to content
This repository has been archived by the owner on Mar 8, 2020. It is now read-only.

JVM object encode implementation #93

Merged
merged 2 commits into from
Jul 5, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/main/native/jni_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ JNIEnv *getJNIEnv() {
return pEnv;
}

// Class fully qualified names
const char CLS_NODE[] = "org/bblfsh/client/v2/Node";
const char CLS_CTX[] = "org/bblfsh/client/v2/Context";
const char CLS_CTX[] = "org/bblfsh/client/v2/ContextExt";
const char CLS_OBJ[] = "java/lang/Object";
const char CLS_RE[] = "java/lang/RuntimeException";
const char CLS_JNODE[] = "org/bblfsh/client/v2/JNode";
Expand All @@ -34,6 +35,7 @@ const char CLS_JUINT[] = "org/bblfsh/client/v2/JUint";
const char CLS_JARR[] = "org/bblfsh/client/v2/JArray";
const char CLS_JOBJ[] = "org/bblfsh/client/v2/JObject";

// Method signatures
const char METHOD_JNODE_KEY_AT[] = "(I)Ljava/lang/String;";
const char METHOD_JNODE_VALUE_AT[] = "(I)Lorg/bblfsh/client/v2/JNode;";
const char METHOD_JOBJ_ADD[] =
Expand Down Expand Up @@ -126,8 +128,8 @@ jfieldID getField(JNIEnv *env, jobject obj, const char *name) {
return jfid;
}

static jmethodID MethodID(JNIEnv *env, const char *method,
const char *signature, const char *className) {
jmethodID MethodID(JNIEnv *env, const char *method, const char *signature,
const char *className) {
jclass cls = env->FindClass(className);
checkJvmException(std::string("failed to find a class ").append(className));

Expand Down Expand Up @@ -171,7 +173,7 @@ jobject ObjectMethod(JNIEnv *env, const char *method, const char *signature,
va_start(varargs, object);
jobject res = env->CallObjectMethodV(*object, mId, varargs);
va_end(varargs);
checkJvmException(std::string("failed get varargs for ")
checkJvmException(std::string("failed to get varargs for ")
.append(className)
.append(".")
.append(method));
Expand Down
1 change: 1 addition & 0 deletions src/main/native/jni_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ jint IntMethod(JNIEnv *, const char *, const char *, const char *,
jobject ObjectMethod(JNIEnv *, const char *, const char *, const char *,
const jobject *, ...);

jmethodID MethodID(JNIEnv *, const char *, const char *, const char *);
#endif
20 changes: 10 additions & 10 deletions src/main/native/org_bblfsh_client_v2_Context.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions src/main/native/org_bblfsh_client_v2_ContextExt.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

132 changes: 87 additions & 45 deletions src/main/native/org_bblfsh_client_v2_libuast_Libuast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "jni_utils.h"
#include "org_bblfsh_client_v2_Context.h"
#include "org_bblfsh_client_v2_ContextExt.h"
#include "org_bblfsh_client_v2_Context__.h"
#include "org_bblfsh_client_v2_Node.h"
#include "org_bblfsh_client_v2_libuast_Libuast.h"
Expand Down Expand Up @@ -72,9 +73,7 @@ class ContextExt {

JNIEnv *env = getJNIEnv();
jclass cls = env->FindClass(CLS_NODE);
if (env->ExceptionOccurred() || !cls) {
return 0;
}
checkJvmException("failed to find class " + std::string(CLS_NODE));

if (!env->IsInstanceOf(obj, cls)) {
const char *err = "ContextExt.toHandle() called not on Node type";
Expand All @@ -84,9 +83,7 @@ class ContextExt {

auto handle =
(NodeHandle)env->GetLongField(obj, getField(env, obj, "handle"));
if (env->ExceptionOccurred() || !handle) {
return 0;
}
checkJvmException("failed to get field Node.handle");

return handle;
}
Expand All @@ -103,11 +100,12 @@ class ContextExt {
return toJ(root);
}

// Encode serializes external UAST.
// Encode serializes the external UAST.
// Borrows the reference.
jobject Encode(jobject node, UastFormat format) {
NodeHandle h = toHandle(node);
uast::Buffer data = ctx->Encode(h, format);
// if (!assertNotContext(node)) return nullptr;

uast::Buffer data = ctx->Encode(toHandle(node), format);
return asJvmBuffer(data);
}
};
Expand All @@ -131,7 +129,7 @@ class Node : public uast::Node<Node *> {
static NodeKind kindOf(jobject obj) {
JNIEnv *env = getJNIEnv();
// TODO(bzz): expose JNode.kind & replace type comparison \w a string test
if (!obj) {
if (!obj || env->IsInstanceOf(obj, env->FindClass(CLS_JNULL))) {
return NODE_NULL;
} else if (env->IsInstanceOf(obj, env->FindClass(CLS_JSTR))) {
return NODE_STRING;
Expand Down Expand Up @@ -189,49 +187,71 @@ class Node : public uast::Node<Node *> {

NodeKind Kind() { return kind; }

// TODO(#90): implement and test (all 'As*' are unused stubs for now)
std::string *AsString() {
std::string *AsString() { // new ref
if (!str) {
const char methodName[] = "str";
JNIEnv *env = getJNIEnv();
const char *utf = env->GetStringUTFChars((jstring)obj, 0);
jstring jstr = (jstring)ObjectMethod(
env, methodName, "()Ljava/lang/String;", CLS_JSTR, &obj);

const char *utf = env->GetStringUTFChars(jstr, 0);
str = new std::string(utf);
env->ReleaseStringUTFChars((jstring)obj, utf);
env->ReleaseStringUTFChars(jstr, utf);
}

std::string *s = new std::string(*str);
return s;
}
int64_t AsInt() {
const char methodName[] = "num";
JNIEnv *env = getJNIEnv();
jclass cls = env->FindClass("java/lang/Integer");
jmethodID valueId = env->GetMethodID(cls, "longValue", "()J");
long long value = (long long)env->CallLongMethod(obj, valueId);
jmethodID mID = MethodID(env, methodName, "()J", CLS_JINT);

long long value = (long long)env->CallLongMethod(obj, mID);
checkJvmException(std::string("failed to call ")
.append(CLS_JINT)
.append(".")
.append(methodName)
.append(" at Node::AsInt()"));
return (int64_t)(value);
}
uint64_t AsUint() {
const char methodName[] = "get";
JNIEnv *env = getJNIEnv();
jclass cls = env->FindClass("java/lang/Integer");
jmethodID valueId = env->GetMethodID(cls, "intValue", "()I");
jlong value = env->CallIntMethod(obj, valueId);
jmethodID mID = MethodID(env, methodName, "()J", CLS_JUINT);

jmethodID mId = env->GetMethodID(cls, "toUnsignedLong", "(I)J");
jlong v = env->CallLongMethod(obj, mId, value);

return (uint64_t)(v);
jlong value = env->CallLongMethod(obj, mID);
checkJvmException(std::string("failed to call ")
.append(CLS_JUINT)
.append(".")
.append(methodName)
.append(" at Node::AsUint()"));
return (uint64_t)(value);
}
double AsFloat() {
const char methodName[] = "num";
JNIEnv *env = getJNIEnv();
jclass cls = env->FindClass("java/lang/Double");
jmethodID valueId = env->GetMethodID(cls, "floatValue", "()F");
float value = (float)env->CallFloatMethod(obj, valueId);
jmethodID mID = MethodID(env, methodName, "()D", CLS_JFLT);

double value = (double)env->CallDoubleMethod(obj, mID);
checkJvmException(std::string("failed to call ")
.append(CLS_JFLT)
.append(".")
.append(methodName)
.append(" at Node::AsFloat()"));
return value;
}
bool AsBool() {
const char methodName[] = "value";
JNIEnv *env = getJNIEnv();
// TODO(bzz) check failures, cache classes, read 'value' filed
jclass cls = env->FindClass("java/lang/Boolean");
jmethodID valueId = env->GetMethodID(cls, "booleanValue", "()Z");
bool value = (bool)env->CallBooleanMethod(obj, valueId);
jmethodID mID = MethodID(env, methodName, "()Z", CLS_JBOOL);

bool value = (bool)env->CallBooleanMethod(obj, mID);
checkJvmException(std::string("failed to call ")
.append(CLS_JBOOL)
.append(".")
.append(methodName)
.append(" at Node::AsBool()"));
return value;
}
size_t Size() {
Expand All @@ -245,7 +265,7 @@ class Node : public uast::Node<Node *> {

JNIEnv *env = getJNIEnv();
jstring key = (jstring)ObjectMethod(env, "keyAt", METHOD_JNODE_KEY_AT,
CLS_JNODE, &obj);
CLS_JNODE, &obj, i);

const char *k = env->GetStringUTFChars(key, 0);
std::string *s = new std::string(k);
Expand All @@ -258,7 +278,7 @@ class Node : public uast::Node<Node *> {

JNIEnv *env = getJNIEnv();
jobject val =
ObjectMethod(env, "valueAt", METHOD_JNODE_VALUE_AT, CLS_JNODE, &obj);
ObjectMethod(env, "valueAt", METHOD_JNODE_VALUE_AT, CLS_JNODE, &obj, i);
return lookupOrCreate(env->NewGlobalRef(val)); // new ref
}

Expand Down Expand Up @@ -287,8 +307,7 @@ class Node : public uast::Node<Node *> {

jstring k = env->NewStringUTF(key.data());

jobject res =
ObjectMethod(env, "add", METHOD_JOBJ_ADD, CLS_JOBJ, &obj, k, v);
ObjectMethod(env, "add", METHOD_JOBJ_ADD, CLS_JOBJ, &obj, k, v);
checkJvmException(
std::string("failed to call JObject.add() from Node::SetKeyValue(")
.append(key)
Expand Down Expand Up @@ -404,6 +423,9 @@ class Context {
if (node == nullptr) return nullptr;
return iface->toJ(node);
}
// toNode returns a node associated with a JVM object.
// Returns a new reference.
Node *toNode(jobject obj) { return iface->lookupOrCreate(obj); }

public:
Context() {
Expand All @@ -427,6 +449,16 @@ class Context {
return toJ(root); // new ref
}

// Encode serializes UAST.
// Creates a new reference.
jobject Encode(jobject node, UastFormat format) {
// if (!assertNotContext(node)) return nullptr;

Node *n = toNode(node);
uast::Buffer data = ctx->Encode(n, format);
return asJvmBuffer(data);
}

jobject LoadFrom(jobject src) { // JNode
JNIEnv *env = getJNIEnv();

Expand Down Expand Up @@ -474,13 +506,13 @@ JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_decode(
jCtxExt = nullptr;
delete (ctx);
delete (p);
checkJvmException("failed to instantiate Context class");
checkJvmException("failed to instantiate ContextExt class");
}

return jCtxExt;
}

// TODO(#86): implement
// TODO(#83): implement
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_filter(
JNIEnv *, jobject, jobject, jstring) {
return nullptr;
Expand All @@ -490,30 +522,40 @@ JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_filter(
// v2.Context()
// ==========================================

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_encode(
JNIEnv *env, jobject self, jobject node) {
UastFormat fmt = UAST_BINARY; // TODO(bzz): make it argument

Context *p = getHandle<Context>(env, self, nativeContext);
return p->Encode(node, fmt);
}

JNIEXPORT jlong JNICALL
Java_org_bblfsh_client_v2_Context_00024_create(JNIEnv *env, jobject self) {
auto c = new Context();
uast::Context<NodeHandle> *ctx; // TODO(#90): init from c on encode() impl
auto p = new ContextExt(ctx);
return (long)p;
return (long)c;
}

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_root(JNIEnv *env,
jobject self) {
// ==========================================
// v2.ContextExt()
// ==========================================

JNIEXPORT jobject JNICALL
Java_org_bblfsh_client_v2_ContextExt_root(JNIEnv *env, jobject self) {
ContextExt *p = getHandle<ContextExt>(env, self, nativeContext);
return p->RootNode();
}

JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_encode(
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_ContextExt_encode(
JNIEnv *env, jobject self, jobject node) {
UastFormat fmt = UAST_BINARY; // TODO(bzz): make it argument & enum

ContextExt *p = getHandle<ContextExt>(env, self, nativeContext);
return p->Encode(node, fmt);
}

JNIEXPORT void JNICALL Java_org_bblfsh_client_v2_Context_dispose(JNIEnv *env,
jobject self) {
JNIEXPORT void JNICALL
Java_org_bblfsh_client_v2_ContextExt_dispose(JNIEnv *env, jobject self) {
ContextExt *p = getHandle<ContextExt>(env, self, nativeContext);
setHandle<ContextExt>(env, self, 0, nativeContext);
delete p;
Expand Down
Loading