diff --git a/bind/java/seq_android.c b/bind/java/seq_android.c index bd32c82..168f8f5 100644 --- a/bind/java/seq_android.c +++ b/bind/java/seq_android.c @@ -73,7 +73,15 @@ static mem *mem_get(JNIEnv *env, jobject obj) { return (mem*)(uintptr_t)(*env)->GetLongField(env, obj, memptr_id); } -static uint8_t *mem_read(JNIEnv *env, jobject obj, uint32_t size) { +static uint32_t align(uint32_t offset, uint32_t alignment) { + uint32_t pad = offset % alignment; + if (pad > 0) { + pad = alignment-pad; + } + return pad+offset; +} + +static uint8_t *mem_read(JNIEnv *env, jobject obj, uint32_t size, uint32_t alignment) { if (size == 0) { return NULL; } @@ -81,15 +89,17 @@ static uint8_t *mem_read(JNIEnv *env, jobject obj, uint32_t size) { if (m == NULL) { LOG_FATAL("mem_read on NULL mem"); } - if (m->len-m->off < size) { - LOG_FATAL("short read, size: %d", size); + uint32_t offset = align(m->off, alignment); + + if (m->len-offset < size) { + LOG_FATAL("short read"); } - uint8_t *res = m->buf+m->off; - m->off += size; + uint8_t *res = m->buf+offset; + m->off = offset+size; return res; } -uint8_t *mem_write(JNIEnv *env, jobject obj, uint32_t size) { +uint8_t *mem_write(JNIEnv *env, jobject obj, uint32_t size, uint32_t alignment) { mem *m = mem_get(env, obj); if (m == NULL) { LOG_FATAL("mem_write on NULL mem"); @@ -97,14 +107,15 @@ uint8_t *mem_write(JNIEnv *env, jobject obj, uint32_t size) { if (m->off != m->len) { LOG_FATAL("write can only append to seq, size: (off=%d, len=%d, size=%d", m->off, m->len, size); } + uint32_t offset = align(m->off, alignment); uint32_t cap = m->cap; - while (m->off+size > cap) { + while (offset+size > cap) { cap *= 2; } m = mem_ensure(m, cap); - uint8_t *res = m->buf+m->off; - m->off += size; - m->len += size; + uint8_t *res = m->buf+offset; + m->off = offset+size; + m->len = offset+size; return res; } @@ -219,7 +230,7 @@ Java_go_Seq_free(JNIEnv *env, jobject obj) { } } -#define MEM_READ(obj, ty) ((ty*)mem_read(env, obj, sizeof(ty))) +#define MEM_READ(obj, ty) ((ty*)mem_read(env, obj, sizeof(ty), sizeof(ty))) JNIEXPORT jbyte JNICALL Java_go_Seq_readInt8(JNIEnv *env, jobject obj) { @@ -266,7 +277,7 @@ Java_go_Seq_readUTF16(JNIEnv *env, jobject obj) { if (size == 0) { return NULL; } - return (*env)->NewString(env, (jchar*)mem_read(env, obj, 2*size), size); + return (*env)->NewString(env, (jchar*)mem_read(env, obj, 2*size, 1), size); } JNIEXPORT jbyteArray JNICALL @@ -283,7 +294,7 @@ Java_go_Seq_readByteArray(JNIEnv *env, jobject obj) { return res; } -#define MEM_WRITE(ty) (*(ty*)mem_write(env, obj, sizeof(ty))) +#define MEM_WRITE(ty) (*(ty*)mem_write(env, obj, sizeof(ty), sizeof(ty))) JNIEXPORT void JNICALL Java_go_Seq_writeInt8(JNIEnv *env, jobject obj, jbyte v) { @@ -323,7 +334,7 @@ Java_go_Seq_writeUTF16(JNIEnv *env, jobject obj, jstring v) { } int32_t size = (*env)->GetStringLength(env, v); MEM_WRITE(int32_t) = size; - (*env)->GetStringRegion(env, v, 0, size, (jchar*)mem_write(env, obj, 2*size)); + (*env)->GetStringRegion(env, v, 0, size, (jchar*)mem_write(env, obj, 2*size, 1)); } JNIEXPORT void JNICALL diff --git a/bind/seq/buffer.go b/bind/seq/buffer.go index 6fb9441..462ed77 100644 --- a/bind/seq/buffer.go +++ b/bind/seq/buffer.go @@ -51,43 +51,58 @@ func (b *Buffer) grow(need int) { b.Data = data } +// align returns the aligned offset. +func align(offset, alignment int) int { + pad := offset % alignment + if pad > 0 { + pad = alignment - pad + } + return pad + offset +} + func (b *Buffer) ReadInt32() int32 { - if len(b.Data)-b.Offset < 4 { + offset := align(b.Offset, 4) + if len(b.Data)-offset < 4 { b.panic(4) } - v := *(*int32)(unsafe.Pointer(&b.Data[b.Offset])) - b.Offset += 4 + v := *(*int32)(unsafe.Pointer(&b.Data[offset])) + b.Offset = offset + 4 return v } func (b *Buffer) ReadInt64() int64 { - if len(b.Data)-b.Offset < 8 { + offset := align(b.Offset, 8) + if len(b.Data)-offset < 8 { b.panic(8) } - v := *(*int64)(unsafe.Pointer(&b.Data[b.Offset])) - b.Offset += 8 + v := *(*int64)(unsafe.Pointer(&b.Data[offset])) + b.Offset = offset + 8 return v } +// TODO(hyangah): int8, int16? + func (b *Buffer) ReadInt() int { return int(b.ReadInt64()) } func (b *Buffer) ReadFloat32() float32 { - if len(b.Data)-b.Offset < 4 { + offset := align(b.Offset, 4) + if len(b.Data)-offset < 4 { b.panic(4) } - v := *(*float32)(unsafe.Pointer(&b.Data[b.Offset])) - b.Offset += 4 + v := *(*float32)(unsafe.Pointer(&b.Data[offset])) + b.Offset = offset + 4 return v } func (b *Buffer) ReadFloat64() float64 { - if len(b.Data)-b.Offset < 8 { + offset := align(b.Offset, 8) + if len(b.Data)-offset < 8 { b.panic(8) } - v := *(*float64)(unsafe.Pointer(&b.Data[b.Offset])) - b.Offset += 8 + v := *(*float64)(unsafe.Pointer(&b.Data[offset])) + b.Offset = offset + 8 return v } @@ -118,19 +133,21 @@ func (b *Buffer) ReadRef() *Ref { } func (b *Buffer) WriteInt32(v int32) { - if len(b.Data)-b.Offset < 4 { - b.grow(4) + offset := align(b.Offset, 4) + if len(b.Data)-offset < 4 { + b.grow(offset + 4 - len(b.Data)) } - *(*int32)(unsafe.Pointer(&b.Data[b.Offset])) = v - b.Offset += 4 + *(*int32)(unsafe.Pointer(&b.Data[offset])) = v + b.Offset = offset + 4 } func (b *Buffer) WriteInt64(v int64) { - if len(b.Data)-b.Offset < 8 { - b.grow(8) + offset := align(b.Offset, 8) + if len(b.Data)-offset < 8 { + b.grow(offset + 8 - len(b.Data)) } - *(*int64)(unsafe.Pointer(&b.Data[b.Offset])) = v - b.Offset += 8 + *(*int64)(unsafe.Pointer(&b.Data[offset])) = v + b.Offset = offset + 8 } func (b *Buffer) WriteInt(v int) { @@ -138,19 +155,21 @@ func (b *Buffer) WriteInt(v int) { } func (b *Buffer) WriteFloat32(v float32) { - if len(b.Data)-b.Offset < 4 { - b.grow(4) + offset := align(b.Offset, 4) + if len(b.Data)-offset < 4 { + b.grow(offset + 4 - len(b.Data)) } - *(*float32)(unsafe.Pointer(&b.Data[b.Offset])) = v - b.Offset += 4 + *(*float32)(unsafe.Pointer(&b.Data[offset])) = v + b.Offset = offset + 4 } func (b *Buffer) WriteFloat64(v float64) { - if len(b.Data)-b.Offset < 8 { - b.grow(8) + offset := align(b.Offset, 8) + if len(b.Data)-offset < 8 { + b.grow(offset + 8 - len(b.Data)) } - *(*float64)(unsafe.Pointer(&b.Data[b.Offset])) = v - b.Offset += 8 + *(*float64)(unsafe.Pointer(&b.Data[offset])) = v + b.Offset = offset + 8 } func (b *Buffer) WriteByteArray(byt []byte) { diff --git a/bind/seq/utf16.go b/bind/seq/utf16.go index 3e5a9b3..8b0698d 100644 --- a/bind/seq/utf16.go +++ b/bind/seq/utf16.go @@ -34,12 +34,17 @@ func writeUint16(b []byte, v rune) { } func (b *Buffer) WriteUTF16(s string) { - // first 4 bytes is the length, as int32. written last. - // next n bytes is utf-16 string. - if len(b.Data)-b.Offset < 4+4*len(s) { - b.grow(4 + 4*len(s)) // worst case estimate, everything is surrogate pair + // The first 4 bytes is the length, as int32 (4-byte aligned). + // written last. + // The next n bytes is utf-16 string (1-byte aligned). + offset0 := align(b.Offset, 4) // length. + offset1 := align(offset0+4, 1) // contents. + + if len(b.Data)-offset1 < 4*len(s) { + // worst case estimate, everything is surrogate pair + b.grow(offset1 + 4*len(s) - len(b.Data)) } - data := b.Data[b.Offset+4:] + data := b.Data[offset1:] n := 0 for _, v := range s { switch { @@ -62,7 +67,7 @@ func (b *Buffer) WriteUTF16(s string) { // length is number of uint16 values, not number of bytes. b.WriteInt32(int32(n / 2)) - b.Offset += n + b.Offset = offset1 + n } const maxSliceLen = (1<<31 - 1) / 2 @@ -82,9 +87,10 @@ func (b *Buffer) ReadUTF16() string { if size < 0 { panic(fmt.Sprintf("string size negative: %d", size)) } - u := (*[maxSliceLen]uint16)(unsafe.Pointer(&b.Data[b.Offset]))[:size] + offset := align(b.Offset, 1) + u := (*[maxSliceLen]uint16)(unsafe.Pointer(&b.Data[offset]))[:size] s := string(utf16.Decode(u)) // TODO: save the []rune alloc - b.Offset += 2 * size + b.Offset = offset + 2*size return s }