view dwt/internal/c/callback.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 8b48be5454ce
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;

import dwt.internal.Callback;

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 (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 (Win32){}
    else version (Win32_WCE){}
    else
        import tango.stdc.posix.sys.mman;

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

SWT_PTR Java_org_eclipse_swt_internal_Callback_bind (JNIEnv* env, jclass that,
        jobject callbackObject, jobject object, jstring method,
        jstring signature, jint argCount, jboolean isStatic,
        jboolean 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, sizeof(callbackData));
        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 (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) * sizeof(SWT_PTR);
                    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) * sizeof(SWT_PTR); k >= sizeof(SWT_PTR) * 2; k -= sizeof(
                        SWT_PTR))
                {
                    //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 + sizeof(SWT_PTR) bytes
                code[j++] = 0xb8;
                (cast(SWT_PTR*) &code[j])[0] = cast(SWT_PTR) &callback;
                j += sizeof(SWT_PTR);

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

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

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

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

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

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