package org.jruby.ext.ffi.jffi;
import com.kenai.jffi.CallingConvention;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import org.jruby.RubyInstanceConfig;
import org.jruby.ext.ffi.CallbackInfo;
import org.jruby.ext.ffi.MappedType;
import org.jruby.ext.ffi.NativeType;
import org.jruby.ext.ffi.Type;
import org.jruby.util.WeakIdentityHashMap;
import org.jruby.util.cli.Options;
class JITCompiler {
private final Map<JITSignature, HandleRef>
handles = new HashMap<JITSignature, HandleRef>();
private final Map<Class<? extends NativeInvoker>, JITHandle>
classes = new WeakHashMap();
private final ReferenceQueue referenceQueue = new ReferenceQueue();
private final JITHandle failedHandle = new JITHandle(this,
new JITSignature(NativeType.VOID, new NativeType[0], false, new boolean[0], CallingConvention.DEFAULT, false),
true);
private static class SingletonHolder {
private static final JITCompiler INSTANCE = new JITCompiler();
}
public static JITCompiler getInstance() {
return SingletonHolder.INSTANCE;
}
private static final class HandleRef extends WeakReference<JITHandle> {
JITSignature signature;
public HandleRef(JITHandle handle, JITSignature signature, ReferenceQueue refqueue) {
super(handle, refqueue);
this.signature = signature;
}
}
private void cleanup() {
HandleRef ref;
while ((ref = (HandleRef) referenceQueue.poll()) != null) {
handles.remove(ref.signature);
}
}
JITHandle getHandle(Signature signature, boolean unique) {
boolean hasResultConverter = !(signature.getResultType() instanceof Type.Builtin);
NativeType nativeResultType;
Type resultType = signature.getResultType();
if (resultType instanceof Type.Builtin || resultType instanceof CallbackInfo) {
nativeResultType = resultType.getNativeType();
} else if (resultType instanceof MappedType) {
nativeResultType = ((MappedType) resultType).getRealType().getNativeType();
} else {
return failedHandle;
}
NativeType[] nativeParameterTypes = new NativeType[signature.getParameterCount()];
boolean[] hasParameterConverter = new boolean[signature.getParameterCount()];
for (int i = 0; i < hasParameterConverter.length; i++) {
Type parameterType = signature.getParameterType(i);
if (parameterType instanceof Type.Builtin || parameterType instanceof CallbackInfo) {
nativeParameterTypes[i] = parameterType.getNativeType();
} else if (parameterType instanceof MappedType) {
nativeParameterTypes[i] = ((MappedType) parameterType).getRealType().getNativeType();
} else {
return failedHandle;
}
setParameterConverterWithTypeAndSignature(signature, hasParameterConverter, i, parameterType);
}
JITSignature jitSignature = new JITSignature(nativeResultType, nativeParameterTypes,
hasResultConverter, hasParameterConverter, signature.getCallingConvention(), signature.isIgnoreError());
if (unique) {
return new JITHandle(this, jitSignature, Options.COMPILE_MODE.load() == RubyInstanceConfig.CompileMode.OFF);
}
synchronized (this) {
cleanup();
HandleRef ref = handles.get(jitSignature);
JITHandle handle = ref != null ? ref.get() : null;
if (handle == null) {
handle = new JITHandle(this, jitSignature, Options.COMPILE_MODE.load() == RubyInstanceConfig.CompileMode.OFF);
handles.put(jitSignature, new HandleRef(handle, jitSignature, referenceQueue));
}
return handle;
}
}
@SuppressWarnings("deprecation")
private void setParameterConverterWithTypeAndSignature(Signature signature, boolean[] hasParameterConverter, int i, Type parameterType) {
hasParameterConverter[i] = !(parameterType instanceof Type.Builtin)
|| DataConverters.isEnumConversionRequired(parameterType, signature.getEnums());
}
void registerClass(JITHandle handle, Class<? extends NativeInvoker> klass) {
classes.put(klass, handle);
}
}