org.nustaq.offheap.structs.unsafeimpl.FSTByteArrayUnsafeStructGeneration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fst Show documentation
Show all versions of fst Show documentation
A fast java serialization drop in-replacement and some serialization based utils such as Structs and OffHeap Memory.
/*
* Copyright 2014 Ruediger Moeller.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nustaq.offheap.structs.unsafeimpl;
import org.nustaq.offheap.structs.FSTStruct;
import org.nustaq.serialization.FSTClazzInfo;
import javassist.*;
import javassist.expr.FieldAccess;
/**
* Date: 22.06.13
* Time: 20:54
* To change this template use File | Settings | File Templates.
*/
public class FSTByteArrayUnsafeStructGeneration implements FSTStructGeneration {
public static boolean trackChanges = false;
@Override
public FSTStructGeneration newInstance() {
return new FSTByteArrayUnsafeStructGeneration();
}
@Override
public void defineStructWriteAccess(FieldAccess f, CtClass type, FSTClazzInfo.FSTFieldInfo fieldInfo) {
int off = fieldInfo.getStructOffset();
try {
boolean vola = fieldInfo.isVolatile();
validateAnnotations(fieldInfo,vola);
String insert = "";
if ( vola ) {
insert = "Volatile";
}
String fieldName = "\""+fieldInfo.getName()+"\"";
if ( type == CtPrimitiveType.booleanType ) {
final String body = "___bytes.putBool" + insert + "((long)" + off + "+___offset, $1 );";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,1,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
if ( type == CtPrimitiveType.byteType ) {
final String body = "___bytes.put"+insert+"("+off+"+___offset,$1);";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,1,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
if ( type == CtPrimitiveType.charType ) {
final String body = "___bytes.putChar"+insert+"("+off+"+___offset,$1);";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,2,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
if ( type == CtPrimitiveType.shortType ) {
final String body = "___bytes.putShort"+insert+"("+off+"+___offset,$1);";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,2,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
if ( type == CtPrimitiveType.intType ) {
final String body = "___bytes.putInt"+insert+"("+off+"+___offset,$1);";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,4,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
if ( type == CtPrimitiveType.longType ) {
final String body = "___bytes.putLong"+insert+"("+off+"+___offset,$1);";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,8,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
if ( type == CtPrimitiveType.floatType ) {
final String body = "___bytes.putFloat"+insert+"("+off+"+___offset,$1);";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,4,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
if ( type == CtPrimitiveType.doubleType ) {
final String body = "___bytes.putDouble"+insert+"("+off+"+___offset,$1);";
if (trackChanges) {
f.replace("{" +
body +
"if (tracker!=null) tracker.addChange("+off+"+___offset,8,"+ fieldName +");" +
"}");
} else {
f.replace(body);
}
} else
{
String code =
"{"+
"long tmpOff = ___offset + ___bytes.getInt("+off+" + ___offset);"+
"if ( $1 == null ) { " +
"___bytes.putInt(tmpOff+4,-1); " +
"return; " +
"}"+
"int obj_len=___bytes.getInt(tmpOff); "+
"org.nustaq.offheap.structs.FSTStruct struct = (org.nustaq.offheap.structs.FSTStruct)$1;"+
"if ( !struct.isOffHeap() ) {"+
" struct=___fac.toStruct(struct);"+ // FIMXE: do direct toByte to avoid tmp alloc
"}"+
"if (struct.getByteSize() > obj_len ) throw new RuntimeException(\"object too large to be written\");"+
(trackChanges ? "if (tracker!=null) tracker.addChange(tmpOff,struct.getByteSize(),"+ fieldName +"); ":"") +
// "unsafe.copyMemory(struct.___bytes,struct.___offset,___bytes,tmpOff,(long)struct.getByteSize());"+
"struct.___bytes.copyTo(___bytes,tmpOff,struct.___offset,(long)struct.getByteSize());"+
"___bytes.putInt(tmpOff, obj_len);"+ // rewrite original size
"}";
f.replace(code);
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
void validateAnnotations(FSTClazzInfo.FSTFieldInfo fieldInfo, boolean vola) {
if ( vola ) {
if ( ! fieldInfo.isIntegral() )
throw new RuntimeException("volatile only applicable to primitive types");
}
}
@Override
public void defineArrayAccessor(FSTClazzInfo.FSTFieldInfo fieldInfo, FSTClazzInfo clInfo, CtMethod method) {
boolean vola = fieldInfo.isVolatile();
validateAnnotations(fieldInfo,vola);
String insert = "";
if ( vola ) {
insert = "Volatile";
}
try {
Class arrayType = fieldInfo.getArrayType();
int off = fieldInfo.getStructOffset();
String prefix ="{ long _st_off=___offset + ___bytes.getInt("+off+"+___offset);"+ // array base offset in byte arr
"int _st_len=___bytes.getInt("+off+"+4+___offset); "+
"if ($1>=_st_len||$1<0) throw new ArrayIndexOutOfBoundsException(\"index:\"+$1+\" len:\"+_st_len);";
if ( method.getReturnType() == CtClass.voidType ) {
String record = "";
String fieldName = "\""+fieldInfo.getName()+"\"";
if ( arrayType == boolean.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange(_st_off+$1,1,"+ fieldName +");";
}
method.setBody(prefix+"___bytes.putBool"+insert+"( _st_off+$1,$2);"+record+"}");
} else
if ( arrayType == byte.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange((long)_st_off+$1,1,"+ fieldName +");";
}
method.setBody(prefix+"___bytes.put"+insert+"( _st_off+$1,$2);"+record+"}");
} else
if ( arrayType == char.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange(_st_off+$1*2,2,"+ fieldName +");";
}
method.setBody(prefix+"___bytes.putChar"+insert+"( _st_off+$1*2,$2);"+record+"}");
} else
if ( arrayType == short.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange(_st_off+$1*2,2,"+ fieldName +");";
}
method.setBody(prefix+" ___bytes.putShort"+insert+"( _st_off+$1*2,$2);"+record+"}");
} else
if ( arrayType == int.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange(_st_off+$1*4,4,"+ fieldName +");";
}
method.setBody(prefix+" ___bytes.putInt"+insert+"(_st_off+$1*4,$2);"+record+"}");
} else
if ( arrayType == long.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange(_st_off+$1*8,8,"+ fieldName +");";
}
method.setBody(prefix+"___bytes.putLong"+insert+"( _st_off+$1*8,$2);"+record+"}");
} else
if ( arrayType == double.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange(_st_off+$1*8,8,"+ fieldName +");";
}
method.setBody(prefix+"___bytes.putDouble"+insert+"( _st_off+$1*8,$2);"+record+"}");
} else
if ( arrayType == float.class ) {
if (trackChanges) {
record = "if (tracker!=null) tracker.addChange(_st_off+$1*4,4,"+ fieldName +");";
}
method.setBody(prefix+"___bytes.putFloat"+insert+"(_st_off+$1*4,$2);"+record+"}");
} else {
String structCL = FSTStruct.class.getName();
method.setBody(
prefix+
"int _elem_len=___bytes.getInt("+off+"+8+___offset); "+
structCL+" struct = ("+structCL+")$2;"+
"if ( struct == null ) { " +
"___bytes.putInt((long)_st_off+$1*_elem_len+4,-1); " +
"return; " +
"}"+
"if ( !struct.isOffHeap() ) {"+
" struct=___fac.toStruct(struct);"+ // FIMXE: do direct toByte to avoid tmp alloc
"}"+
"if ( _elem_len < struct.getByteSize() )"+
" throw new RuntimeException(\"Illegal size when rewriting object array value. elem size:\"+_elem_len+\" new object size:\"+struct.getByteSize()+\"\");"+
(trackChanges ? "if (tracker!=null) tracker.addChange(_st_off+$1*_elem_len, struct.getByteSize(),"+ fieldName +"); ":"") +
// "unsafe.copyMemory(struct.___bytes,struct.___offset,___bytes,(long)_st_off+$1*_elem_len,(long)struct.getByteSize());"+
"struct.___bytes.copyTo(___bytes,(long)_st_off+$1*_elem_len,struct.___offset,(long)struct.getByteSize());"+
"}"
);
}
} else { // read access
if ( arrayType == boolean.class ) {
String src = prefix + "return ___bytes.getBool" + insert + "( (long)_st_off+$1); }";
method.setBody(src);
} else
if ( arrayType == byte.class ) {
method.setBody(prefix+"return ___bytes.get"+insert+"( (long)_st_off+$1);}");
} else
if ( arrayType == char.class ) {
method.setBody(prefix+"return ___bytes.getChar"+insert+"( (long)_st_off+$1*2); }");
} else
if ( arrayType == short.class ) {
method.setBody(prefix+"return ___bytes.getShort"+insert+"( (long)_st_off+$1*2);}");
} else
if ( arrayType == int.class ) {
method.setBody(prefix+"return ___bytes.getInt"+insert+"( (long)_st_off+$1*4);}");
} else
if ( arrayType == long.class ) {
method.setBody(prefix+"return ___bytes.getLong"+insert+"( (long)_st_off+$1*8);}");
} else
if ( arrayType == double.class ) {
method.setBody(prefix+"return ___bytes.getDouble"+insert+"( (long)_st_off+$1*8);}");
} else
if ( arrayType == float.class ) {
method.setBody(prefix+"return ___bytes.getFloat"+insert+"( (long)_st_off+$1*4);}");
} else { // object array
String meth =
prefix+
"int _elem_len=___bytes.getInt("+off+"+8+___offset); "+
"return ("+fieldInfo.getArrayType().getName()+")___fac.getStructPointerByOffset(___bytes,(long)_st_off+$1*_elem_len);"+
"}";
method.setBody(meth);
}
}
} catch (Exception ex) {
throw new RuntimeException("in field "+fieldInfo.getField(),ex);
}
}
public void defineStructSetCAS(FSTClazzInfo.FSTFieldInfo casAcc, FSTClazzInfo clInfo, CtMethod method) {
int off = casAcc.getStructOffset();
try {
if ( method.getParameterTypes().length != 2 ) {
throw new RuntimeException("CAS setter requires expected and newValue args");
}
} catch (NotFoundException e) {
e.printStackTrace();
}
try {
if ( casAcc.getType() == int.class ) {
method.setBody("return ___bytes.compareAndSwapInt("+off+"+___offset,$1,$2);");
} else
if ( casAcc.getType() == int.class ) {
method.setBody("return ___bytes.compareAndSwapLong("+off+"+___offset,$1,$2);");
} else {
throw new RuntimeException("CAS access only applicable to int and long.");
}
} catch (CannotCompileException e) {
throw new RuntimeException(e);
}
}
@Override
public void defineArrayElementSize(FSTClazzInfo.FSTFieldInfo indexfi, FSTClazzInfo clInfo, CtMethod method) {
int off = indexfi.getStructOffset();
try {
method.setBody("{ return ___bytes.getInt("+off+"+8+___offset); }");
} catch (CannotCompileException e) {
throw new RuntimeException(e);
}
}
@Override
public void defineArrayIndex(FSTClazzInfo.FSTFieldInfo fieldInfo, FSTClazzInfo clInfo, CtMethod method) {
int index = fieldInfo.getStructOffset();
try {
method.setBody("{ return (int) (___bytes.getInt( ___offset+"+index+")+___offset); }");
} catch (CannotCompileException e) {
throw new RuntimeException(e);
}
}
@Override
public void defineArrayPointer(FSTClazzInfo.FSTFieldInfo indexfi, FSTClazzInfo clInfo, CtMethod method) {
int index = indexfi.getStructOffset();
CtClass[] parameterTypes = new CtClass[0];
try {
parameterTypes = method.getParameterTypes();
} catch (NotFoundException e) {
e.printStackTrace();
}
if ( parameterTypes != null && parameterTypes.length ==1 ) {
try {
if (indexfi.isIntegral()) {
method.setBody("{ ___fac.fillPrimitiveArrayBasePointer($1,___bytes, ___offset, "+index+"); }");
} else {
method.setBody("{ ___fac.fillTypedArrayBasePointer($1,___bytes, ___offset, "+index+"); }");
}
} catch (CannotCompileException e) {
throw new RuntimeException(e);
}
} else {
try {
if (indexfi.isIntegral()) {
method.setBody("{ return (org.nustaq.offheap.structs.FSTStruct)___fac.createPrimitiveArrayBasePointer(___bytes, ___offset, "+index+"); }");
} else
method.setBody("{ return ("+indexfi.getArrayType().getName()+")___fac.createTypedArrayBasePointer(___bytes, ___offset, "+index+"); }");
} catch (CannotCompileException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void defineArrayLength(FSTClazzInfo.FSTFieldInfo fieldInfo, FSTClazzInfo clInfo, CtMethod method) {
int off = fieldInfo.getStructOffset();
try {
method.setBody("{ return ___bytes.getInt("+off+"+4+___offset); }");
} catch (CannotCompileException e) {
throw new RuntimeException(e);
}
}
@Override
public void defineFieldStructIndex(FSTClazzInfo.FSTFieldInfo fieldInfo, FSTClazzInfo clInfo, CtMethod method) {
int off = fieldInfo.getStructOffset();
try {
method.setBody("{ return "+off+"; }");
} catch (CannotCompileException e) {
throw new RuntimeException(e);
}
}
@Override
public void defineStructReadAccess(FieldAccess f, CtClass type, FSTClazzInfo.FSTFieldInfo fieldInfo) {
boolean vola = fieldInfo.isVolatile();
validateAnnotations(fieldInfo,vola);
String insert = "";
String statement = "";
if ( vola ) {
insert = "Volatile";
}
int off = fieldInfo.getStructOffset();
try {
if ( type == CtPrimitiveType.booleanType ) {
f.replace("$_ = ___bytes.getBool"+insert+"("+off+"+___offset);");
} else
if ( type == CtPrimitiveType.byteType ) {
f.replace("$_ = ___bytes.get"+insert+"("+off+"+___offset);");
} else
if ( type == CtPrimitiveType.charType ) {
f.replace("$_ = ___bytes.getChar"+insert+"("+off+"+___offset);");
} else
if ( type == CtPrimitiveType.shortType ) {
f.replace("$_ = ___bytes.getShort"+insert+"("+off+"+___offset);");
} else
if ( type == CtPrimitiveType.intType ) {
f.replace("$_ = ___bytes.getInt"+insert+"("+off+"+___offset);");
} else
if ( type == CtPrimitiveType.longType ) {
f.replace("$_ = ___bytes.getLong"+insert+"("+off+"+___offset);");
} else
if ( type == CtPrimitiveType.floatType ) {
f.replace("$_ = ___bytes.getFloat"+insert+"("+off+"+___offset);");
} else
if ( type == CtPrimitiveType.doubleType ) {
f.replace("$_ = ___bytes.getDouble"+insert+"("+off+"+___offset);");
} else { // object ref or obje array
String typeString = type.getName();
if ( type.isArray() ) {
throw new RuntimeException("invalid direct access to array in struct code. Use arrayaccessor name convention as documented."+fieldInfo);
}
if ( ! FSTStruct.class.isAssignableFrom(Class.forName( typeString) ) ) {
throw new RuntimeException("invalid type, require at least FSTStruct "+fieldInfo);
}
statement = "{ int tmpIdx = ___bytes.getInt( " + off + " + ___offset); if (tmpIdx < 0) return null;" +
"long __tmpOff = ___offset + tmpIdx; " +
"" + typeString + " tmp = (" + typeString + ")___fac.getStructPointerByOffset(___bytes,__tmpOff); " +
"if ( tmp == null ) return null;" +
(trackChanges ? "tmp.tracker = new org.nustaq.offheap.structs.FSTStructChange(tracker,\"" + fieldInfo.getName() + "\"); " : "")+
"$_ = tmp; " +
"}";
f.replace(statement);
// f.replace("{ Object _o = unsafe.toString(); $_ = _o; }");
}
} catch (Exception ex) {
throw new RuntimeException(""+fieldInfo+" "+statement,ex);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy