Пример #1
0
/**
 * Entry function which will process the assembled code and perform the required actions
 */
struct value_defn processAssembledCode(char * assembled, unsigned int currentPoint, unsigned int length) {
    struct value_defn empty;
    empty.type=NONE_TYPE;
    empty.dtype=SCALAR;
    unsigned int i, fnAddr;
    for (i=currentPoint; i<length;) {
        unsigned char command=getUChar(&assembled[i]);
        i+=sizeof(unsigned char);
        if (command == LET_TOKEN) i=handleLet(assembled, i, length, 0);
        if (command == LETNOALIAS_TOKEN) i=handleLet(assembled, i, length, 1);
        if (command == ARRAYSET_TOKEN) i=handleArraySet(assembled, i, length);
        if (command == STOP_TOKEN) return empty;
        if (command == IF_TOKEN) i=handleIf(assembled, i, length);
        if (command == IFELSE_TOKEN) i=handleIf(assembled, i, length);
        if (command == FOR_TOKEN) i=handleFor(assembled, i, length);
        if (command == GOTO_TOKEN) i=handleGoto(assembled, i, length);
        if (command == FNCALL_TOKEN || command == FNCALL_BY_VAR_TOKEN) {
            i=handleFnCall(assembled, i, &fnAddr, length, command == FNCALL_BY_VAR_TOKEN ? 1:0);
            fnLevel++;
            processAssembledCode(assembled, fnAddr, length);
            clearVariablesToLevel(fnLevel);
            fnLevel--;
        }
        if (command == NATIVE_TOKEN) i=handleNative(assembled, i, length, NULL);
        if (command == RETURN_TOKEN) return empty;
        if (command == RETURN_EXP_TOKEN) {
            return getExpressionValue(assembled, &i, length);
        }
        if (stopInterpreter) return empty;
    }
    return empty;
}
Пример #2
0
/**
 * Entry function which will process the assembled code and perform the required actions
 */
void processAssembledCode(char * assembled, unsigned int length, unsigned short numberSymbols,
		int coreId, int numberActiveCores, int baseHostPid) {
	stopInterpreter=0;
	currentSymbolEntries=0;
	localCoreId=coreId;
	numActiveCores=numberActiveCores;
	symbolTable=initialiseSymbolTable(numberSymbols);
	hostCoresBasePid=baseHostPid;
	unsigned int i;
	for (i=0;i<length;) {
		unsigned short command=getUShort(&assembled[i]);
		i+=sizeof(unsigned short);
		if (command == LET_TOKEN) i=handleLet(assembled, i);
		if (command == ARRAYSET_TOKEN) i=handleArraySet(assembled, i);
		if (command == DIMARRAY_TOKEN) i=handleDimArray(assembled, i, 0);
		if (command == DIMSHAREDARRAY_TOKEN) i=handleDimArray(assembled, i, 1);
		if (command == PRINT_TOKEN) i=handlePrint(assembled, i);
		if (command == STOP_TOKEN) return;
		if (command == SYNC_TOKEN) i=handleSync(assembled, i);
		if (command == IF_TOKEN) i=handleIf(assembled, i);
		if (command == IFELSE_TOKEN) i=handleIf(assembled, i);
		if (command == FOR_TOKEN) i=handleFor(assembled, i);
		if (command == GOTO_TOKEN) i=handleGoto(assembled, i);
		if (command == INPUT_TOKEN) i=handleInput(assembled, i);
		if (command == INPUT_STRING_TOKEN) i=handleInputWithString(assembled, i);
		if (command == SEND_TOKEN) i=handleSend(assembled, i);
		if (command == RECV_TOKEN) i=handleRecv(assembled, i);
		if (command == RECVTOARRAY_TOKEN) i=handleRecvToArray(assembled, i);
		if (command == SENDRECV_TOKEN) i=handleSendRecv(assembled, i);
		if (command == SENDRECVARRAY_TOKEN) i=handleSendRecvArray(assembled, i);
		if (command == BCAST_TOKEN) i=handleBcast(assembled, i);
		if (command == REDUCTION_TOKEN) i=handleReduction(assembled, i);
		if (stopInterpreter) return;
	}
}
Пример #3
0
static struct value_defn getExpressionValue(char * assembled, unsigned int * currentPoint, unsigned int length, int threadId) {
#else
static struct value_defn getExpressionValue(char * assembled, unsigned int * currentPoint, unsigned int length) {
#endif
    struct value_defn value;

