blob: 1ed58995249bfdedde3829bda07841e5af4c76fc [file] [log] [blame]
//===--------- CLISignature.cpp - Reads CLI signatures --------------------===//
//
// N3
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Assembly.h"
#include "MSCorlib.h"
#include "N3.h"
#include "Reader.h"
#include "VMClass.h"
#include "VMThread.h"
#include "SignatureNames.def"
using namespace n3;
// ECMA 335: page 150 23.1.16 Element types used in signatures
static VMCommonClass* METHOD_ElementTypeEnd(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("implement me");
return 0;
}
static VMCommonClass* METHOD_ElementTypeVoid(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pVoid;
}
static VMCommonClass* METHOD_ElementTypeBoolean(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pBoolean;
}
static VMCommonClass* METHOD_ElementTypeChar(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pChar;
}
static VMCommonClass* METHOD_ElementTypeI1(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pSInt8;
}
static VMCommonClass* METHOD_ElementTypeU1(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pUInt8;
}
static VMCommonClass* METHOD_ElementTypeI2(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pSInt16;
}
static VMCommonClass* METHOD_ElementTypeU2(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pUInt16;
}
static VMCommonClass* METHOD_ElementTypeI4(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pSInt32;
}
static VMCommonClass* METHOD_ElementTypeU4(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pUInt32;
}
static VMCommonClass* METHOD_ElementTypeI8(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pSInt64;
}
static VMCommonClass* METHOD_ElementTypeU8(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pUInt64;
}
static VMCommonClass* METHOD_ElementTypeR4(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pFloat;
}
static VMCommonClass* METHOD_ElementTypeR8(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pDouble;
}
static VMCommonClass* METHOD_ElementTypeString(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pString;
}
static VMCommonClass* METHOD_ElementTypePtr(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMCommonClass* contains = ass->exploreType(offset, genClass, genMethod);
return ass->constructPointer(contains, 1);
}
static VMCommonClass* METHOD_ElementTypeByRef(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMCommonClass* contains = ass->exploreType(offset, genClass, genMethod);
return ass->constructPointer(contains, 1);
}
static VMCommonClass* METHOD_ElementTypeValueType(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
uint32 value = ass->uncompressSignature(offset);
uint32 table = value & 3;
uint32 index = value >> 2;
uint32 token = 0;
switch (table) {
case 0:
table = CONSTANT_TypeDef;
break;
case 1:
table = CONSTANT_TypeRef;
break;
case 2:
table = CONSTANT_TypeSpec;
break;
default:
VMThread::get()->getVM()->error("unknown TypeDefOrRefEncoded %d", index);
break;
}
token = (table << 24) + index;
VMCommonClass* cl = ass->loadType((N3*) (VMThread::get()->getVM()), token, false,
false, false, true, genClass, genMethod);
return cl;
}
static VMCommonClass* METHOD_ElementTypeClass(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
uint32 value = ass->uncompressSignature(offset);
uint32 table = value & 3;
uint32 index = value >> 2;
uint32 token = 0;
switch (table) {
case 0:
table = CONSTANT_TypeDef;
break;
case 1:
table = CONSTANT_TypeRef;
break;
case 2:
table = CONSTANT_TypeSpec;
break;
default:
VMThread::get()->getVM()->error("unknown TypeDefOrRefEncoded %d", index);
break;
}
token = (table << 24) + index;
VMCommonClass* cl = ass->loadType((N3*) (VMThread::get()->getVM()), token, false,
false, false, true, genClass, genMethod);
return cl;
}
static VMCommonClass* METHOD_ElementTypeVar(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
uint32 number = ass->uncompressSignature(offset);
assert(genClass != NULL && "Current Generic Class not set!");
return genClass->genericParams[number];
}
static VMCommonClass* METHOD_ElementTypeArray(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMCommonClass* cl = ass->exploreType(offset, genClass, genMethod);
uint32 rank = ass->uncompressSignature(offset);
uint32 numSizes = ass->uncompressSignature(offset);
if (numSizes != 0) {
printf("type = %s\n", mvm::PrintBuffer(cl).cString());
VMThread::get()->getVM()->error("implement me");
}
for (uint32 i = 0; i < numSizes; ++i) {
ass->uncompressSignature(offset);
}
uint32 numObounds = ass->uncompressSignature(offset);
if (numObounds != 0)
VMThread::get()->getVM()->error("implement me");
for (uint32 i = 0; i < numObounds; ++i) {
ass->uncompressSignature(offset);
}
VMClassArray* array = ass->constructArray(cl, rank);
return array;
}
static VMCommonClass* METHOD_ElementTypeGenericInst(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
// offset points to (CLASS | VALUETYPE) TypeDefOrRefEncoded
// skip generic type definition
offset++; // this is (CLASS | VALUETYPE)
// save starting offset for later use
uint32 genericTypeOffset = offset;
ass->uncompressSignature(offset); // TypeDefOrRefEncoded
//VMCommonClass* cl = ass->exploreType(offset);
uint32 argCount = ass->uncompressSignature(offset);
std::vector<VMCommonClass*> args;
// Get generic arguments.
for (uint32 i = 0; i < argCount; ++i) {
args.push_back(ass->exploreType(offset, genClass, genMethod));
}
// save offset
uint32 endOffset = offset;
// restore starting offset
offset = genericTypeOffset;
// TypeDefOrRefEncoded
uint32 value = ass->uncompressSignature(offset);
uint32 table = value & 3;
uint32 index = value >> 2;
uint32 token = 0;
switch (table) {
case 0:
table = CONSTANT_TypeDef;
break;
case 1:
table = CONSTANT_TypeRef;
break;
case 2:
table = CONSTANT_TypeSpec;
break;
default:
VMThread::get()->getVM()->error("unknown TypeDefOrRefEncoded %d", index);
break;
}
token = (table << 24) + index;
VMCommonClass* cl = ass->loadType((N3*) (VMThread::get()->getVM()), token, false,
false, false, true, args, genClass, genMethod);
// restore endOffset
offset = endOffset;
return cl;
}
static VMCommonClass* METHOD_ElementTypeTypedByRef(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::typedReference;
}
static VMCommonClass* METHOD_ElementTypeI(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pIntPtr;
}
static VMCommonClass* METHOD_ElementTypeU(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pUIntPtr;
}
static VMCommonClass* METHOD_ElementTypeFnptr(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("implement me");
return 0;
}
static VMCommonClass* METHOD_ElementTypeObject(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return MSCorlib::pObject;
}
static VMCommonClass* METHOD_ElementTypeSzarray(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMCommonClass* contains = ass->exploreType(offset, genClass, genMethod);
VMClassArray* res = ass->constructArray(contains, 1);
return res;
}
static VMCommonClass* METHOD_ElementTypeMvar(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod *currGenericMethod) {
uint32 number = ass->uncompressSignature(offset);
if (currGenericMethod == NULL) {
// when reading in signatures which contain references to generic arguments
// of generic methods we need create a placeholder for each of them,
// this is done by creating a dummy VMClass which has the assembly field
// set to NULL, the token field is used to store the generic argument number
VMClass* cl = new(ass->allocator, "VMClass") VMClass();
cl->token = number;
cl->assembly = ass;
cl->nameSpace = ass->name;
char *tmp = (char *) alloca(100);
snprintf(tmp, 100, "!!%d", number);
cl->name = VMThread::get()->getVM()->asciizToUTF8(tmp);
return cl;
} else {
return currGenericMethod->genericParams[number];
}
}
static VMCommonClass* METHOD_ElementTypeCmodReqd(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("implement me");
return 0;
}
static VMCommonClass* METHOD_ElementTypeCmodOpt(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("implement me");
return 0;
}
static VMCommonClass* METHOD_ElementTypeInternal(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("implement me");
return 0;
}
static VMCommonClass* METHOD_ElementTypeModifier(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("implement me");
return 0;
}
static VMCommonClass* METHOD_ElementTypeSentinel(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("implement me");
return 0;
}
static VMCommonClass* METHOD_ElementTypePinned(uint32 op, Assembly* ass,
uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
return 0;
}
static VMCommonClass* unimplemented(uint32 op, Assembly* ass, uint32& offset,
VMGenericClass* genClass, VMGenericMethod* genMethod) {
VMThread::get()->getVM()->error("unknown signature");
return 0;
}
signatureVector_t Assembly::signatureVector[0x46] = { METHOD_ElementTypeEnd, // 0x00
METHOD_ElementTypeVoid, // 0x01
METHOD_ElementTypeBoolean, // 0x02
METHOD_ElementTypeChar, // 0x03
METHOD_ElementTypeI1, // 0x04
METHOD_ElementTypeU1, // 0x05
METHOD_ElementTypeI2, // 0x06
METHOD_ElementTypeU2, // 0x07
METHOD_ElementTypeI4, // 0x08
METHOD_ElementTypeU4, // 0x09
METHOD_ElementTypeI8, // 0x0A
METHOD_ElementTypeU8, // 0x0B
METHOD_ElementTypeR4, // 0x0C
METHOD_ElementTypeR8, // 0x0D
METHOD_ElementTypeString, // 0x0E
METHOD_ElementTypePtr, // 0x1F
METHOD_ElementTypeByRef, // 0x10
METHOD_ElementTypeValueType, // 0x11
METHOD_ElementTypeClass, // 0x12
METHOD_ElementTypeVar, // 0x13
METHOD_ElementTypeArray, // 0x14
METHOD_ElementTypeGenericInst, // 0x15
METHOD_ElementTypeTypedByRef, // 0x16
unimplemented, // 0x17
METHOD_ElementTypeI, // 0x18
METHOD_ElementTypeU, // 0x19
unimplemented, // 0x1A
METHOD_ElementTypeFnptr, // 0x1B
METHOD_ElementTypeObject, // 0x1C
METHOD_ElementTypeSzarray, // 0x1D
METHOD_ElementTypeMvar, // 0x1E
METHOD_ElementTypeCmodReqd, // 0x1F
METHOD_ElementTypeCmodOpt, // 0x20
METHOD_ElementTypeInternal, // 0x21
METHOD_ElementTypeModifier, // 0x22
unimplemented, // 0x23
unimplemented, // 0x24
unimplemented, // 0x25
unimplemented, // 0x26
unimplemented, // 0x27
unimplemented, // 0x28
unimplemented, // 0x29
unimplemented, // 0x2A
unimplemented, // 0x2B
unimplemented, // 0x2C
unimplemented, // 0x2D
unimplemented, // 0x2E
unimplemented, // 0x2F
unimplemented, // 0x30
unimplemented, // 0x31
unimplemented, // 0x32
unimplemented, // 0x33
unimplemented, // 0x34
unimplemented, // 0x35
unimplemented, // 0x36
unimplemented, // 0x37
unimplemented, // 0x38
unimplemented, // 0x39
unimplemented, // 0x3A
unimplemented, // 0x3B
unimplemented, // 0x3C
unimplemented, // 0x3D
unimplemented, // 0x3E
unimplemented, // 0x3F
unimplemented, // 0x40
METHOD_ElementTypeSentinel, // 0x41
unimplemented, // 0x42
unimplemented, // 0x43
unimplemented, // 0x44
METHOD_ElementTypePinned // 0x45
};
bool Assembly::extractMethodSignature(uint32& offset, VMCommonClass* cl,
std::vector<VMCommonClass*>& types, VMGenericClass* genClass, VMGenericMethod* genMethod) {
//uint32 count =
uncompressSignature(offset);
uint32 call = uncompressSignature(offset);
if (call & CONSTANT_Generic) {
//uint32 genArgCount =
uncompressSignature(offset);
}
uint32 paramCount = uncompressSignature(offset);
uint32 hasThis = call & CONSTANT_HasThis ? 1 : 0;
uint32 realCount = paramCount + hasThis;
VMCommonClass* ret = exploreType(offset, genClass, genMethod);
types.push_back(ret);
if (hasThis) {
types.push_back(cl);
}
for (uint32 i = hasThis; i < realCount; ++i) {
VMCommonClass* cur = exploreType(offset, genClass, genMethod);
types.push_back(cur);
}
return hasThis != 0;
}
// checks whether the MethodDefSig at offset contains generic parameters
bool Assembly::isGenericMethod(uint32& offset) {
uncompressSignature(offset); // count
uint32 callingConvention = READ_U1(bytes, offset);
return callingConvention & CONSTANT_Generic ? true : false;
}
void Assembly::methodSpecSignature(uint32& offset,
std::vector<VMCommonClass*>& genArgs, VMGenericClass* genClass, VMGenericMethod* genMethod) {
uncompressSignature(offset); // count
uint32 genericSig = uncompressSignature(offset);
if (genericSig != 0x0a) {
VMThread::get()->getVM()->error("unknown methodSpec sig %x", genericSig);
}
uint32 genArgCount = uncompressSignature(offset);
for (uint32 i = 0; i < genArgCount; i++) {
genArgs.push_back(exploreType(offset, genClass, genMethod));
}
}
void Assembly::localVarSignature(uint32& offset,
std::vector<VMCommonClass*>& locals, VMGenericClass* genClass, VMGenericMethod* genMethod) {
//uint32 count =
uncompressSignature(offset);
uint32 localSig = uncompressSignature(offset);
uint32 nbLocals = uncompressSignature(offset);
if (localSig != 0x7) {
VMThread::get()->getVM()->error("unknown local sig %x", localSig);
}
for (uint32 i = 0; i < nbLocals; ++i) {
VMCommonClass* cl = exploreType(offset, genClass, genMethod);
if (!cl)
--i; // PINNED
else
locals.push_back(cl);
}
}
VMCommonClass* Assembly::extractFieldSignature(uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
//uint32 count =
uncompressSignature(offset);
uint32 fieldSig = uncompressSignature(offset);
if (fieldSig != 0x6) {
VMThread::get()->getVM()->error("unknown field sig %x", fieldSig);
}
// TODO implement support for custom modifiers
// see ECMA 335 23.2.4, 23.2.7
return exploreType(offset, genClass, genMethod);
}
VMCommonClass* Assembly::extractTypeInSignature(uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
//uint32 count =
uncompressSignature(offset);
return exploreType(offset, genClass, genMethod);
}
VMCommonClass* Assembly::exploreType(uint32& offset, VMGenericClass* genClass, VMGenericMethod* genMethod) {
uint32 op = READ_U1(bytes, offset);
assert(op < 0x46 && "unknown signature type");
return (signatureVector[op]) (op, this, offset, genClass, genMethod);
}
uint32 Assembly::uncompressSignature(uint32& offset) {
uint32 value = READ_U1(bytes, offset);
if ((value & 0x80) == 0) {
return value;
} else if ((value & 0x40) == 0) {
uint32 val2 = READ_U1(bytes, offset);
return (((value & 0x3f) << 8) | val2);
} else {
uint32 val2 = READ_U1(bytes, offset);
uint32 val3 = READ_U1(bytes, offset);
uint32 val4 = READ_U1(bytes, offset);
return ((value & 0x1f) << 24) | (val2 << 16) | (val3 << 8) | val4;
}
}