view dwt/internal/c/callback.d @ 7:e831403a80a9

Add 'cast' to casts
author Frank Benoit <benoit@tionex.de>
date Wed, 27 Aug 2008 14:30:35 +0200
parents 8b48be5454ce
children 30a762abda2a
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 dwt.dwthelper.utils;
import dwt.internal.Callback;

/* Header */

version cast(Win32)
{
    import tango.sys.win32.UserGdi;
    import tango.sys.win32.Types;
}

else version cast(Win32_WCE)
{
    import tango.sys.win32.UserGdi;
    import tango.sys.win32.Types;
}

else
    alias RETURN_TYPE SWT_PTR;

/* Implementation */

alias size_t SWT_PTR;

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

bool USE_ASSEMBLER = false;

version cast(X86)
    bool USE_ASSEMBLER = true;

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

SWT_PTR callback(int index, ...);

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

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

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

    if (jvm == null)
        (*env).GetJavaVM(env, &jvm);

    if (!initialized)
    {
        memset(&callbackData, 0, callbackData.sizeof);
        initialized = 1;
    }
    
    if (method)
        methodString = cast(/*const*/char*) (*env).GetStringUTFChars(env, method, null);
    
    if (signature)
        sigString = cast(/*const*/char*) (*env).GetStringUTFChars(env, signature, null);
    
    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 (method && methodString)
        (*env).ReleaseStringUTFChars(env, method, methodString);
    
    if (signature && sigString)
        (*env).ReleaseStringUTFChars(env, signature, sigString);
    
    if (mid == 0)
        goto fail;
    
    for (i = 0; i < MAX_CALLBACKS; i++)
    {
        if (!callbackData[i].callback)
        {
            if ((callbackData[i].callback = (*env).NewGlobalRef(env, callbackObject)) == null)
                goto fail;
            
            if ((callbackData[i].object = (*env).NewGlobalRef(env, 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];

            {
                int j = 0, k, pad = 0;
                ubyte* code;
                
                if (callbackCode == null)
                {
                    version cast(Win32)
                    {
                        callbackCode = VirtualAlloc(null, CALLBACK_THUNK_SIZE * MAX_CALLBACKS, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
                        if (callbackCode == null)
                            return 0;
                    }

                    else version cast(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 cast(Win32)
                {
                    // RETN argCount * SWT_PTR.sizeof - 3 bytes
                    code[j++] = 0xc2;
                    code[j++] = cast(ubyte) (argCount * SWT_PTR.sizeof);
                    code[j++] = 0x00;
                }

                else version cast(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)
                {
                    jclass errorClass = (*env).FindClass(env, "java/lang/Error");
                    (*env).ThrowNew(env, errorClass, "Callback thunk overflow");
                }

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