view dwt/internal/c/callback.d @ 13:f565d3a95c0a

Ported dwt.internal
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Fri, 22 Aug 2008 16:46:34 +0200
parents a329f9c3d66d
children 2952d5604c0a
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2000, 2007 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     
 * Port to the D programming language:
 *     Jacob Carlborg <jacob.carlborg@gmail.com>
 *******************************************************************************/
module dwt.internal.c.callback;

/**
 * Callback implementation.
 */

import tango.stdc.string;

import dwt.dwthelper.utils;
import dwt.internal.Callback;

/* Header */

const bool REDUCED_CALLBACKS = false;
alias size_t SWT_PTR;

version (Win32)
{
    import tango.sys.win32.UserGdi;
    import tango.sys.win32.Types;
    
    alias LRESULT RETURN_TYPE;
}

else version (Win32_WCE)
{
    import tango.sys.win32.UserGdi;
    import tango.sys.win32.Types;
    
    alias LRESULT RETURN_TYPE;
}

else
    alias SWT_PTR RETURN_TYPE;

version (X86)
    const bool USE_ASSEMBLER = true;

else
    const bool USE_ASSEMBLER = true;

static if (REDUCED_CALLBACKS)
    const int MAX_CALLBACKS = 16;

else static if (USE_ASSEMBLER)
    const int MAX_CALLBACKS = 256;

else
    const int MAX_CALLBACKS = 128;    

const int MAX_ARGS = 12;

struct CALLBACK_DATA 
{
    Callback callback;
    jmethodID methodID;
    Object object;
    bool isStatic;
    bool isArrayBased; 
    int argCount;
    SWT_PTR errorResult;
}

/* Implementation */


/* --------------- callback globals ----------------- */

private
{
    CALLBACK_DATA callbackData[MAX_CALLBACKS];
    int callbackEnabled = 1;
    int callbackEntryCount = 0;
    bool initialized = 0;
    
    debug
        int counter = 0;
}

static if (USE_ASSEMBLER)
{
    version (Win32){}
    else version (Win32_WCE){}
    else
        import tango.stdc.posix.sys.mman;

    private ubyte* callbackCode = null;
    const int CALLBACK_THUNK_SIZE = 64;
}