    unsigned char expressionId=getUChar(&assembled[*currentPoint]);
    *currentPoint+=sizeof(unsigned char);
    if (expressionId == INTEGER_TOKEN) {
        value.type=INT_TYPE;
        value.dtype=SCALAR;
        cpy(value.data, &assembled[*currentPoint], sizeof(int));
        *currentPoint+=sizeof(int);
    } else if (expressionId == REAL_TOKEN) {
        value.type=REAL_TYPE;
        value.dtype=SCALAR;
        cpy(value.data, &assembled[*currentPoint], sizeof(float));
        *currentPoint+=sizeof(float);
    } else if (expressionId == BOOLEAN_TOKEN) {
        value.type=BOOLEAN_TYPE;
        value.dtype=SCALAR;
        cpy(value.data, &assembled[*currentPoint], sizeof(int));
        *currentPoint+=sizeof(int);
    } else if (expressionId == STRING_TOKEN) {
        value.type=STRING_TYPE;
        char * strPtr=assembled + *currentPoint;
        cpy(&value.data, &strPtr, sizeof(char*));
        *currentPoint+=(slength(strPtr)+1);
        value.dtype=SCALAR;
    } else if (expressionId == NONE_TOKEN) {
        value.type=NONE_TYPE;
        value.dtype=SCALAR;
    } else if (expressionId ==FN_ADDR_TOKEN) {
        value.type=FN_ADDR_TYPE;
        value.dtype=SCALAR;
        cpy(value.data, &assembled[*currentPoint], sizeof(unsigned short));
        *currentPoint+=sizeof(unsigned short);
    } else if (expressionId == LET_TOKEN) {
#ifdef HOST_INTERPRETER
        *currentPoint=handleLet(assembled, *currentPoint, length, 0, threadId);
        value=getExpressionValue(assembled, currentPoint, length, threadId);
#else
        *currentPoint=handleLet(assembled, *currentPoint, length, 0);
        value=getExpressionValue(assembled, currentPoint, length);
#endif
    } else if (expressionId == ARRAY_TOKEN) {
        int i, j, repetitionMultiplier=1, numItems=getInt(&assembled[*currentPoint]), totalSize=numItems;
        *currentPoint+=sizeof(int);
        unsigned char hasRepetition=getUChar(&assembled[*currentPoint]), ndims=1;
        *currentPoint+=sizeof(unsigned char);
        if (hasRepetition) {
#ifdef HOST_INTERPRETER
            struct value_defn repetitionV=getExpressionValue(assembled, currentPoint, length, threadId);
#else
            struct value_defn repetitionV=getExpressionValue(assembled, currentPoint, length);
#endif
            cpy(&repetitionMultiplier, repetitionV.data, sizeof(int));
            totalSize*=repetitionMultiplier;
        }
#ifdef HOST_INTERPRETER
        char * address=getHeapMemory(sizeof(unsigned char) + (sizeof(int)*(totalSize+1)), 0, threadId);
#else
        char * address=getHeapMemory(sizeof(unsigned char) + (sizeof(int)*(totalSize+1)), 0, currentSymbolEntries, symbolTable);
#endif
        cpy(value.data, &address, sizeof(char*));
        ndims=ndims | (1 << 4);
        cpy(address, &ndims, sizeof(unsigned char));
        address+=sizeof(unsigned char);
        cpy(address, &totalSize, sizeof(int));
        unsigned int prevCP=*currentPoint;
        for (j=0; j<repetitionMultiplier; j++) {
            *currentPoint=prevCP;
            for (i=0; i<numItems; i++) {
#ifdef HOST_INTERPRETER
                struct value_defn itemV=getExpressionValue(assembled, currentPoint, length, threadId);
#else
                struct value_defn itemV=getExpressionValue(assembled, currentPoint, length);
#endif
                cpy(address+((i+(j*numItems)+1) * sizeof(int)), itemV.data, sizeof(int));
                value.type=itemV.type;
            }
        }
        value.dtype=ARRAY;
    } else if (expressionId == FNCALL_TOKEN || expressionId == FNCALL_BY_VAR_TOKEN) {
#ifdef HOST_INTERPRETER
        unsigned int fnAddr;
        *currentPoint=handleFnCall(assembled, *currentPoint, &fnAddr, length, expressionId == FNCALL_BY_VAR_TOKEN ? 1:0, threadId);
        fnLevel[threadId]++;
        value=processAssembledCode(assembled, fnAddr, length, threadId);
        clearVariablesToLevel(fnLevel[threadId], threadId);
        fnLevel[threadId]--;
#else
        unsigned int fnAddr;
        *currentPoint=handleFnCall(assembled, *currentPoint, &fnAddr, length, expressionId == FNCALL_BY_VAR_TOKEN ? 1:0);
        fnLevel++;
        value=processAssembledCode(assembled, fnAddr, length);
        clearVariablesToLevel(fnLevel);
        fnLevel--;
#endif
    } else if (expressionId == NATIVE_TOKEN) {
#ifdef HOST_INTERPRETER
        *currentPoint=handleNative(assembled, *currentPoint, length, &value, threadId);
#else
        *currentPoint=handleNative(assembled, *currentPoint, length, &value);
#endif
    } else if (expressionId == IDENTIFIER_TOKEN || expressionId == ARRAYACCESS_TOKEN) {
        unsigned short variable_id=getUShort(&assembled[*currentPoint]);
        *currentPoint+=sizeof(unsigned short);
#ifdef HOST_INTERPRETER
        struct symbol_node* variableSymbol=getVariableSymbol(variable_id, fnLevel[threadId], threadId, 1);
#else
        struct symbol_node* variableSymbol=getVariableSymbol(variable_id, fnLevel, 1);
#endif
        if (expressionId == IDENTIFIER_TOKEN) {
            if (variableSymbol->value.dtype==SCALAR) {
                value=getVariableValue(variableSymbol, -1);
            } else if (variableSymbol->value.dtype==ARRAY) {
                value.dtype=ARRAY;
                value.type=variableSymbol->value.type;
                cpy(value.data, variableSymbol->value.data, sizeof(char*));
            }
        } else if (expressionId == ARRAYACCESS_TOKEN) {
#ifdef HOST_INTERPRETER
            int targetIndex=getArrayAccessorIndex(variableSymbol, assembled, currentPoint, length, threadId);
#else
            int targetIndex=getArrayAccessorIndex(variableSymbol, assembled, currentPoint, length);
#endif
            value=getVariableValue(variableSymbol, targetIndex);
        }
    } else if (expressionId == ADD_TOKEN || expressionId == SUB_TOKEN || expressionId == MUL_TOKEN ||
               expressionId == DIV_TOKEN || expressionId == MOD_TOKEN || expressionId == POW_TOKEN) {
#ifdef HOST_INTERPRETER
        value=computeExpressionResult(expressionId, assembled, currentPoint, length, threadId);
#else
        value=computeExpressionResult(expressionId, assembled, currentPoint, length);
#endif
    } else if (expressionId == EQ_TOKEN || expressionId == NEQ_TOKEN || expressionId == GT_TOKEN || expressionId == GEQ_TOKEN ||
               expressionId == LT_TOKEN || expressionId == LEQ_TOKEN || expressionId == IS_TOKEN) {
        *currentPoint-=sizeof(unsigned char);
#ifdef HOST_INTERPRETER
        int retVal=determine_logical_expression(assembled, currentPoint, length, threadId);
#else
        int retVal=determine_logical_expression(assembled, currentPoint, length);
#endif
        value.type=BOOLEAN_TYPE;
        value.dtype=SCALAR;
        cpy(value.data, &retVal, sizeof(int));
    }
    return value;
}

/**
 * Computes the result of a simple mathematical expression, if one is a real and the other an integer
 * then raises to be a real
 */
#ifdef HOST_INTERPRETER
static struct value_defn computeExpressionResult(unsigned char operator, char * assembled, unsigned int * currentPoint,
        unsigned int length, int threadId) {
#else
static struct value_defn computeExpressionResult(unsigned char operator, char * assembled, unsigned int * currentPoint,
        unsigned int length) {
#endif
    struct value_defn value;
#ifdef HOST_INTERPRETER
    struct value_defn v1=getExpressionValue(assembled, currentPoint, length, threadId);
    struct value_defn v2=getExpressionValue(assembled, currentPoint, length, threadId);
#else
    struct value_defn v1=getExpressionValue(assembled, currentPoint, length);
    struct value_defn v2=getExpressionValue(assembled, currentPoint, length);
#endif
    value.type=v1.type==INT_TYPE && v2.type==INT_TYPE ? INT_TYPE : v1.type==STRING_TYPE || v2.type==STRING_TYPE ? STRING_TYPE : REAL_TYPE;
    value.dtype=SCALAR;
    if (value.type==INT_TYPE) {
        int i, value1=getInt(v1.data), value2=getInt(v2.data), result;
        if (operator==ADD_TOKEN) result=value1+value2;
        if (operator==SUB_TOKEN) result=value1-value2;
        if (operator==MUL_TOKEN) result=value1*value2;
        if (operator==DIV_TOKEN) result=value1/value2;
        if (operator==MOD_TOKEN) result=value1%value2;
        if (operator==POW_TOKEN) {
            result=value2 == 0 ? 1 : value1;
            for (i=1; i<value2; i++) result=result*value1;
        }
        cpy(&value.data, &result, sizeof(int));
    } else if (value.type==REAL_TYPE) {
        float value1=getFloat(v1.data);
        float value2=getFloat(v2.data);
        float result;
        if (v1.type==INT_TYPE) value1=(float) getInt(v1.data);
        if (v2.type==INT_TYPE) {
            value2=(float) getInt(v2.data);
            if (operator == POW_TOKEN) {
                int i;
                result=value2 == 0 ? 1 : value1;
                for (i=1; i<(int) value2; i++) result=result*value1;
            }
        }
        if (operator == ADD_TOKEN) result=value1+value2;
        if (operator == SUB_TOKEN) result=value1-value2;
        if (operator == MUL_TOKEN) result=value1*value2;
        if (operator == DIV_TOKEN) result=value1/value2;
        cpy(&value.data, &result, sizeof(float));
    } else if (value.type==STRING_TYPE) {
        if (operator == ADD_TOKEN) {
#ifdef HOST_INTERPRETER
            return performStringConcatenation(v1, v2, threadId);
#else
            return performStringConcatenation(v1, v2, currentSymbolEntries, symbolTable);
#endif
        } else {
            raiseError(ERR_ONLY_ADDITION_STR);
        }
    }
    return value;
}

/**
 * Retrieves the absolute array target index based upon the provided index expression(s) and dimensions of the array itself. Does some error checking
 * to ensure that the configured values do not exceed the size
 */
#ifdef HOST_INTERPRETER
static int getArrayAccessorIndex(struct symbol_node* variableSymbol, char * assembled, unsigned int * currentPoint, unsigned int length, int threadId) {
#else
static int getArrayAccessorIndex(struct symbol_node* variableSymbol, char * assembled, unsigned int * currentPoint, unsigned int length) {
#endif
    struct value_defn index;
    int i, j, runningWeight, spec_weight, num_weights, specificIndex=0, provIdx;
    unsigned int totSize=1;
    unsigned char num_dims=getUChar(&assembled[*currentPoint]), array_dims, needsExtension=0, allowedExtension;
    *currentPoint+=sizeof(unsigned char);

    char * arraymemory;
    cpy(&arraymemory, variableSymbol->value.data, sizeof(char*));
    cpy(&array_dims, arraymemory, sizeof(unsigned char));
    allowedExtension=(array_dims >> 4) & 1;
    array_dims=array_dims&0xF;
    arraymemory+=sizeof(unsigned char);

    if (num_dims > array_dims) raiseError(ERR_TOO_MANY_ARR_INDEX);

    for (i=0; i<num_dims; i++) {
        num_weights=array_dims-(i+1);
        runningWeight=1;
        for (j=num_weights; j<0; j--) {
            cpy(&spec_weight, &arraymemory[sizeof(int) * (array_dims-j)], sizeof(int));
            runningWeight*=spec_weight;
        }
#ifdef HOST_INTERPRETER
        index=getExpressionValue(assembled, currentPoint, length, threadId);
#else
        index=getExpressionValue(assembled, currentPoint, length);
#endif
        cpy(&spec_weight, &arraymemory[sizeof(int) * i], sizeof(int));
        totSize*=spec_weight;
        provIdx=getInt(index.data);
        if (provIdx < 0) {
            raiseError(ERR_NEG_ARR_INDEX);
        } else if (provIdx >= spec_weight) {
            if (!allowedExtension) raiseError(ERR_ARR_INDEX_EXCEED_SIZE);
            spec_weight=provIdx+1;
            cpy(&arraymemory[sizeof(int) * i], &spec_weight, sizeof(int));
            needsExtension=1;
        }
        specificIndex+=(runningWeight * provIdx);
    }
    if (needsExtension) {
        unsigned int newSize=1;
        for (i=0; i<num_dims; i++) {
            cpy(&spec_weight, &arraymemory[sizeof(int) * i], sizeof(int));
            newSize*=spec_weight;
        }
#ifdef HOST_INTERPRETER
        char * newmem=getHeapMemory((sizeof(int) * newSize) + (sizeof(int) * num_dims) + sizeof(unsigned char), 0, threadId);
#else
        char * newmem=getHeapMemory((sizeof(int) * newSize) + (sizeof(int) * num_dims) + sizeof(unsigned char), 0, currentSymbolEntries, symbolTable);
#endif
        arraymemory-=sizeof(unsigned char);
        cpy(newmem, arraymemory, (sizeof(int) * totSize) + (sizeof(int) * num_dims) + sizeof(unsigned char));
#ifdef HOST_INTERPRETER
        freeMemoryInHeap(arraymemory, threadId);
#else
        freeMemoryInHeap(arraymemory);
#endif
        cpy(variableSymbol->value.data, &newmem, sizeof(char*));
    }
    return specificIndex;
}

/**
 * Retrieves the symbol entry of a variable based upon its id
 */
#ifdef HOST_INTERPRETER
static struct symbol_node* getVariableSymbol(unsigned short id, unsigned char lvl, int threadId, int followAlias) {
#else
static struct symbol_node* getVariableSymbol(unsigned short id, unsigned char lvl, int followAlias) {
#endif
    int i;
#ifdef HOST_INTERPRETER
    for (i=0; i<=currentSymbolEntries[threadId]; i++) {
        if (symbolTable[threadId][i].id == id && symbolTable[threadId][i].state != UNALLOCATED && (symbolTable[threadId][i].level == 0 || symbolTable[threadId][i].level==lvl)) {
            if (followAlias && symbolTable[threadId][i].state == ALIAS) {
                return getVariableSymbol(symbolTable[threadId][i].alias, lvl-1, threadId, 1);
            } else {
                return &(symbolTable[threadId])[i];
            }
        }
#else
    for (i=0; i<=currentSymbolEntries; i++) {
        if (symbolTable[i].id == id && symbolTable[i].state != UNALLOCATED && (symbolTable[i].level == 0 || symbolTable[i].level==lvl)) {
            if (followAlias && symbolTable[i].state == ALIAS) {
                return getVariableSymbol(symbolTable[i].alias, lvl-1, 1);
            } else {
                return &symbolTable[i];
            }
        }
#endif
    }
    int zero=0;
#ifdef HOST_INTERPRETER
    int newEntryLocation=getSymbolTableEntryId(threadId);
    symbolTable[threadId][newEntryLocation].id=id;
    symbolTable[threadId][newEntryLocation].state=ALLOCATED;
    symbolTable[threadId][newEntryLocation].level=lvl;
    symbolTable[threadId][newEntryLocation].value.type=INT_TYPE;
    cpy(symbolTable[threadId][newEntryLocation].value.data, &zero, sizeof(int));
    return &symbolTable[threadId][newEntryLocation];
#else
    int newEntryLocation=getSymbolTableEntryId();
    symbolTable[newEntryLocation].id=id;
    symbolTable[newEntryLocation].level=lvl;
    symbolTable[newEntryLocation].state=ALLOCATED;
    symbolTable[newEntryLocation].value.type=INT_TYPE;
    symbolTable[newEntryLocation].value.dtype=SCALAR;
    cpy(symbolTable[newEntryLocation].value.data, &zero, sizeof(int));
    return &symbolTable[newEntryLocation];
#endif
}
#ifdef HOST_INTERPRETER
static int getSymbolTableEntryId(int threadId) {
#else
static int getSymbolTableEntryId(void) {
#endif
    int i;
#ifdef HOST_INTERPRETER
    for (i=0; i<=currentSymbolEntries[threadId]; i++) {
        if (symbolTable[threadId][i].state == UNALLOCATED) return i;
    }
    return ++currentSymbolEntries[threadId];
#else
    for (i=0; i<=currentSymbolEntries; i++) {
        if (symbolTable[i].state == UNALLOCATED) return i;
    }
    return ++currentSymbolEntries;
#endif
}

#ifdef HOST_INTERPRETER
static void clearVariablesToLevel(unsigned char clearLevel, int threadId) {
#else
static void clearVariablesToLevel(unsigned char clearLevel) {
#endif
    int i;
    char * smallestMemoryAddress=0, *ptr;
#ifdef HOST_INTERPRETER
    for (i=0; i<=currentSymbolEntries[threadId]; i++) {
        if (symbolTable[threadId][i].level >= clearLevel && symbolTable[threadId][i].state != UNALLOCATED) {
            symbolTable[threadId][i].state=UNALLOCATED;
            if (symbolTable[threadId][i].value.dtype==SCALAR && symbolTable[threadId][i].value.type != STRING_TYPE) {
                cpy(&ptr, symbolTable[threadId][i].value.data, sizeof(int*));
                if (ptr != 0 && (smallestMemoryAddress == 0 || smallestMemoryAddress > ptr)) smallestMemoryAddress=ptr;
            }
        }
    }
#else
    for (i=0; i<=currentSymbolEntries; i++) {
        if (symbolTable[i].level >= clearLevel && symbolTable[i].state != UNALLOCATED) {
            symbolTable[i].state=UNALLOCATED;
            if (symbolTable[i].value.dtype==SCALAR && symbolTable[i].value.type != STRING_TYPE) {
                cpy(&ptr, symbolTable[i].value.data, sizeof(char*));
                if (ptr != 0 && (smallestMemoryAddress == 0 || smallestMemoryAddress > ptr)) smallestMemoryAddress=ptr;
            }
        }
    }
#endif
    if (smallestMemoryAddress != 0) clearFreedStackFrames(smallestMemoryAddress);
}

/**
 * Sets a variables value in memory as pointed to by symbol table
 */
void setVariableValue(struct symbol_node* variableSymbol, struct value_defn value, int index) {
    variableSymbol->value.type=value.type;
    if (value.type == STRING_TYPE) {
        cpy(&variableSymbol->value.data, &value.data, sizeof(char*));
    } else {
        int currentAddress=getInt(variableSymbol->value.data);
        if (currentAddress == 0) {
            char * address=getStackMemory(sizeof(int) * index, 0);
            cpy(variableSymbol->value.data, &address, sizeof(char*));
            cpy(address+((index+1) *4), value.data, sizeof(int));
        } else {
            char * ptr;
            cpy(&ptr, variableSymbol->value.data, sizeof(char*));
            if (variableSymbol->value.dtype == ARRAY) {
                unsigned char num_dims;
                cpy(&num_dims, ptr, sizeof(unsigned char));
                num_dims=num_dims & 0xF;
                ptr+=((index+num_dims)*sizeof(int)) + sizeof(unsigned char);
            } else {
                ptr+=(index+1)*sizeof(int);
            }
            cpy(ptr, value.data, sizeof(int));
        }
    }
}

/**
 * Retrieves a variable value from memory, which the symbol table points to
 */
struct value_defn getVariableValue(struct symbol_node* variableSymbol, int index) {
    struct value_defn val;
    val.type=variableSymbol->value.type;
    val.dtype=SCALAR;
    if (variableSymbol->value.type == STRING_TYPE) {
        cpy(&val.data, &variableSymbol->value.data, sizeof(int*));
    } else {
        char * ptr;
        cpy(&ptr, variableSymbol->value.data, sizeof(char*));
        if (variableSymbol->value.dtype == ARRAY) {
            unsigned char num_dims;
            cpy(&num_dims, ptr, sizeof(unsigned char));
            num_dims=num_dims & 0xF;
            ptr+=((index+num_dims)*sizeof(int)) + sizeof(unsigned char);
        } else {
            ptr+=(index+1)*sizeof(int);
        }
        cpy(val.data, ptr, sizeof(char*));
    }
    return val;
}

static unsigned char getUChar(void* data) {
    unsigned char v;
    cpy(&v, data, sizeof(unsigned char));
    return v;
}

/**
 * Helper method to get an unsigned short from data (needed as casting to integer directly requires 4 byte alignment
 * which we do not want to enforce as it wastes memory.)
 */
static unsigned short getUShort(void* data) {
    unsigned short v;
    cpy(&v, data, sizeof(unsigned short));
    return v;
}