| //===--------- 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; |
| } |
| } |