Package jnr.ffi.provider.jffi

Source Code of jnr.ffi.provider.jffi.AbstractX86StubCompiler$PageHolder

/*
* Copyright (C) 2008-2010 Wayne Meissner
*
* This file is part of the JNR project.
*
* 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 jnr.ffi.provider.jffi;

import com.kenai.jffi.MemoryIO;
import com.kenai.jffi.NativeMethod;
import com.kenai.jffi.NativeMethods;
import com.kenai.jffi.PageManager;
import jnr.ffi.Platform;
import jnr.x86asm.Assembler;

import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Base class for most X86_32/X86_64 stub compilers
*/
abstract class AbstractX86StubCompiler extends StubCompiler {
    public final static boolean DEBUG = Boolean.getBoolean("jnr.ffi.compile.dump");

    private static final class StaticDataHolder {
        // Keep a reference from the loaded class to the pages holding the code for that class.
        static final Map<Class, PageHolder> PAGES
                = Collections.synchronizedMap(new WeakHashMap<Class, PageHolder>());
    }
    final List<Stub> stubs = new LinkedList<Stub>();


    static final class Stub {
        final String name;
        final String signature;
        final Assembler assembler;

        public Stub(String name, String signature, Assembler assembler) {
            this.name = name;
            this.signature = signature;
            this.assembler = assembler;
        }
    }

    static final class PageHolder {
        final PageManager pm;
        final long memory;
        final long pageCount;

        public PageHolder(PageManager pm, long memory, long pageCount) {
            this.pm = pm;
            this.memory = memory;
            this.pageCount = pageCount;
        }

        @Override
        protected void finalize() throws Throwable {
            try {
                pm.freePages(memory, (int) pageCount);
            } catch (Throwable t) {
                Logger.getLogger(getClass().getName()).log(Level.WARNING,
                    "Exception when freeing native pages: %s", t.getLocalizedMessage());
            } finally {
                super.finalize();
            }
        }

    }

    @Override
    void attach(Class clazz) {

        if (stubs.isEmpty()) {
            return;
        }

        long codeSize = 0;
        for (Stub stub : stubs) {
            // add 8 bytes for alignment
            codeSize += stub.assembler.codeSize() + 8;
        }

        PageManager pm = PageManager.getInstance();

        long npages = (codeSize + pm.pageSize() - 1) / pm.pageSize();
        // Allocate some native memory for it
        long code = pm.allocatePages((int) npages, PageManager.PROT_READ | PageManager.PROT_WRITE);
        if (code == 0) {
            throw new OutOfMemoryError("allocatePages failed for codeSize=" + codeSize);
        }
        PageHolder page = new PageHolder(pm, code, npages);

        // Now relocate/copy all the assembler stubs into the real code area
        List<NativeMethod> methods = new ArrayList<NativeMethod>(stubs.size());
        long fn = code;
        PrintStream dbg = System.err;
        System.out.flush(); System.err.flush();

        for (Stub stub : stubs) {
            Assembler asm = stub.assembler;
            // align the start of all functions on a 8 byte boundary
            fn = align(fn, 8);
            ByteBuffer buf = ByteBuffer.allocate(asm.codeSize()).order(ByteOrder.LITTLE_ENDIAN);
            stub.assembler.relocCode(buf, fn);
            buf.flip();
            MemoryIO.getInstance().putByteArray(fn, buf.array(), buf.arrayOffset(), buf.limit());

            if (DEBUG && X86Disassembler.isAvailable()) {

                dbg.println(clazz.getName() + "." + stub.name + " " + stub.signature);
                X86Disassembler disassembler = X86Disassembler.create();
                disassembler.setMode(Platform.getNativePlatform().getCPU() == Platform.CPU.I386
                        ? X86Disassembler.Mode.I386 : X86Disassembler.Mode.X86_64);
                disassembler.setSyntax(X86Disassembler.Syntax.INTEL);
                disassembler.setInputBuffer(MemoryUtil.newPointer(fn), asm.offset());
                while (disassembler.disassemble()) {
                    dbg.printf("%8x: %s\n", disassembler.offset(), disassembler.insn());
                }
                if (buf.remaining() > asm.offset()) {
                    // libudis86 for some reason cannot understand the code asmjit emits for the trampolines
                    dbg.printf("%8x: <indirect call trampolines>\n", asm.offset());
                }
                dbg.println();
            }
            methods.add(new NativeMethod(fn, stub.name, stub.signature));

            fn += asm.codeSize();
        }

        pm.protectPages(code, (int) npages, PageManager.PROT_READ | PageManager.PROT_EXEC);

        NativeMethods.register(clazz, methods);
        StaticDataHolder.PAGES.put(clazz, page);
    }

    static final int align(int offset, int align) {
        return (offset + align - 1) & ~(align - 1);
    }

    static final long align(long offset, long align) {
        return (offset + align - 1) & ~(align - 1);
    }
}
TOP

Related Classes of jnr.ffi.provider.jffi.AbstractX86StubCompiler$PageHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.