SWT_PTR bind (Callback callbackObject, Object object, String method, String signature, int argCount, bool isStatic, bool isArrayBased, SWT_PTR errorResult)
{
    int i;
    jmethodID mid = null;
    jclass javaClass = that;
    string methodString = null;
    string sigString = null;

    if (!initialized)
    {
        memset(&callbackData, 0, callbackData.sizeof);
        initialized = true;
    }
    
    if (method)
        methodString = method;
    
    if (signature)
        sigString = signature;
    
    if (object && methodString && sigString)
    {
        if (isStatic)
        {
            mid = (*env).GetStaticMethodID(env, object, methodString, sigString);
        }
        else
        {
            javaClass = (*env).GetObjectClass(env, object);
            mid = (*env).GetMethodID(env, javaClass, methodString, sigString);
        }
    }
    
    if (mid == 0)
        goto fail;
    
    for (i = 0; i < MAX_CALLBACKS; i++)
    {
        if (!callbackData[i].callback)
        {
            if ((callbackData[i].callback = callbackObject) == null)
                goto fail;
            
            if ((callbackData[i].object = object) == null)
                goto fail;
            
            callbackData[i].isStatic = isStatic;
            callbackData[i].isArrayBased = isArrayBased;
            callbackData[i].argCount = argCount;
            callbackData[i].errorResult = errorResult;
            callbackData[i].methodID = mid;

            static if (!USE_ASSEMBLER)
                return cast(SWT_PTR) fnx_array[argCount][i];
            
            else
            {
                int j = 0, k, pad = 0;
                ubyte* code;
                
                if (callbackCode == null)
                {
                    version (Win32)
                    {
                        callbackCode = VirtualAlloc(null, CALLBACK_THUNK_SIZE * MAX_CALLBACKS, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                        if (callbackCode == null)
                            return 0;
                    }

                    else version (Win32_WCE)
                    {
                        callbackCode = VirtualAlloc(null, CALLBACK_THUNK_SIZE * MAX_CALLBACKS, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                        if (callbackCode == null)
                            return 0;
                    }

                    else
                    {
                        callbackCode = mmap(null, CALLBACK_THUNK_SIZE * MAX_CALLBACKS, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
                        if (callbackCode == MAP_FAILED)
                            return 0;
                    }
                }
                code = cast(ubyte*) (callbackCode + (i * CALLBACK_THUNK_SIZE));

                //PUSH EBP - 1 byte
                code[j++] = 0x55;

                //MOV EBP,ESP - 2 bytes
                code[j++] = 0x8b;
                code[j++] = 0xec;

                version (darwin)
                {
                    /* darwin calling conventions require that the stack be aligned on a 16-byte boundary. */
                    k = (argCount + 3) * SWT_PTR.sizeof;
                    pad = ((k + 15) & ~15) - k;
                    if (pad > 0)
                    {
                        //SUB ESP,pad - 3 bytes
                        code[j++] = 0x83;
                        code[j++] = 0xec;
                        code[j++] = pad;
                    }
                }

                // 3*argCount bytes
                for (k = (argCount + 1) * SWT_PTR.sizeof; k >= SWT_PTR.sizeof * 2; k -= SWT_PTR.sizeof)
                {
                    //PUSH SS:[EBP+k]
                    code[j++] = 0xff;
                    code[j++] = 0x75;
                    code[j++] = k;
                }

                if (i > 127)
                {
                    //PUSH i - 5 bytes
                    code[j++] = 0x68;
                    code[j++] = ((i >> 0) & 0xFF);
                    code[j++] = ((i >> 8) & 0xFF);
                    code[j++] = ((i >> 16) & 0xFF);
                    code[j++] = ((i >> 24) & 0xFF);
                }
                else
                {
                    //PUSH i - 2 bytes
                    code[j++] = 0x6a;
                    code[j++] = i;
                }

                //MOV EAX callback - 1 + SWT_PTR.sizeof bytes
                code[j++] = 0xb8;
                (cast(SWT_PTR*) &code[j])[0] = cast(SWT_PTR) &callback;
                j += SWT_PTR.sizeof;

                //CALL EAX - 2 bytes
                code[j++] = 0xff;
                code[j++] = 0xd0;

                //ADD ESP,(argCount + 1) * SWT_PTR.sizeof - 3 bytes
                code[j++] = 0x83;
                code[j++] = 0xc4;

                version (darwin)
                    code[j++] = cast(ubyte) (pad + ((argCount + 1) * SWT_PTR.sizeof));
                else
                    code[j++] = cast(ubyte) ((argCount + 1) * SWT_PTR.sizeof);

                //POP EBP - 1 byte
                code[j++] = 0x5d;

                version (Win32)
                {
                    // RETN argCount * SWT_PTR.sizeof - 3 bytes
                    code[j++] = 0xc2;
                    code[j++] = cast(ubyte) (argCount * SWT_PTR.sizeof);
                    code[j++] = 0x00;
                }

                else version (Win32_WCE)
                {
                    // RETN argCount * SWT_PTR.sizeof - 3 bytes
                    code[j++] = 0xc2;
                    code[j++] = cast(ubyte) (argCount * SWT_PTR.sizeof);
                    code[j++] = 0x00;
                }

                else
                {
                    // RETN - 1 byte
                    code[j++] = 0xc3;
                }

                if (j > CALLBACK_THUNK_SIZE)
                    throw new Error("Callback thunk overflow");

                return cast(SWT_PTR) code;
            }
        }
    }
    
    fail:
        return 0;
}

void unbind (Callback callback)
{
    int i;
    for (i=0; i<MAX_CALLBACKS; i++) {
        if (callbackData[i].callback !is null && callbackData[i].callback == callback) {
            if (callbackData[i].callback !is null) delete callbackData[i].callback;
            if (callbackData[i].object !is null) delete allbackData[i].object;
            memset(&callbackData[i], 0, CALLBACK_DATA.sizeof);
        }
    }
}

bool getEnabled ()
{
    return callbackEnabled;
}

int getEntryCount ()
{
    return callbackEntryCount;
}

void setEnabled (bool enable)
{
    callbackEnabled = enable;
}

void reset ()
{
    memset(cast(void*) &callbackData, 0, callbackData.sizeof);
}