#include "BasicBlockSpliter.h" #include "../metadata/Opcodes.h" #include "../metadata/MetadataUtil.h" using namespace hybridclr::metadata; namespace hybridclr { namespace transform { void BasicBlockSpliter::SplitNormal(const byte* ilcodeStart, uint32_t codeSize, Uin32Set& ilOffsets) { const byte* codeEnd = ilcodeStart + codeSize; const byte* ip = ilcodeStart; while (ip < codeEnd) { ilOffsets.insert((uint32_t)(ip - ilcodeStart)); const OpCodeInfo* oc = DecodeOpCodeInfo(ip, codeEnd); IL2CPP_ASSERT(oc); int32_t opCodeSize = GetOpCodeSize(ip, oc); const byte* nextIp = ip + opCodeSize; int32_t nextOffset = (int32_t)(nextIp - ilcodeStart); IL2CPP_ASSERT(nextOffset >= 0 && nextOffset <= (int32_t)codeSize); switch (oc->inlineType) { case ArgType::None: case ArgType::Data: { break; } case ArgType::StaticBranch: { _splitOffsets.insert(nextOffset); break; } case ArgType::BranchTarget: { int32_t offset; switch (oc->inlineParam) { case 1: { offset = GetI1(ip + 1); break; } case 4: { offset = GetI4LittleEndian(ip + 1); break; } default: { RaiseExecutionEngineException("invalid BranchTarget param"); offset = -1; } } // don't split 0 offset br if (offset != 0 || (oc->baseOpValue == OpcodeValue::LEAVE || oc->baseOpValue == OpcodeValue::LEAVE_S)) { _splitOffsets.insert(nextOffset); _splitOffsets.insert(nextOffset + offset); } break; } case ArgType::Switch: { uint32_t caseNum = GetI4LittleEndian(ip + 1); bool splitAny = false; for (uint32_t caseIdx = 0; caseIdx < caseNum; caseIdx++) { int32_t caseOffset = GetI4LittleEndian(ip + 5 + caseIdx * 4); if (caseOffset != 0) { _splitOffsets.insert(nextOffset + caseOffset); splitAny = true; } } if (splitAny) { _splitOffsets.insert(nextOffset); } break; } default: { RaiseExecutionEngineException("unknown inline type"); nextOffset = -1; } } ip = nextIp; } IL2CPP_ASSERT(ip == codeEnd); } void BasicBlockSpliter::SplitExceptionHandles(const byte* ilcodeStart, uint32_t codeSize, const std::vector& exceptionClauses) { for (auto& eh : exceptionClauses) { _splitOffsets.insert(eh.tryOffset); _splitOffsets.insert(eh.tryOffset + eh.tryLength); _splitOffsets.insert(eh.handlerOffsets); _splitOffsets.insert(eh.handlerOffsets + eh.handlerLength); if (eh.flags == CorILExceptionClauseType::Filter) { _splitOffsets.insert(eh.classTokenOrFilterOffset); } } } void BasicBlockSpliter::SplitBasicBlocks() { const byte* ilcodeStart = _body.ilcodes; uint32_t codeSize = _body.codeSize; Uin32Set ilOffsets(codeSize); ilOffsets.insert(codeSize); SplitNormal(ilcodeStart, codeSize, ilOffsets); SplitExceptionHandles(ilcodeStart, codeSize, _body.exceptionClauses); /*if (_splitOffsets.find(0) != _splitOffsets.end()) { _splitOffsets.erase(0); }*/ #if DEBUG for (uint32_t offset : _splitOffsets) { IL2CPP_ASSERT(ilOffsets.find(offset) != ilOffsets.end()); } IL2CPP_ASSERT(_splitOffsets.find(codeSize) != _splitOffsets.end()); #endif } } }