/** * Copyright 2013, Landz and its contributors. All rights reserved. * * 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 z.znr.invoke.linux.x64; import com.kenai.jffi.Platform; import jdk.internal.org.objectweb.asm.ClassVisitor; import jdk.internal.org.objectweb.asm.ClassWriter; import z.znr.InlineAssembler; import z.znr.invoke.types.*; import java.io.OutputStreamWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.Collection; import static jdk.internal.org.objectweb.asm.Opcodes.*; import static z.znr.invoke.linux.x64.AsmUtil.emitDefaultConstructor; import static z.znr.invoke.linux.x64.AsmUtil.emitStaticFieldInitialization; import static z.znr.invoke.linux.x64.CodegenUtils.*; import static z.znr.invoke.linux.x64.Native.STUB_NAME; import static z.znr.invoke.linux.x64.Native.nextClassID; final class PrimitiveX86MethodHandleGenerator implements MethodHandleGenerator { private static final boolean ENABLED = Util.getBooleanProperty("jnr.invoke.x86asm.enabled", true); private static final String PAGE_HOLDER_FIELD = "pageHolder"; private final StubCompiler compiler = StubCompiler.newCompiler(); public boolean isSupported(ResultType resultType, Collection<ParameterType> parameterTypes) { if (!ENABLED) { return false; } final Platform platform = Platform.getPlatform(); if (platform.getOS().equals(Platform.OS.WINDOWS)) { return false; } if (!platform.getCPU().equals(Platform.CPU.I386) && !platform.getCPU().equals(Platform.CPU.X86_64)) { return false; } for (ParameterType parameterType : parameterTypes) { if (!isSupportedParameter(parameterType)) { return false; } } return isSupportedResult(resultType) && compiler.canCompile(resultType, parameterTypes.toArray(new ParameterType[parameterTypes.size()])); } @Override public MethodHandle createBoundHandle(Signature signature, InlineAssembler inlineAssembler) { AsmClassLoader classLoader = new AsmClassLoader(Native.class.getClassLoader()); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); ClassVisitor cv = Native.DEBUG ? AsmUtil.newCheckClassAdapter(cw) : cw; AsmBuilder builder = new AsmBuilder(p(Native.class) + "$x86asm$" + nextClassID.getAndIncrement(), cv, classLoader); ResultType resultType = signature.getResultType().asPrimitiveType(); cv.visit(V1_7, ACC_PUBLIC | ACC_FINAL, builder.getClassNamePath(), null, p(Object.class), new String[0]); compile(signature, builder, inlineAssembler, STUB_NAME, resultType, signature.parameterTypeArray()); // Stash a strong ref to the library, so it doesn't get garbage collected. builder.getObjectField(Util.inlineAssemblerToCodeAddress(inlineAssembler).address()); emitDefaultConstructor(cv); emitStaticFieldInitialization(builder, cv); cv.visitField(ACC_PUBLIC | ACC_STATIC | ACC_VOLATILE, PAGE_HOLDER_FIELD, ci(Object.class), null, null); cv.visitEnd(); try { Class implClass = classLoader.defineClass(builder.getClassNamePath().replace("/", "."), cw.toByteArray(), Native.DEBUG ? new OutputStreamWriter(System.err) : null); // Attach any native method stubs, and store a strong ref to the compiled page in a class var implClass.getField("pageHolder").set(implClass, compiler.attach(implClass)); return MethodHandles.lookup().findStatic(implClass, STUB_NAME, signature.methodType()); } catch (Throwable ex) { throw new RuntimeException(ex); } } private void compile(Signature signature, AsmBuilder builder, InlineAssembler inlineAssembler, String stubName, ResultType resultType, ParameterType[] parameterTypes) { Class[] nativeParameterTypes = Util.javaTypeArray(parameterTypes); Class nativeReturnType = resultType.javaType(); builder.getClassVisitor().visitMethod(ACC_PUBLIC | ACC_FINAL | ACC_NATIVE | ACC_STATIC, stubName, sig(nativeReturnType, nativeParameterTypes), null, null).visitEnd(); compiler.compile(inlineAssembler, stubName, resultType, parameterTypes, nativeReturnType, nativeParameterTypes, signature.saveErrno()); } private static boolean isSupportedType(SignatureType type) { switch (type.nativeType()) { case SCHAR: case UCHAR: case SSHORT: case USHORT: case SINT: case UINT: case SLONG: case ULONG: case SLONG_LONG: case ULONG_LONG: case POINTER: case FLOAT: case DOUBLE: return type.javaType().isPrimitive(); default: return false; } } static boolean isSupportedResult(ResultType resultType) { return isSupportedType(resultType) || (resultType.nativeType() == NativeType.VOID && void.class == resultType.javaType()) ; } static boolean isSupportedParameter(ParameterType parameterType) { return isSupportedType(parameterType) ; } }