github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/bind/java/seq_android.c (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include <android/log.h>
     6  #include <errno.h>
     7  #include <jni.h>
     8  #include <stdint.h>
     9  #include <stdio.h>
    10  #include <unistd.h>
    11  #include "seq_android.h"
    12  #include "_cgo_export.h"
    13  
    14  #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "go/Seq", __VA_ARGS__)
    15  #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "go/Seq", __VA_ARGS__)
    16  
    17  static jfieldID memptr_id;
    18  static jfieldID receive_refnum_id;
    19  static jfieldID receive_code_id;
    20  static jfieldID receive_handle_id;
    21  
    22  static jclass jbytearray_clazz;
    23  
    24  // pinned represents a pinned array to be released at the end of Send call.
    25  typedef struct pinned {
    26  	jobject ref;
    27  	void* ptr;
    28  	struct pinned* next;
    29  } pinned;
    30  
    31  // mem is a simple C equivalent of seq.Buffer.
    32  //
    33  // Many of the allocations around mem could be avoided to improve
    34  // function call performance, but the goal is to start simple.
    35  typedef struct mem {
    36  	uint8_t *buf;
    37  	uint32_t off;
    38  	uint32_t len;
    39  	uint32_t cap;
    40  
    41  	// TODO(hyangah): have it as a separate field outside mem?
    42  	pinned* pinned;
    43  } mem;
    44  
    45  // mem_ensure ensures that m has at least size bytes free.
    46  // If m is NULL, it is created.
    47  static mem *mem_ensure(mem *m, uint32_t size) {
    48  	if (m == NULL) {
    49  		m = (mem*)malloc(sizeof(mem));
    50  		if (m == NULL) {
    51  			LOG_FATAL("mem_ensure malloc failed");
    52  		}
    53  		m->cap = 0;
    54  		m->off = 0;
    55  		m->len = 0;
    56  		m->buf = NULL;
    57  		m->pinned = NULL;
    58  	}
    59  	uint32_t cap = m->cap;
    60  	if (m->cap > m->off+size) {
    61  		return m;
    62  	}
    63  	if (cap == 0) {
    64  		cap = 64;
    65  	}
    66  	// TODO(hyangah): consider less aggressive allocation such as
    67  	//   cap += max(pow2round(size), 64)
    68  	while (cap < m->off+size) {
    69  		cap *= 2;
    70  	}
    71  	m->buf = (uint8_t*)realloc((void*)m->buf, cap);
    72  	if (m->buf == NULL) {
    73  		LOG_FATAL("mem_ensure realloc failed, off=%d, size=%d", m->off, size);
    74  	}
    75  	m->cap = cap;
    76  	return m;
    77  }
    78  
    79  static mem *mem_get(JNIEnv *env, jobject obj) {
    80  	// Storage space for pointer is always 64-bits, even on 32-bit
    81  	// machines. Cast to uintptr_t to avoid -Wint-to-pointer-cast.
    82  	return (mem*)(uintptr_t)(*env)->GetLongField(env, obj, memptr_id);
    83  }
    84  
    85  static uint32_t align(uint32_t offset, uint32_t alignment) {
    86  	uint32_t pad = offset % alignment;
    87  	if (pad > 0) {
    88  		pad = alignment-pad;
    89  	}
    90  	return pad+offset;
    91  }
    92  
    93  static uint8_t *mem_read(JNIEnv *env, jobject obj, uint32_t size, uint32_t alignment) {
    94  	if (size == 0) {
    95  		return NULL;
    96  	}
    97  	mem *m = mem_get(env, obj);
    98  	if (m == NULL) {
    99  		LOG_FATAL("mem_read on NULL mem");
   100  	}
   101  	uint32_t offset = align(m->off, alignment);
   102  
   103  	if (m->len-offset < size) {
   104  		LOG_FATAL("short read");
   105  	}
   106  	uint8_t *res = m->buf+offset;
   107  	m->off = offset+size;
   108  	return res;
   109  }
   110  
   111  uint8_t *mem_write(JNIEnv *env, jobject obj, uint32_t size, uint32_t alignment) {
   112  	mem *m = mem_get(env, obj);
   113  	if (m == NULL) {
   114  		LOG_FATAL("mem_write on NULL mem");
   115  	}
   116  	if (m->off != m->len) {
   117  		LOG_FATAL("write can only append to seq, size: (off=%d, len=%d, size=%d", m->off, m->len, size);
   118  	}
   119  	uint32_t offset = align(m->off, alignment);
   120  	m = mem_ensure(m, offset - m->off + size);
   121  	uint8_t *res = m->buf+offset;
   122  	m->off = offset+size;
   123  	m->len = offset+size;
   124  	return res;
   125  }
   126  
   127  static void *pin_array(JNIEnv *env, jobject obj, jobject arr) {
   128  	mem *m = mem_get(env, obj);
   129  	if (m == NULL) {
   130  		m = mem_ensure(m, 64);
   131  	}
   132  	pinned *p = (pinned*) malloc(sizeof(pinned));
   133  	if (p == NULL) {
   134  		LOG_FATAL("pin_array malloc failed");
   135  	}
   136  	p->ref = (*env)->NewGlobalRef(env, arr);
   137  
   138  	if ((*env)->IsInstanceOf(env, p->ref, jbytearray_clazz)) {
   139  		p->ptr = (*env)->GetByteArrayElements(env, p->ref, NULL);
   140  	} else {
   141  		LOG_FATAL("unsupported array type");
   142  	}
   143  
   144  	p->next = m->pinned;
   145  	m->pinned = p;
   146  	return p->ptr;
   147  }
   148  
   149  static void unpin_arrays(JNIEnv *env, mem *m) {
   150  	pinned* p = m->pinned;
   151  	while (p != NULL) {
   152  		if ((*env)->IsInstanceOf(env, p->ref, jbytearray_clazz)) {
   153  			(*env)->ReleaseByteArrayElements(env, p->ref, (jbyte*)p->ptr, JNI_ABORT);
   154  		} else {
   155  			LOG_FATAL("invalid array type");
   156  		}
   157  
   158  		(*env)->DeleteGlobalRef(env, p->ref);
   159  
   160  		pinned* o = p;
   161  		p = p->next;
   162  		free(o);
   163  	}
   164  	m->pinned = NULL;
   165  }
   166  
   167  static void describe_exception(JNIEnv* env) {
   168  	jthrowable exc = (*env)->ExceptionOccurred(env);
   169  	if (exc) {
   170  		(*env)->ExceptionDescribe(env);
   171  		(*env)->ExceptionClear(env);
   172  	}
   173  }
   174  
   175  static jfieldID find_field(JNIEnv *env, const char *class_name, const char *field_name, const char *field_type) {
   176  	jclass clazz = (*env)->FindClass(env, class_name);
   177  	if (clazz == NULL) {
   178  		describe_exception(env);
   179  		LOG_FATAL("cannot find %s", class_name);
   180  		return NULL;
   181  	}
   182  	jfieldID id = (*env)->GetFieldID(env, clazz, field_name , field_type);
   183  	if(id == NULL) {
   184  		describe_exception(env);
   185  		LOG_FATAL("no %s/%s field", field_name, field_type);
   186  		return NULL;
   187  	}
   188  	return id;
   189  }
   190  
   191  static jclass find_class(JNIEnv *env, const char *class_name) {
   192  	jclass clazz = (*env)->FindClass(env, class_name);
   193  	if (clazz == NULL) {
   194  		describe_exception(env);
   195  		LOG_FATAL("cannot find %s", class_name);
   196  		return NULL;
   197  	}
   198  	return (*env)->NewGlobalRef(env, clazz);
   199  }
   200  
   201  JNIEXPORT void JNICALL
   202  Java_go_Seq_initSeq(JNIEnv *env, jclass clazz) {
   203  	memptr_id = find_field(env, "go/Seq", "memptr", "J");
   204  	receive_refnum_id = find_field(env, "go/Seq$Receive", "refnum", "I");
   205  	receive_handle_id = find_field(env, "go/Seq$Receive", "handle", "I");
   206  	receive_code_id = find_field(env, "go/Seq$Receive", "code", "I");
   207  
   208  	jclass bclazz = find_class(env, "[B");
   209  	jbytearray_clazz = (*env)->NewGlobalRef(env, bclazz);
   210  }
   211  
   212  JNIEXPORT void JNICALL
   213  Java_go_Seq_ensure(JNIEnv *env, jobject obj, jint size) {
   214  	mem *m = mem_get(env, obj);
   215  	if (m == NULL || m->off+size > m->cap) {
   216  		m = mem_ensure(m, size);
   217  		(*env)->SetLongField(env, obj, memptr_id, (jlong)(uintptr_t)m);
   218  	}
   219  }
   220  
   221  JNIEXPORT void JNICALL
   222  Java_go_Seq_free(JNIEnv *env, jobject obj) {
   223  	mem *m = mem_get(env, obj);
   224  	if (m != NULL) {
   225  		unpin_arrays(env, m);
   226  		free((void*)m->buf);
   227  		free((void*)m);
   228  	}
   229  }
   230  
   231  #define MEM_READ(obj, ty) ((ty*)mem_read(env, obj, sizeof(ty), sizeof(ty)))
   232  
   233  JNIEXPORT jboolean JNICALL
   234  Java_go_Seq_readBool(JNIEnv *env, jobject obj) {
   235  	int8_t *v = MEM_READ(obj, int8_t);
   236  	if (v == NULL) {
   237  		return 0;
   238  	}
   239  	return *v != 0 ? 1 : 0;
   240  }
   241  
   242  JNIEXPORT jbyte JNICALL
   243  Java_go_Seq_readInt8(JNIEnv *env, jobject obj) {
   244  	uint8_t *v = MEM_READ(obj, uint8_t);
   245  	if (v == NULL) {
   246  		return 0;
   247  	}
   248  	return *v;
   249  }
   250  
   251  JNIEXPORT jshort JNICALL
   252  Java_go_Seq_readInt16(JNIEnv *env, jobject obj) {
   253  	int16_t *v = MEM_READ(obj, int16_t);
   254  	return v == NULL ? 0 : *v;
   255  }
   256  
   257  JNIEXPORT jint JNICALL
   258  Java_go_Seq_readInt32(JNIEnv *env, jobject obj) {
   259  	int32_t *v = MEM_READ(obj, int32_t);
   260  	return v == NULL ? 0 : *v;
   261  }
   262  
   263  JNIEXPORT jlong JNICALL
   264  Java_go_Seq_readInt64(JNIEnv *env, jobject obj) {
   265  	int64_t *v = MEM_READ(obj, int64_t);
   266  	return v == NULL ? 0 : *v;
   267  }
   268  
   269  JNIEXPORT jfloat JNICALL
   270  Java_go_Seq_readFloat32(JNIEnv *env, jobject obj) {
   271  	float *v = MEM_READ(obj, float);
   272  	return v == NULL ? 0 : *v;
   273  }
   274  
   275  JNIEXPORT jdouble JNICALL
   276  Java_go_Seq_readFloat64(JNIEnv *env, jobject obj) {
   277  	double *v = MEM_READ(obj, double);
   278  	return v == NULL ? 0 : *v;
   279  }
   280  
   281  JNIEXPORT jstring JNICALL
   282  Java_go_Seq_readUTF16(JNIEnv *env, jobject obj) {
   283  	int32_t size = *MEM_READ(obj, int32_t);
   284  	if (size == 0) {
   285  		return NULL;
   286  	}
   287  	return (*env)->NewString(env, (jchar*)mem_read(env, obj, 2*size, 1), size);
   288  }
   289  
   290  JNIEXPORT jbyteArray JNICALL
   291  Java_go_Seq_readByteArray(JNIEnv *env, jobject obj) {
   292  	// Send the (array length, pointer) pair encoded as two int64.
   293  	// The pointer value is omitted if array length is 0.
   294  	jlong size = Java_go_Seq_readInt64(env, obj);
   295  	if (size == 0) {
   296  		return NULL;
   297  	}
   298  	jbyteArray res = (*env)->NewByteArray(env, size);
   299  	jlong ptr = Java_go_Seq_readInt64(env, obj);
   300  	(*env)->SetByteArrayRegion(env, res, 0, size, (jbyte*)(intptr_t)(ptr));
   301  	return res;
   302  }
   303  
   304  #define MEM_WRITE(ty) (*(ty*)mem_write(env, obj, sizeof(ty), sizeof(ty)))
   305  
   306  JNIEXPORT void JNICALL
   307  Java_go_Seq_writeBool(JNIEnv *env, jobject obj, jboolean v) {
   308  	MEM_WRITE(int8_t) = v ? 1 : 0;
   309  }
   310  
   311  JNIEXPORT void JNICALL
   312  Java_go_Seq_writeInt8(JNIEnv *env, jobject obj, jbyte v) {
   313  	MEM_WRITE(int8_t) = v;
   314  }
   315  
   316  JNIEXPORT void JNICALL
   317  Java_go_Seq_writeInt16(JNIEnv *env, jobject obj, jshort v) {
   318  	MEM_WRITE(int16_t) = v;
   319  }
   320  
   321  JNIEXPORT void JNICALL
   322  Java_go_Seq_writeInt32(JNIEnv *env, jobject obj, jint v) {
   323  	MEM_WRITE(int32_t) = v;
   324  }
   325  
   326  JNIEXPORT void JNICALL
   327  Java_go_Seq_writeInt64(JNIEnv *env, jobject obj, jlong v) {
   328  	MEM_WRITE(int64_t) = v;
   329  }
   330  
   331  JNIEXPORT void JNICALL
   332  Java_go_Seq_writeFloat32(JNIEnv *env, jobject obj, jfloat v) {
   333  	MEM_WRITE(float) = v;
   334  }
   335  
   336  JNIEXPORT void JNICALL
   337  Java_go_Seq_writeFloat64(JNIEnv *env, jobject obj, jdouble v) {
   338  	MEM_WRITE(double) = v;
   339  }
   340  
   341  JNIEXPORT void JNICALL
   342  Java_go_Seq_writeUTF16(JNIEnv *env, jobject obj, jstring v) {
   343  	if (v == NULL) {
   344  		MEM_WRITE(int32_t) = 0;
   345  		return;
   346  	}
   347  	int32_t size = (*env)->GetStringLength(env, v);
   348  	MEM_WRITE(int32_t) = size;
   349  	(*env)->GetStringRegion(env, v, 0, size, (jchar*)mem_write(env, obj, 2*size, 1));
   350  }
   351  
   352  JNIEXPORT void JNICALL
   353  Java_go_Seq_writeByteArray(JNIEnv *env, jobject obj, jbyteArray v) {
   354  	// For Byte array, we pass only the (array length, pointer) pair
   355  	// encoded as two int64 values. If the array length is 0,
   356  	// the pointer value is omitted.
   357  	if (v == NULL) {
   358  		MEM_WRITE(int64_t) = 0;
   359  		return;
   360  	}
   361  
   362  	jsize len = (*env)->GetArrayLength(env, v);
   363  	MEM_WRITE(int64_t) = len;
   364  	if (len == 0) {
   365  		return;
   366  	}
   367  
   368  	jbyte* b = pin_array(env, obj, v);
   369  	MEM_WRITE(int64_t) = (jlong)(uintptr_t)b;
   370  }
   371  
   372  JNIEXPORT void JNICALL
   373  Java_go_Seq_resetOffset(JNIEnv *env, jobject obj) {
   374  	mem *m = mem_get(env, obj);
   375  	if (m == NULL) {
   376  		LOG_FATAL("resetOffset on NULL mem");
   377  	}
   378  	m->off = 0;
   379  }
   380  
   381  JNIEXPORT void JNICALL
   382  Java_go_Seq_log(JNIEnv *env, jobject obj, jstring v) {
   383  	mem *m = mem_get(env, obj);
   384  	const char *label = (*env)->GetStringUTFChars(env, v, NULL);
   385  	if (label == NULL) {
   386  		LOG_FATAL("log GetStringUTFChars failed");
   387  	}
   388  	if (m == NULL) {
   389  		LOG_INFO("%s: mem=NULL", label);
   390  	} else {
   391  		LOG_INFO("%s: mem{off=%d, len=%d, cap=%d}", label, m->off, m->len, m->cap);
   392  	}
   393  	(*env)->ReleaseStringUTFChars(env, v, label);
   394  }
   395  
   396  JNIEXPORT void JNICALL
   397  Java_go_Seq_destroyRef(JNIEnv *env, jclass clazz, jint refnum) {
   398  	DestroyRef(refnum);
   399  }
   400  
   401  JNIEXPORT void JNICALL
   402  Java_go_Seq_send(JNIEnv *env, jclass clazz, jstring descriptor, jint code, jobject src_obj, jobject dst_obj) {
   403  	mem *src = mem_get(env, src_obj);
   404  	if (src == NULL) {
   405  		LOG_FATAL("send src is NULL");
   406  	}
   407  	mem *dst = mem_get(env, dst_obj);
   408  	if (dst == NULL) {
   409  		LOG_FATAL("send dst is NULL");
   410  	}
   411  
   412  	GoString desc;
   413  	desc.p = (char*)(*env)->GetStringUTFChars(env, descriptor, NULL);
   414  	if (desc.p == NULL) {
   415  		LOG_FATAL("send GetStringUTFChars failed");
   416  	}
   417  	desc.n = (*env)->GetStringUTFLength(env, descriptor);
   418  	Send(desc, (GoInt)code, src->buf, src->len, &dst->buf, &dst->len);
   419  	(*env)->ReleaseStringUTFChars(env, descriptor, desc.p);
   420  	unpin_arrays(env, src);  // assume 'src' is no longer needed.
   421  }
   422  
   423  JNIEXPORT void JNICALL
   424  Java_go_Seq_recv(JNIEnv *env, jclass clazz, jobject in_obj, jobject receive) {
   425  	mem *in = mem_get(env, in_obj);
   426  	if (in == NULL) {
   427  		LOG_FATAL("recv in is NULL");
   428  	}
   429  	struct Recv_return ret = Recv(&in->buf, &in->len);
   430  	(*env)->SetIntField(env, receive, receive_refnum_id, ret.r0);
   431  	(*env)->SetIntField(env, receive, receive_code_id, ret.r1);
   432  	(*env)->SetIntField(env, receive, receive_handle_id, ret.r2);
   433  }
   434  
   435  JNIEXPORT void JNICALL
   436  Java_go_Seq_recvRes(JNIEnv *env, jclass clazz, jint handle, jobject out_obj) {
   437  	mem *out = mem_get(env, out_obj);
   438  	if (out == NULL) {
   439  		LOG_FATAL("recvRes out is NULL");
   440  	}
   441  	RecvRes((int32_t)handle, out->buf, out->len);
   442  }
   443  
   444  JNIEXPORT void JNICALL
   445  Java_go_Seq_setContext(JNIEnv* env, jclass clazz, jobject ctx) {
   446  	JavaVM* vm;
   447          if ((*env)->GetJavaVM(env, &vm) != 0) {
   448  		LOG_FATAL("failed to get JavaVM");
   449  	}
   450  	setContext(vm, (*env)->NewGlobalRef(env, ctx));
   451  }