Friday, August 6, 2010

Just In Time Compiler for Managed Platform- Part 6: Put Field and Get Field

Now we have our object on the heap. We need mechanism to putfield and getfield. The operation is very simple indeed.

First we need a helper to get a field index (variable) in the object memory in the heap:

//And also we put the method names in HelperMethods structure


int GetFieldIndex(JavaClass *pTargetClass, Context *pContext, u2 index)
{
    CONSTANT_Fieldref_info *pFieldInfo 
                 = (CONSTANT_Fieldref_info *)pContext->pClass->constant_pool[index];
    
    ASSERT(pFieldInfo->tag == CONSTANT_Fieldref); 

    u2 classIndex = getu2(&((u1 *)pFieldInfo)[1]);
    u2 nameAndTypeIndex = getu2(&((u1 *)pFieldInfo)[3]);

    CONSTANT_NameAndType_info *pNameTypeInfo 
                  = (CONSTANT_NameAndType_info *)  pContext->pClass->constant_pool[nameAndTypeIndex];

    ASSERT(pNameTypeInfo->tag == CONSTANT_NameAndType);

    u2 nameIndex = getu2(&((u1 *)pNameTypeInfo)[1]);
    u2 descIndex = getu2(&((u1 *)pNameTypeInfo)[3]);
    CString strFieldName, strFieldDesc;
    
    if(!pContext->pClass->GetStringFromConstPool(nameIndex, strFieldName))  
    {
        ASSERT(FALSE); 
        return -1;
    }
    
    if(!pContext->pClass->GetStringFromConstPool(descIndex, strFieldDesc))  
    {
        ASSERT(FALSE);
        return -2;
    }

    int superClassSize = 0;
   
    JavaClass *pCurClass = pTargetClass;
    
    int fieldIndex = -1;
    while(true)
    {        
        fieldIndex = pCurClass->GetFieldIndex(strFieldName, strFieldDesc);
        pCurClass = pTargetClass->GetSuperClass();
        if(fieldIndex >= 0)
        {
            fieldIndex += pCurClass ? pCurClass->GetObjectFieldCount() : 0;
            break;
        }
        else
        {            
            if(!pCurClass)
            {
                break;
            }
        }
    }

    ASSERT(fieldIndex>=0);
    return fieldIndex;
}


Now we define the method to execute the two instructions. We do not generate code foe this operaions and callback from the generated code since the operation is static and no parsing or instruction execution required-

#define PUT_FIELD_HELPER_INDEX 4
#define GET_FIELD_HELPER_INDEX 5 

void PutField(Context *pContext, u2 index)
{
    Variable obj=pContext->stack[pContext->stackTop-2];
    Variable value=pContext->stack[pContext->stackTop-1];
    Variable *pVarList = pContext->pVMEnv->pObjectHeap->GetObjectPointer(obj.object);

    JavaClass *pTargetClass = (JavaClass *)pVarList[0].ptrValue;
    ASSERT(pTargetClass && pTargetClass->magic == 0xCAFEBABE);

    int fieldIndex = GetFieldIndex(pTargetClass, pContext, index);
    
    pVarList[fieldIndex+1]=value;

    pContext->stackTop-=2;
}

void GetField(Context *pContext, u2 index)
{
    Variable obj=pContext->stack[pContext->stackTop-1]; 
    Variable *pVarList=pContext->pVMEnv->pObjectHeap->GetObjectPointer(obj.object);

    JavaClass *pTargetClass = (JavaClass *)pVarList[0].ptrValue;
    ASSERT(pTargetClass && pTargetClass->magic == 0xCAFEBABE);

    int fieldIndex = GetFieldIndex(pTargetClass, pContext, index);

    pContext->stack[pContext->stackTop-1]=pVarList[fieldIndex+1];
}


Now we generate instruction for them. Here is how we do it for putfield:

void EmitCallPutField(u1* code, int &ip, u4 index)
{
    u1 c[]={
        //((void (*)(Context *pContext, u2 index))pContext->pVMEnv->ppHelperMethods[PUT_FIELD_HELPER_INDEX])(pContext, 0x1234);
        0x8B, 0xF4, //            mov         esi,esp 
        0x68, 0x00, 0x00, 0x00, 0x00, //   push        index 
        0x8B, 0x45, 0x08, //         mov         eax,dword ptr [pContext] 
        0x50, //               push        eax  
        0x8B, 0x4D, 0x08, //         mov         ecx,dword ptr [pContext] 
        0x8B, 0x51, 0x10, //         mov         edx,dword ptr [ecx+10h] 
        0x8B, 0x42, 0x08, //         mov         eax,dword ptr [edx+8] 
        0x8B, 0x48, 0x10, //         mov         ecx,dword ptr [eax+10h] 
        0xFF, 0xD1, //            call        ecx  
        0x83, 0xC4, 0x08, //         add         esp,8 
    };

    memcpy(c+3, &index, sizeof(index));
    memcpy(&code[ip], c, sizeof(c));
    ip+=sizeof(c);
}

void ExecutePutField(u1* code, int& ip, u2 index)
{
    EmitCallPutField(code, ip, index);
}

For getfield we just need to change the method pointer (add 4)

mov ecx,dword ptr [eax+14h] 

So we can assign value to a class field and get that value when we need it. Next we need array handling. Comes next day.

No comments:

Post a Comment