static void method_jit_result (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) { if (result == MONO_PROFILE_OK) { int i; MonoDebugSourceLocation *sourceLoc; MonoDebugMethodJitInfo *dmji; MonoClass *klass = mono_method_get_class (method); char *signature = mono_signature_get_desc (mono_method_signature (method), TRUE); char *name = g_strdup_printf ("%s(%s)", mono_method_get_name (method), signature); char *classname = g_strdup_printf ("%s%s%s", mono_class_get_namespace (klass), mono_class_get_namespace (klass)[0] != 0 ? "::" : "", mono_class_get_name (klass)); gpointer code_start = mono_jit_info_get_code_start (jinfo); int code_size = mono_jit_info_get_code_size (jinfo); iJIT_Method_Load vtuneMethod; memset(&vtuneMethod, 0, sizeof(vtuneMethod)); vtuneMethod.method_id = iJIT_GetNewMethodID(); vtuneMethod.method_name = name; vtuneMethod.method_load_address = code_start; vtuneMethod.method_size = code_size; vtuneMethod.class_file_name = classname; dmji = mono_debug_find_method (method, mono_domain_get()); if (dmji != NULL) { vtuneMethod.line_number_size = dmji->num_line_numbers; vtuneMethod.line_number_table = (vtuneMethod.line_number_size != 0) ? (LineNumberInfo*)malloc(sizeof(LineNumberInfo) * vtuneMethod.line_number_size) : NULL; for (i = 0; i < dmji->num_line_numbers; ++i) { sourceLoc = mono_debug_lookup_source_location (method, dmji->line_numbers[i].native_offset, mono_domain_get()); if (sourceLoc == NULL) { g_free (vtuneMethod.line_number_table); vtuneMethod.line_number_table = NULL; vtuneMethod.line_number_size = 0; break; } if (i == 0) vtuneMethod.source_file_name = strdup(sourceLoc->source_file); vtuneMethod.line_number_table[i].Offset = dmji->line_numbers[i].native_offset; vtuneMethod.line_number_table[i].LineNumber = sourceLoc->row; mono_debug_free_source_location (sourceLoc); } mono_debug_free_method_jit_info (dmji); } iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &vtuneMethod); if (vtuneMethod.source_file_name != NULL) g_free (vtuneMethod.source_file_name); if (vtuneMethod.line_number_table != NULL) g_free (vtuneMethod.line_number_table); g_free (signature); g_free (name); g_free (classname); } }
void RegisterV(const void* base_address, u32 code_size, const char* format, va_list args) { #if !(defined USE_OPROFILE && USE_OPROFILE) && !defined(USE_VTUNE) if (!s_perf_map_file.IsOpen()) return; #endif std::string symbol_name = StringFromFormatV(format, args); #if defined USE_OPROFILE && USE_OPROFILE op_write_native_code(s_agent, symbol_name.data(), (u64)base_address, base_address, code_size); #endif #ifdef USE_VTUNE iJIT_Method_Load jmethod = {0}; jmethod.method_id = iJIT_GetNewMethodID(); jmethod.method_load_address = const_cast<void*>(base_address); jmethod.method_size = code_size; jmethod.method_name = const_cast<char*>(symbol_name.data()); iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod); #endif // Linux perf /tmp/perf-$pid.map: if (s_perf_map_file.IsOpen()) { std::string entry = StringFromFormat( "%llx %x %s\n", (u64)base_address, code_size, symbol_name.data()); s_perf_map_file.WriteBytes(entry.data(), entry.size()); } }
// // Unregister and notify VTune that even sampling is done. // void VTuneChakraProfile::UnRegister() { #if ENABLE_NATIVE_CODEGEN if(isJitProfilingActive) { iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL); } #endif }
int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int) { CPS2VM virtualMachine; CMainWindow MainWindow(virtualMachine); MainWindow.Loop(); #ifdef VTUNE_ENABLED iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL); #endif return 0; }
void JitBlockCache::FinalizeBlock(int block_num, bool block_link) { JitBlock &b = blocks_[block_num]; b.originalFirstOpcode = Memory::Read_Opcode_JIT(b.originalAddress); MIPSOpcode opcode = GetEmuHackOpForBlock(block_num); Memory::Write_Opcode_JIT(b.originalAddress, opcode); AddBlockMap(block_num); u32 latestExit = 0; if (block_link) { for (int i = 0; i < MAX_JIT_BLOCK_EXITS; i++) { if (b.exitAddress[i] != INVALID_EXIT) { links_to_.insert(std::make_pair(b.exitAddress[i], block_num)); latestExit = std::max(latestExit, b.exitAddress[i]); } } LinkBlock(block_num); LinkBlockExits(block_num); } if (Memory::IsScratchpadAddress(b.originalAddress)) { ExpandRange(blockMemRanges_[JITBLOCK_RANGE_SCRATCH], b.originalAddress, latestExit); } const u32 halfUserMemory = (PSP_GetUserMemoryEnd() - PSP_GetUserMemoryBase()) / 2; if (b.originalAddress < PSP_GetUserMemoryBase() + halfUserMemory) { ExpandRange(blockMemRanges_[JITBLOCK_RANGE_RAMBOTTOM], b.originalAddress, latestExit); } if (latestExit > PSP_GetUserMemoryBase() + halfUserMemory) { ExpandRange(blockMemRanges_[JITBLOCK_RANGE_RAMTOP], b.originalAddress, latestExit); } #if defined USE_OPROFILE && USE_OPROFILE char buf[100]; sprintf(buf, "EmuCode%x", b.originalAddress); const u8* blockStart = blocks_[block_num].checkedEntry; op_write_native_code(agent, buf, (uint64_t)blockStart, blockStart, b.normalEntry + b.codeSize - b.checkedEntry); #endif #ifdef USE_VTUNE sprintf(b.blockName, "EmuCode_0x%08x", b.originalAddress); iJIT_Method_Load jmethod = {0}; jmethod.method_id = iJIT_GetNewMethodID(); jmethod.class_file_name = ""; jmethod.source_file_name = __FILE__; jmethod.method_load_address = (void*)blocks_[block_num].checkedEntry; jmethod.method_size = b.normalEntry + b.codeSize - b.checkedEntry; jmethod.line_number_size = 0; jmethod.method_name = b.blockName; iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod); #endif }
void JitBlockCache::Shutdown() { delete [] blocks_; blocks_ = 0; num_blocks_ = 0; #if defined USE_OPROFILE && USE_OPROFILE op_close_agent(agent); #endif #ifdef USE_VTUNE iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL); #endif }
void Shutdown() { #if defined USE_OPROFILE && USE_OPROFILE op_close_agent(s_agent); s_agent = nullptr; #endif #ifdef USE_VTUNE iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, nullptr); #endif if (s_perf_map_file.IsOpen()) s_perf_map_file.Close(); }
void reportHelperToVtune(const char *name, void *start, void *end) { static unsigned int helperNumber = MIN_HELPER_ID; iJIT_Method_Load methodInfo; memset(&methodInfo, 0, sizeof(methodInfo)); assertx(helperNumber < MIN_METHOD_ID); methodInfo.method_id = helperNumber++; methodInfo.method_name = const_cast<char *>(name); methodInfo.method_load_address = start; methodInfo.method_size = (char*)end - (char*)start; iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void *)&methodInfo); }
void reportTrampolineToVtune(void* begin, size_t size) { iJIT_Method_Load methodInfo; memset(&methodInfo, 0, sizeof(methodInfo)); methodInfo.method_id = MIN_METHOD_ID; methodInfo.method_name = const_cast<char *>("Trampoline"); methodInfo.source_file_name = const_cast<char *>("Undefined"); // Report main body methodInfo.method_load_address = begin; methodInfo.method_size = size; methodInfo.line_number_size = 0; methodInfo.line_number_table = 0; iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void *)&methodInfo); }
static void code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBufferType type, void *data) { char *name; iJIT_Method_Load vtuneMethod; if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) name = g_strdup_printf ("code_buffer_specific_trampoline_%s", (char*) data); else name = (char*) code_buffer_desc (type); memset (&vtuneMethod, 0, sizeof (vtuneMethod)); vtuneMethod.method_id = iJIT_GetNewMethodID (); vtuneMethod.method_name = name; vtuneMethod.method_load_address = buffer; vtuneMethod.method_size = size; iJIT_NotifyEvent (iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &vtuneMethod); if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) { g_free (name); } }
// // Log loop body load event to VTune // void VTuneChakraProfile::LogLoopBodyLoadEvent(Js::FunctionBody* body, Js::LoopHeader* loopHeader, Js::LoopEntryPointInfo* entryPoint, uint16 loopNumber) { #if ENABLE_NATIVE_CODEGEN if (isJitProfilingActive) { iJIT_Method_Load methodInfo; memset(&methodInfo, 0, sizeof(iJIT_Method_Load)); const char16* methodName = body->GetExternalDisplayName(); size_t methodLength = wcslen(methodName); methodLength = min(methodLength, (size_t)UINT_MAX); // Just truncate if it is too big size_t length = methodLength * 3 + /* spaces */ 2 + _countof(LoopStr) + /*size of loop number*/ 10 + /*NULL*/ 1; utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length); if(utf8MethodName) { methodInfo.method_id = iJIT_GetNewMethodID(); size_t len = utf8::EncodeInto(utf8MethodName, methodName, (charcount_t)methodLength); sprintf_s((char*)(utf8MethodName + len), length - len," %s %d", LoopStr, loopNumber + 1); methodInfo.method_name = (char*)utf8MethodName; methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress(); methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact size_t urlLength = 0; utf8char_t* utf8Url = GetUrl(body, &urlLength); methodInfo.source_file_name = (char*)utf8Url; iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo); OUTPUT_TRACE(Js::ProfilerPhase, _u("Loop body load event: %s Loop %d\n"), methodName, loopNumber + 1); if(urlLength > 0) { HeapDeleteArray(urlLength, utf8Url); } HeapDeleteArray(length, utf8MethodName); } } #endif }
void CBasicBlock::Compile() { #ifndef AOT_USE_CACHE Framework::CMemStream stream; { static #ifdef AOT_BUILD_CACHE __declspec(thread) #endif CMipsJitter* jitter = nullptr; if(jitter == nullptr) { Jitter::CCodeGen* codeGen = Jitter::CreateCodeGen(); jitter = new CMipsJitter(codeGen); for(unsigned int i = 0; i < 4; i++) { jitter->SetVariableAsConstant( offsetof(CMIPS, m_State.nGPR[CMIPS::R0].nV[i]), 0); } } jitter->SetStream(&stream); jitter->Begin(); CompileRange(jitter); // codeGen.DumpVariables(0); // codeGen.EndQuota(); jitter->End(); } m_function = CMemoryFunction(stream.GetBuffer(), stream.GetSize()); #ifdef VTUNE_ENABLED if(iJIT_IsProfilingActive() == iJIT_SAMPLING_ON) { iJIT_Method_Load jmethod = {}; jmethod.method_id = iJIT_GetNewMethodID(); jmethod.class_file_name = ""; jmethod.source_file_name = __FILE__; jmethod.method_load_address = m_function.GetCode(); jmethod.method_size = m_function.GetSize(); jmethod.line_number_size = 0; auto functionName = string_format("BasicBlock_0x%08X_0x%08X", m_begin, m_end); jmethod.method_name = const_cast<char*>(functionName.c_str()); iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, reinterpret_cast<void*>(&jmethod)); } #endif #endif #ifdef AOT_ENABLED size_t blockSize = ((m_end - m_begin) / 4) + 1; auto blockData = new uint32[blockSize]; for(uint32 i = 0; i < blockSize; i++) { blockData[i] = m_context.m_pMemoryMap->GetWord(m_begin + (i * 4)); } uint32 blockChecksum = crc32(0, reinterpret_cast<Bytef*>(blockData), blockSize * 4); #endif #ifdef AOT_USE_CACHE AOT_BLOCK* blocksBegin = &_aot_firstBlock; AOT_BLOCK* blocksEnd = blocksBegin + _aot_blockCount; AOT_BLOCK blockRef = {blockChecksum, m_begin, m_end, nullptr}; static const auto blockComparer = [](const AOT_BLOCK& item1, const AOT_BLOCK& item2) { return item1.key < item2.key; }; // assert(std::is_sorted(blocksBegin, blocksEnd, blockComparer)); bool blockExists = std::binary_search(blocksBegin, blocksEnd, blockRef, blockComparer); auto blockIterator = std::lower_bound(blocksBegin, blocksEnd, blockRef, blockComparer); assert(blockExists); assert(blockIterator != blocksEnd); assert(blockIterator->key.crc == blockChecksum); assert(blockIterator->key.begin == m_begin); assert(blockIterator->key.end == m_end); m_function = reinterpret_cast<void (*)(void*)>(blockIterator->fct); #endif #ifdef AOT_BUILD_CACHE { std::lock_guard<std::mutex> lock(m_aotBlockOutputStreamMutex); m_aotBlockOutputStream->Write32(blockChecksum); m_aotBlockOutputStream->Write32(m_begin); m_aotBlockOutputStream->Write32(m_end); m_aotBlockOutputStream->Write(blockData, blockSize * 4); } #endif }
void reportTraceletToVtune(const Unit* unit, const Func* func, const TransRec& tr) { iJIT_Method_Load methodInfo; memset(&methodInfo, 0, sizeof(methodInfo)); if (!unit) return; methodInfo.method_id = tr.src.getFuncId() + MIN_METHOD_ID; if (func && func->fullName()) { methodInfo.method_name = const_cast<char *>(func->fullName()->data()); } else { methodInfo.method_name = const_cast<char *>("unknown"); } methodInfo.source_file_name = const_cast<char *>(unit->filepath()->data()); // aStart field of tr.bcmapping may point to cold range, so we need to // explicitly form mappings for main code and cold size_t bcSize = tr.bcMapping.size(); std::vector<LineNumberInfo> mainLineMap, coldLineMap; for (size_t i = 0; i < bcSize; i++) { LineNumberInfo info; info.LineNumber = unit->getLineNumber(tr.bcMapping[i].bcStart); // Note that main code may be generated in the cold code range (see // emitBlock in code-gen-x64 genCodeImpl()) so we need to explicitly check // the aStart value. if (tr.bcMapping[i].aStart >= tr.aStart && tr.bcMapping[i].aStart < tr.aStart + tr.aLen) { info.Offset = tr.bcMapping[i].aStart - tr.aStart; mainLineMap.push_back(info); } else if (tr.bcMapping[i].aStart >= tr.acoldStart && tr.bcMapping[i].aStart < tr.acoldStart + tr.acoldLen) { info.Offset = tr.bcMapping[i].aStart - tr.acoldStart; coldLineMap.push_back(info); } info.Offset = tr.bcMapping[i].acoldStart - tr.acoldStart; coldLineMap.push_back(info); } auto infoComp = [&](const LineNumberInfo& a, const LineNumberInfo& b) -> bool { return a.Offset < b.Offset; }; std::sort(mainLineMap.begin(), mainLineMap.end(), infoComp); std::sort(coldLineMap.begin(), coldLineMap.end(), infoComp); // Note that at this moment LineNumberInfo structures contain pairs of lines // and code offset for the start of the corresponding code, while JIT API // treats the offset as the end of this code (and the start offset is taken // from the previous element or is 0); need to shift the elements. Also, // attribute the prologue (code before the first byte in the mapping) to the // first line. auto shiftLineMap = [&](std::vector<LineNumberInfo>& lineMap, unsigned regionSize) { if (lineMap.size() > 0) { LineNumberInfo tmpInfo; tmpInfo.Offset = regionSize; tmpInfo.LineNumber = lineMap.back().LineNumber; lineMap.push_back(tmpInfo); for (size_t i = lineMap.size() - 2; i > 0; i--) { lineMap[i].LineNumber = lineMap[i - 1].LineNumber; } } }; shiftLineMap(mainLineMap, tr.aLen); shiftLineMap(coldLineMap, tr.acoldLen); // Report main body methodInfo.method_load_address = tr.aStart; methodInfo.method_size = tr.aLen; methodInfo.line_number_size = mainLineMap.size(); methodInfo.line_number_table = &mainLineMap[0]; iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void *)&methodInfo); // Report cold methodInfo.method_load_address = tr.acoldStart; methodInfo.method_size = tr.acoldLen; methodInfo.line_number_size = coldLineMap.size(); methodInfo.line_number_table = &coldLineMap[0]; iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void *)&methodInfo); }
void VTune_RegisterMethod(AvmCore* core, JITCodeInfo* inf) { // assume no method inlining so start/end of JIT code gen = method start/end uintptr startAt = inf->startAddr; uintptr endAt = inf->endAddr; uint32 methodSize = endAt - startAt; Stringp name = inf->method->format(core); int idx[4]; bool hasClass = locateNames(core, name, idx); // register the method iJIT_Method_Load ML; Stringp mname = name->substring(idx[2],idx[3]); VMPI_memset(&ML, 0, sizeof(iJIT_Method_Load)); ML.method_id = (inf->vtune) ? inf->vtune->method_id : iJIT_GetNewMethodID(); ML.method_name = string2char(core, mname); ML.method_load_address = (void *)startAt; // virtual address of that method - This determines the method range for the iJVM_EVENT_TYPE_ENTER/LEAVE_METHOD_ADDR events ML.method_size = methodSize; // Size in memory - Must be exact // md position / line number table SortedIntMap<LineNumberRecord*>* tbl = &inf->lineNumTable; int size = tbl->size(); LineNumberInfo* lines = 0; if (size) { int bsz = size*sizeof(LineNumberInfo); lines = (LineNumberInfo*) malloc(bsz); VMPI_memset(lines, 0, bsz); } String* fileName = 0; int at = 0; for(int i=0; i<size; i++) { sintptr mdPos = tbl->keyAt(i); LineNumberRecord* entry = tbl->at(i); if (entry->filename && entry->lineno) { if (!fileName) fileName = entry->filename; // @todo file name should be part of the lines[] record, no? lines[at].LineNumber = entry->lineno; lines[at].Offset = mdPos - startAt; at++; } } // @todo hack for vtune since it can't process multiple records with the same method name if (inf->sid>0 && at>0) { mname = core->concatStrings(mname,core->newString("_L")); mname = core->concatStrings(mname,core->intToString(lines[0].LineNumber)); mname = core->concatStrings(mname,core->newString("_")); mname = core->concatStrings(mname,core->intToString(inf->sid)); if (ML.method_name) free(ML.method_name); ML.method_name = string2char(core,mname); } ML.line_number_table = lines; // Pointer to the begining of the line numbers info array ML.line_number_size = at; // Line Table size in number of entries - Zero if none UTF8String* utf = ( fileName ) ? fileName->toUTF8String() : core->kEmptyString->toUTF8String(); ML.class_id = 0; // uniq class ID ML.class_file_name = (hasClass) ? string2char(core,name->substring(idx[0],idx[1])) : 0; // class file name ML.source_file_name = (char *)(malloc((utf->length()+3)*sizeof(char))); // +1 for \0 and +2 for wtoc's () wtoc(ML.source_file_name, utf->c_str(), 0); // source file name ML.user_data = NULL; // bits supplied by the user for saving in the JIT file... ML.user_data_size = 0; // the size of the user data buffer ML.env = iJDE_JittingAPI; // DumpVTuneMethodInfo(core, &ML); // Uncommented to debug VTune iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ML); if (inf->vtune && core->VTuneStatus == iJIT_CALLGRAPH_ON) { MMgc::GCHeap* heap = core->GetGC()->GetGCHeap(); heap->SetPageProtection(inf->vtune, sizeof (iJIT_Method_NIDS), false, true); } // free everything we alloc'd ( @todo did vtune really copy all the strings?!? ) if (ML.line_number_table) free(ML.line_number_table); if (ML.class_file_name && hasClass) free(ML.class_file_name); if (ML.method_name) free(ML.method_name); if (ML.source_file_name) free(ML.source_file_name); }
// // Log JIT method native load event to VTune // void VTuneChakraProfile::LogMethodNativeLoadEvent(Js::FunctionBody* body, Js::FunctionEntryPointInfo* entryPoint) { #if ENABLE_NATIVE_CODEGEN if (isJitProfilingActive) { iJIT_Method_Load methodInfo; memset(&methodInfo, 0, sizeof(iJIT_Method_Load)); const char16* methodName = body->GetExternalDisplayName(); // Append function line number info to method name so that VTune can distinguish between polymorphic methods char16 methodNameBuffer[_MAX_PATH]; ULONG lineNumber = body->GetLineNumber(); char16 numberBuffer[20]; _ltow_s(lineNumber, numberBuffer, 10); wcscpy_s(methodNameBuffer, methodName); if (entryPoint->GetJitMode() == ExecutionMode::SimpleJit) { wcscat_s(methodNameBuffer, _u(" Simple")); } wcscat_s(methodNameBuffer, _u(" {line:")); wcscat_s(methodNameBuffer, numberBuffer); wcscat_s(methodNameBuffer, _u("}")); size_t methodLength = wcslen(methodNameBuffer); Assert(methodLength < _MAX_PATH); size_t length = methodLength * 3 + 1; utf8char_t* utf8MethodName = HeapNewNoThrowArray(utf8char_t, length); if (utf8MethodName) { methodInfo.method_id = iJIT_GetNewMethodID(); utf8::EncodeIntoAndNullTerminate(utf8MethodName, methodNameBuffer, (charcount_t)methodLength); methodInfo.method_name = (char*)utf8MethodName; methodInfo.method_load_address = (void*)entryPoint->GetNativeAddress(); methodInfo.method_size = (uint)entryPoint->GetCodeSize(); // Size in memory - Must be exact LineNumberInfo numberInfo[1]; uint lineCount = (entryPoint->GetNativeOffsetMapCount()) * 2 + 1; // may need to record both .begin and .end for all elements LineNumberInfo* pLineInfo = HeapNewNoThrowArray(LineNumberInfo, lineCount); if (pLineInfo == NULL || Js::Configuration::Global.flags.DisableVTuneSourceLineInfo) { // resort to original implementation, attribute all samples to first line numberInfo[0].LineNumber = lineNumber; numberInfo[0].Offset = 0; methodInfo.line_number_size = 1; methodInfo.line_number_table = numberInfo; } else { int size = entryPoint->PopulateLineInfo(pLineInfo, body); methodInfo.line_number_size = size; methodInfo.line_number_table = pLineInfo; } size_t urlLength = 0; utf8char_t* utf8Url = GetUrl(body, &urlLength); methodInfo.source_file_name = (char*)utf8Url; OUTPUT_TRACE(Js::ProfilerPhase, _u("Method load event: %s\n"), methodNameBuffer); iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &methodInfo); HeapDeleteArray(lineCount, pLineInfo); if (urlLength > 0) { HeapDeleteArray(urlLength, utf8Url); } HeapDeleteArray(length, utf8MethodName); } } #endif }
/* called at the end of the program */ static void codeanalyst_shutdown (MonoProfiler *prof) { iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL); }