LONG WINAPI PtokaX_UnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { static volatile LONG PermLock = 0; // When unhandled exception happen then permanently 'lock' here. We terminate after first exception. while(InterlockedExchange(&PermLock, 1) == 1) { ::Sleep(10); } // Set failure hook __pfnDliFailureHook2 = PtokaX_FailHook; // Check if we have debug symbols if(FileExist(sDebugSymbolsFile.c_str()) == false) { #ifdef _BUILD_GUI ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because file with debug symbols" " (PtokaX.pdb) is missing. If you know why this crash happen then please report it as bug to [email protected]!", "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because file with debug symbols" " (PtokaX.pdb) is missing. If you know why this crash happen then please report it as bug to [email protected]!"); #endif ExceptionHandlingUnitialize(); exit(EXIT_FAILURE); } // Initialize debug symbols SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES); if(SymInitialize(GetCurrentProcess(), PATH.c_str(), TRUE) == FALSE) { #ifdef _BUILD_GUI ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because initializatin of" " debug symbols failed. If you know why this crash happen then please report it as bug to [email protected]!", "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because initializatin of" " debug symbols failed. If you know why this crash happen then please report it as bug to [email protected]!"); #endif ExceptionHandlingUnitialize(); exit(EXIT_FAILURE); } // Generate crash log filename time_t acc_time; time(&acc_time); struct tm *tm = localtime(&acc_time); strftime(sDebugBuf, 128, "Crash-%d.%m.%Y-%H.%M.%S.log", tm); // Open crash file FILE * fw = fopen((sLogPath + sDebugBuf).c_str(), "w"); if(fw == NULL) { #ifdef _BUILD_GUI ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to create file with information why this crash happen." " If you know why this crash happen then please report it as bug to [email protected]!", "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to create file with information why this crash happen." " If you know why this crash happen then please report it as bug to [email protected]!"); #endif ExceptionHandlingUnitialize(); SymCleanup(GetCurrentProcess()); exit(EXIT_FAILURE); } string sCrashMsg = "Something bad happen and PtokaX crashed. PtokaX collected information why this crash happen to file "; sCrashMsg += string(sDebugBuf); sCrashMsg += ", please send that file to [email protected]!"; // Write PtokaX version, build and exception code fprintf(fw, "PtokaX version: " PtokaXVersionString " [build " BUILD_NUMBER "]" #ifdef _M_X64 " (x64)" #endif "\nException Code: %x\n", ExceptionInfo->ExceptionRecord->ExceptionCode); { // Write windoze version where we crashed if is possible OSVERSIONINFOEX ver; memset(&ver, 0, sizeof(OSVERSIONINFOEX)); ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if(GetVersionEx((OSVERSIONINFO*)&ver) != 0) { fprintf(fw, "Windows version: %d.%d SP: %d\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor); } } // Write date and time when crash happen strftime(sDebugBuf, 128, "Date and time: %d.%m.%Y %H:%M:%S\n\n", tm); fprintf(fw, sDebugBuf); STACKFRAME64 sf64CallStack; memset(&sf64CallStack, 0, sizeof(STACKFRAME64)); sf64CallStack.AddrPC.Mode = AddrModeFlat; sf64CallStack.AddrStack.Mode = AddrModeFlat; sf64CallStack.AddrFrame.Mode = AddrModeFlat; #ifdef _M_X64 sf64CallStack.AddrPC.Offset = ExceptionInfo->ContextRecord->Rip; sf64CallStack.AddrStack.Offset = ExceptionInfo->ContextRecord->Rsp; sf64CallStack.AddrFrame.Offset = ExceptionInfo->ContextRecord->Rbp; #else sf64CallStack.AddrPC.Offset = ExceptionInfo->ContextRecord->Eip; sf64CallStack.AddrStack.Offset = ExceptionInfo->ContextRecord->Esp; sf64CallStack.AddrFrame.Offset = ExceptionInfo->ContextRecord->Ebp; #endif // Write where crash happen fprintf(fw, "Exception location:\n"); GetSourceFileInfo(sf64CallStack.AddrPC.Offset, fw); GetFunctionInfo(sf64CallStack.AddrPC.Offset, fw); // Try to write callstack fprintf(fw, "\nCall stack:\n"); // We don't want it like never ending story, limit call stack to 100 lines for(uint32_t ui32i = 0; ui32i < 100; ui32i++) { if(StackWalk64( #ifdef _M_X64 IMAGE_FILE_MACHINE_AMD64, #else IMAGE_FILE_MACHINE_I386, #endif GetCurrentProcess(), GetCurrentThread(), &sf64CallStack, ExceptionInfo->ContextRecord, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL) == FALSE || sf64CallStack.AddrFrame.Offset == 0) { break; } GetSourceFileInfo(sf64CallStack.AddrPC.Offset, fw); GetFunctionInfo(sf64CallStack.AddrPC.Offset, fw); } fclose(fw); #ifdef _BUILD_GUI ::MessageBox(NULL, sCrashMsg.c_str(), "PtokaX crashed!", MB_OK | MB_ICONERROR); #else AppendLog(sCrashMsg.c_str()); #endif ExceptionHandlingUnitialize(); SymCleanup(GetCurrentProcess()); exit(EXIT_FAILURE); }
Js::FunctionInfo *InliningDecider::Inline(Js::FunctionBody *const inliner, Js::FunctionInfo* functionInfo, bool isConstructorCall, bool isPolymorphicCall, uint16 constantArgInfo, Js::ProfileId callSiteId, uint recursiveInlineDepth, bool allowRecursiveInlining) { #if defined(DBG_DUMP) || defined(ENABLE_DEBUG_CONFIG_OPTIONS) char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]; char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]; #endif Js::FunctionProxy * proxy = functionInfo->GetFunctionProxy(); if (proxy && proxy->IsFunctionBody()) { if (isLoopBody && PHASE_OFF(Js::InlineInJitLoopBodyPhase, this->topFunc)) { INLINE_TESTTRACE_VERBOSE(_u("INLINING: Skip Inline: Jit loop body: %s (%s)\n"), this->topFunc->GetDisplayName(), this->topFunc->GetDebugNumberSet(debugStringBuffer)); return nullptr; } // Note: disable inline for debugger, as we can't bailout at return from function. // Alternative can be generate this bailout as part of inline, which can be done later as perf improvement. const auto inlinee = proxy->GetFunctionBody(); Assert(this->jitMode == ExecutionMode::FullJit); if (PHASE_OFF(Js::InlinePhase, inlinee) || PHASE_OFF(Js::GlobOptPhase, inlinee) || !ContinueInliningUserDefinedFunctions(this->bytecodeInlinedCount) || this->isInDebugMode) { return nullptr; } if (functionInfo->IsDeferred() || inlinee->GetByteCode() == nullptr) { // DeferredParse... INLINE_TESTTRACE(_u("INLINING: Skip Inline: No bytecode\tInlinee: %s (%s)\tCaller: %s (%s)\n"), inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2)); return nullptr; } #ifdef _M_IX86 if (inlinee->GetHasTry()) { INLINE_TESTTRACE(_u("INLINING: Skip Inline: Has try\tInlinee: %s (%s)\tCaller: %s (%s)\n"), inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2)); return nullptr; } #endif // This is a hard limit as the argOuts array is statically sized. if (inlinee->GetInParamsCount() > Js::InlineeCallInfo::MaxInlineeArgoutCount) { INLINE_TESTTRACE(_u("INLINING: Skip Inline: Params count greater then MaxInlineeArgoutCount\tInlinee: %s (%s)\tParamcount: %d\tMaxInlineeArgoutCount: %d\tCaller: %s (%s)\n"), inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetInParamsCount(), Js::InlineeCallInfo::MaxInlineeArgoutCount, inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2)); return nullptr; } // Wasm functions can have no params if (inlinee->GetInParamsCount() == 0 && !inlinee->GetIsAsmjsMode()) { // Inline candidate has no params, not even a this pointer. This can only be the global function, // which we shouldn't inline. INLINE_TESTTRACE(_u("INLINING: Skip Inline: Params count is zero!\tInlinee: %s (%s)\tParamcount: %d\tCaller: %s (%s)\n"), inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetInParamsCount(), inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2)); return nullptr; } if (inlinee->GetDontInline()) { INLINE_TESTTRACE(_u("INLINING: Skip Inline: Do not inline\tInlinee: %s (%s)\tCaller: %s (%s)\n"), inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2)); return nullptr; } // Do not inline a call to a class constructor if it isn't part of a new expression since the call will throw a TypeError anyway. if (inlinee->IsClassConstructor() && !isConstructorCall) { INLINE_TESTTRACE(_u("INLINING: Skip Inline: Class constructor without new keyword\tInlinee: %s (%s)\tCaller: %s (%s)\n"), inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2)); return nullptr; } if (!DeciderInlineIntoInliner(inlinee, inliner, isConstructorCall, isPolymorphicCall, constantArgInfo, recursiveInlineDepth, allowRecursiveInlining)) { return nullptr; } #if defined(ENABLE_DEBUG_CONFIG_OPTIONS) TraceInlining(inliner, inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetByteCodeCount(), this->topFunc, this->bytecodeInlinedCount, inlinee, callSiteId, this->isLoopBody); #endif this->bytecodeInlinedCount += inlinee->GetByteCodeCount(); return inlinee->GetFunctionInfo(); } Js::OpCode builtInInlineCandidateOpCode; ValueType builtInReturnType; GetBuiltInInfo(functionInfo, &builtInInlineCandidateOpCode, &builtInReturnType); if(builtInInlineCandidateOpCode == 0 && builtInReturnType.IsUninitialized()) { return nullptr; } Assert(this->jitMode == ExecutionMode::FullJit); if (builtInInlineCandidateOpCode != 0 && ( PHASE_OFF(Js::InlinePhase, inliner) || PHASE_OFF(Js::GlobOptPhase, inliner) || isConstructorCall )) { return nullptr; } // Note: for built-ins at this time we don't have enough data (the instr) to decide whether it's going to be inlined. return functionInfo; }