Internal.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. #pragma warning(disable:4996)
  2. #define HEAPHOOK
  3. //#define USE_CHARCONV
  4. #include <stdio.h>
  5. //#include <crtdefs.h>
  6. //#include <malloc.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. //#include <intrin.h>
  10. #ifdef USE_CHARCONV
  11. #include <charconv>
  12. #endif
  13. //#define OBJECT_GUARD_END_SIZE 8
  14. #define OBJECT_GUARD_END_SIZE 0
  15. //#define BF_USE_STOMP_ALLOC 1
  16. //extern "C"
  17. //{
  18. //#include "gperftools/stacktrace.h"
  19. //}
  20. #ifdef _MSC_VER
  21. #include <intrin.h>
  22. #pragma intrinsic(_ReturnAddress)
  23. #define BF_RETURN_ADDRESS _ReturnAddress()
  24. #else
  25. #define BF_RETURN_ADDRESS __builtin_return_address(0)
  26. #endif
  27. #include "BeefySysLib/Common.h"
  28. #include "BfObjects.h"
  29. //#include "gc.h"
  30. #include "StompAlloc.h"
  31. #include "BeefySysLib/platform/PlatformHelper.h"
  32. #ifndef BF_DISABLE_FFI
  33. #include "ffi.h"
  34. #endif
  35. #include "Thread.h"
  36. #ifdef BF_PLATFORM_WINDOWS
  37. #include <fcntl.h>
  38. #include <io.h>
  39. #endif
  40. USING_NS_BF;
  41. static Beefy::StringT<0> gCmdLineString;
  42. bool gCmdLineStringHandled;
  43. bf::System::Runtime::BfRtCallbacks gBfRtCallbacks;
  44. BfRtFlags gBfRtFlags = (BfRtFlags)0;
  45. #ifdef BF_PLATFORM_WINDOWS
  46. DWORD gBfTLSKey = 0;
  47. #else
  48. pthread_key_t gBfTLSKey = 0;
  49. #endif
  50. static int gTestMethodIdx = -1;
  51. static uint32 gTestStartTick = 0;
  52. static bool gTestBreakOnFailure = false;
  53. typedef void(*ClientPipeErrorFunc)(const Beefy::StringView& error, int stackOffset);
  54. static BfpFile* gClientPipe = NULL;
  55. static ClientPipeErrorFunc gClientPipeErrorFunc;
  56. static Beefy::String gTestInBuffer;
  57. namespace bf
  58. {
  59. namespace System
  60. {
  61. class Object;
  62. class Exception;
  63. //System::Threading::Thread* gMainThread;
  64. class Internal
  65. {
  66. private:
  67. BFRT_EXPORT static void __BfStaticCtor();
  68. BFRT_EXPORT static void __BfStaticDtor();
  69. BFRT_EXPORT static void BfStaticCtor();
  70. BFRT_EXPORT static void BfStaticDtor();
  71. BFRT_EXPORT static void Shutdown_Internal();
  72. public:
  73. BFRT_EXPORT static Object* UnsafeCastToObject(void* inPtr);
  74. BFRT_EXPORT static void* UnsafeCastToPtr(Object* obj);
  75. BFRT_EXPORT static void ObjectDynCheck(Object* object, int typeId, bool allowNull);
  76. BFRT_EXPORT static void ObjectDynCheckFailed(Object* object, int typeId);
  77. BFRT_EXPORT static void ThrowIndexOutOfRange(intptr stackOffset);
  78. BFRT_EXPORT static void ThrowObjectNotInitialized(intptr stackOffset);
  79. BFRT_EXPORT static void FatalError(String* error, intptr stackOffset = 0);
  80. BFRT_EXPORT static void MemCpy(void* dest, void* src, intptr length);
  81. BFRT_EXPORT static void MemMove(void* dest, void* src, intptr length);
  82. BFRT_EXPORT static void MemSet(void* addr, uint8 val, intptr length);
  83. BFRT_EXPORT static int CStrLen(char* charPtr);
  84. BFRT_EXPORT static void* Malloc(intptr length);
  85. BFRT_EXPORT static void Free(void* ptr);
  86. BFRT_EXPORT static void* VirtualAlloc(intptr size, bool canExecute, bool canWrite);
  87. BFRT_EXPORT static int64 GetTickCountMicro();
  88. BFRT_EXPORT static void BfDelegateTargetCheck(void* target);
  89. BFRT_EXPORT static void* LoadSharedLibrary(char* filePath);
  90. BFRT_EXPORT static void LoadSharedLibraryInto(char* filePath, void** libDest);
  91. BFRT_EXPORT static void* GetSharedProcAddress(void* libHandle, char* procName);
  92. BFRT_EXPORT static void GetSharedProcAddressInto(void* libHandle, char* procName, void** procDest);
  93. BFRT_EXPORT static char* GetCommandLineArgs();
  94. BFRT_EXPORT static void BfLog(char* str);
  95. BFRT_EXPORT static void ProfilerCmd(char* str);
  96. BFRT_EXPORT static void ReportMemory();
  97. private:
  98. BFRT_EXPORT static void Test_Init(char* testData);
  99. BFRT_EXPORT static void Test_Error(char* error);
  100. BFRT_EXPORT static void Test_Write(char* str);
  101. BFRT_EXPORT static int32 Test_Query();
  102. BFRT_EXPORT static void Test_Finish();
  103. };
  104. namespace IO
  105. {
  106. class File
  107. {
  108. private:
  109. BFRT_EXPORT static bool Exists(char* fileName);
  110. };
  111. class Directory
  112. {
  113. private:
  114. BFRT_EXPORT static bool Exists(char* fileName);
  115. };
  116. }
  117. namespace Diagnostics
  118. {
  119. namespace Contracts
  120. {
  121. class Contract
  122. {
  123. public:
  124. enum ContractFailureKind : uint8
  125. {
  126. ContractFailureKind_Precondition,
  127. //[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Postcondition")]
  128. ContractFailureKind_Postcondition,
  129. //[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Postcondition")]
  130. ContractFailureKind_PostconditionOnException,
  131. ContractFailureKind_Invariant,
  132. ContractFailureKind_Assert,
  133. ContractFailureKind_Assume,
  134. };
  135. private:
  136. BFRT_EXPORT static void ReportFailure(ContractFailureKind failureKind, char* userMessage, int userMessageLen, char* conditionText, int conditionTextLen);
  137. };
  138. }
  139. class Debug
  140. {
  141. private:
  142. BFRT_EXPORT static void Write(char* str, intptr strLen);
  143. };
  144. }
  145. namespace FFI
  146. {
  147. enum FFIABI : int32;
  148. enum FFIResult : int32;
  149. struct FFIType;
  150. struct FFILIB
  151. {
  152. struct FFICIF;
  153. BFRT_EXPORT static void* ClosureAlloc(intptr size, void** outFunc);
  154. BFRT_EXPORT static FFIResult PrepCif(FFICIF* cif, FFIABI abi, int32 nargs, FFIType* rtype, FFIType** argTypes);
  155. BFRT_EXPORT static void Call(FFICIF* cif, void* funcPtr, void* rvalue, void** args);
  156. };
  157. }
  158. struct Float
  159. {
  160. private:
  161. BFRT_EXPORT static int ToString(float f, char* outStr, bool roundTrip);
  162. };
  163. struct Double
  164. {
  165. private:
  166. BFRT_EXPORT static int ToString(double f, char* outStr, bool roundTrip);
  167. };
  168. }
  169. }
  170. //#define BF_TRACK_SIZES 1
  171. #if BF_TRACK_SIZES
  172. static int sAllocSizes[1024*1024];
  173. static int sHighestId = 0;
  174. #endif
  175. using namespace bf::System;
  176. #ifndef BF_PLATFORM_WINDOWS
  177. bool IsDebuggerPresent()
  178. {
  179. return false;
  180. }
  181. #endif
  182. static void TestString(const StringImpl& str);
  183. static void TestReadCmd(Beefy::String& str);
  184. static void Internal_FatalError(const char* error)
  185. {
  186. if (gBfRtCallbacks.CheckErrorHandler != NULL)
  187. gBfRtCallbacks.CheckErrorHandler("FatalError", error, NULL, 0);
  188. if (gClientPipeErrorFunc != NULL)
  189. gClientPipeErrorFunc(error, 0);
  190. else
  191. BfpSystem_FatalError(error, "BEEF FATAL ERROR");
  192. }
  193. extern "C" BFRT_EXPORT int BF_CALLTYPE ftoa(float val, char* str)
  194. {
  195. return sprintf(str, "%1.9f", val);
  196. }
  197. /*static void* MallocHook(size_t size, const void *caller)
  198. {
  199. printf("MallocHook\n");
  200. return NULL;
  201. }*/
  202. /*static int __cdecl HeapHook(int a, size_t b, void* c, void** d)
  203. {
  204. printf("Heap Hook\n");
  205. return 0;
  206. }*/
  207. //////////////////////////////////////////////////////////////////////////
  208. //static Beefy::StringT<0> gErrorString;
  209. static const char* volatile gErrorString = NULL;
  210. void SetErrorString(const char* str)
  211. {
  212. char* newStr = strdup(str);
  213. while (true)
  214. {
  215. const char* prevStr = gErrorString;
  216. auto result = (void*)BfpSystem_InterlockedCompareExchangePtr((uintptr*)&gErrorString, (uintptr)prevStr, (uintptr)newStr);
  217. if (result != prevStr)
  218. continue;
  219. if (prevStr != NULL)
  220. free((void*)prevStr);
  221. break;
  222. }
  223. }
  224. #define SETUP_ERROR(str, skip) SetErrorString(str); gBfRtCallbacks.DebugMessageData_SetupError(str, skip)
  225. static void GetCrashInfo()
  226. {
  227. auto errorString = gErrorString;
  228. if (errorString != NULL)
  229. {
  230. Beefy::String debugStr;
  231. debugStr += "Beef Error: ";
  232. debugStr += (const char*)errorString;
  233. BfpSystem_AddCrashInfo(debugStr.c_str());
  234. }
  235. }
  236. static void NTAPI TlsFreeFunc(void* ptr)
  237. {
  238. gBfRtCallbacks.Thread_Exiting();
  239. }
  240. void bf::System::Console::PutChars(char* ptr, int len)
  241. {
  242. #ifdef BF_PLATFORM_WINDOWS
  243. HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
  244. if (handle != INVALID_HANDLE_VALUE)
  245. {
  246. DWORD numBytesWritten = 0;
  247. ::WriteFile(handle, ptr, (DWORD)len, &numBytesWritten, NULL);
  248. return;
  249. }
  250. #endif
  251. for (int i = 0; i < len; i++)
  252. putchar(ptr[i]);
  253. fflush(stdout);
  254. }
  255. void bf::System::Console::ReopenHandles()
  256. {
  257. #ifdef _MSC_VER
  258. FILE* fDummy;
  259. freopen_s(&fDummy, "CONOUT$", "w", stdout);
  260. freopen_s(&fDummy, "CONOUT$", "w", stderr);
  261. freopen_s(&fDummy, "CONIN$", "r", stdin);
  262. //
  263. // // std::wcout, std::wclog, std::wcerr, std::wcin
  264. HANDLE hConOut = CreateFileA("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  265. HANDLE hConIn = CreateFileA("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  266. SetStdHandle(STD_OUTPUT_HANDLE, hConOut);
  267. SetStdHandle(STD_ERROR_HANDLE, hConOut);
  268. SetStdHandle(STD_INPUT_HANDLE, hConIn);
  269. #endif
  270. }
  271. void bf::System::Runtime::Init(int version, int flags, BfRtCallbacks* callbacks)
  272. {
  273. BfpSystemInitFlags sysInitFlags = BfpSystemInitFlag_InstallCrashCatcher;
  274. if ((flags & 4) != 0)
  275. sysInitFlags = (BfpSystemInitFlags)(sysInitFlags | BfpSystemInitFlag_SilentCrash);
  276. BfpSystem_Init(BFP_VERSION, sysInitFlags);
  277. if (gBfRtCallbacks.Alloc != NULL)
  278. {
  279. Internal_FatalError("BeefRT already initialized. Multiple executable modules in the same process cannot dynamically link to the Beef runtime.");
  280. }
  281. if (version != BFRT_VERSION)
  282. {
  283. char error[256];
  284. sprintf(error, "BeefRT build version '%d' does not match requested version '%d'", BFRT_VERSION, version);
  285. BfpSystem_FatalError(error, "BEEF FATAL ERROR");
  286. }
  287. gBfRtCallbacks = *callbacks;
  288. gBfRtFlags = (BfRtFlags)flags;
  289. #ifdef BF_PLATFORM_WINDOWS
  290. gBfTLSKey = FlsAlloc(TlsFreeFunc);
  291. #else
  292. pthread_key_create(&gBfTLSKey, TlsFreeFunc);
  293. #endif
  294. }
  295. void bf::System::Runtime::InitCrashCatcher(int flags)
  296. {
  297. BfpSystemInitFlags sysInitFlags = BfpSystemInitFlag_InstallCrashCatcher;
  298. if ((flags & 4) != 0)
  299. sysInitFlags = (BfpSystemInitFlags)(sysInitFlags | BfpSystemInitFlag_SilentCrash);
  300. BfpSystem_InitCrashCatcher(sysInitFlags);
  301. BfpSystem_AddCrashInfoFunc(GetCrashInfo);
  302. }
  303. void bf::System::Runtime::ShutdownCrashCatcher()
  304. {
  305. BfpSystem_ShutdownCrashCatcher();
  306. }
  307. void bf::System::Runtime::SetErrorString(char* errorStr)
  308. {
  309. ::SetErrorString(errorStr);
  310. }
  311. void bf::System::Runtime::AddCrashInfoFunc(void* func)
  312. {
  313. BfpSystem_AddCrashInfoFunc(*(BfpCrashInfoFunc*)&func);
  314. }
  315. void bf::System::Runtime::SetCrashReportKind(bf::System::Runtime::RtCrashReportKind crashReportKind)
  316. {
  317. BfpSystem_SetCrashReportKind((BfpCrashReportKind)crashReportKind);
  318. }
  319. //////////////////////////////////////////////////////////////////////////
  320. void Internal::Shutdown_Internal()
  321. {
  322. BfInternalThread::WaitForAllDone();
  323. if (gBfRtCallbacks.GC_Shutdown != NULL)
  324. gBfRtCallbacks.GC_Shutdown();
  325. BfpSystem_Shutdown();
  326. }
  327. void Internal::BfStaticCtor()
  328. {
  329. __BfStaticCtor();
  330. }
  331. void Internal::__BfStaticCtor()
  332. {
  333. }
  334. void Internal::BfStaticDtor()
  335. {
  336. }
  337. void Internal::__BfStaticDtor()
  338. {
  339. }
  340. Object* Internal::UnsafeCastToObject(void* inPtr)
  341. {
  342. return (Object*)inPtr;
  343. }
  344. void* Internal::UnsafeCastToPtr(Object* obj)
  345. {
  346. return (void*)obj;
  347. }
  348. void Internal::ThrowIndexOutOfRange(intptr stackOffset)
  349. {
  350. if (gClientPipeErrorFunc != NULL)
  351. gClientPipeErrorFunc("Index out of range", 0);
  352. else if ((stackOffset != -1) && (::IsDebuggerPresent()))
  353. {
  354. SETUP_ERROR("Index out of range", (int)(2 + stackOffset));
  355. BF_DEBUG_BREAK();
  356. }
  357. Internal_FatalError("Index out of range");
  358. }
  359. void Internal::ThrowObjectNotInitialized(intptr stackOffset)
  360. {
  361. if (gClientPipeErrorFunc != NULL)
  362. gClientPipeErrorFunc("Object not initialized", 0);
  363. else if ((stackOffset != -1) && (::IsDebuggerPresent()))
  364. {
  365. SETUP_ERROR("Object not initialized", (int)(2 + stackOffset));
  366. BF_DEBUG_BREAK();
  367. }
  368. Internal_FatalError("Object not initialized");
  369. }
  370. void Internal::FatalError(bf::System::String* error, intptr stackOffset)
  371. {
  372. Beefy::StringView errorStringView = error->ToStringView();
  373. Beefy::StringSimple errorString = errorStringView;
  374. if (gClientPipeErrorFunc != NULL)
  375. gClientPipeErrorFunc(errorStringView, 0);
  376. if ((stackOffset != -1) && (::IsDebuggerPresent()))
  377. {
  378. SETUP_ERROR(errorString.c_str(), (int)(2 + stackOffset));
  379. BF_DEBUG_BREAK();
  380. }
  381. Internal_FatalError(errorString.c_str());
  382. }
  383. void Internal::MemCpy(void* dest, void* src, intptr length)
  384. {
  385. memcpy(dest, src, length);
  386. }
  387. void Internal::MemMove(void* dest, void* src, intptr length)
  388. {
  389. memmove(dest, src, length);
  390. }
  391. void Internal::MemSet(void* addr, uint8 val, intptr length)
  392. {
  393. memset(addr, val, length);
  394. }
  395. int Internal::CStrLen(char* charPtr)
  396. {
  397. return (int)strlen(charPtr);
  398. }
  399. void* Internal::Malloc(intptr length)
  400. {
  401. #if BF_USE_STOMP_ALLOC
  402. return StompAlloc(length);
  403. #elif BF_TRACK_SIZES
  404. uint8* allocPtr = (uint8*)malloc(length + 16);
  405. *((int*)allocPtr) = length;
  406. sAllocSizes[0] += length;
  407. return allocPtr + 16;
  408. #else
  409. return malloc(length);
  410. #endif
  411. }
  412. void* Internal::VirtualAlloc(intptr size, bool canExecute, bool canWrite)
  413. {
  414. #ifdef BF_PLATFORM_WINDOWS
  415. OutputDebugStrF("Performing VirtualAlloc: %d %d %d\n", size, canExecute, canWrite);
  416. int prot = PAGE_READWRITE;
  417. if (canExecute && canWrite)
  418. prot = PAGE_EXECUTE_READWRITE;
  419. else if (canExecute)
  420. prot = PAGE_EXECUTE_READ;
  421. void* ptr = ::VirtualAlloc(NULL, size, MEM_RESERVE, prot);
  422. return ptr;
  423. #else
  424. BF_FATAL("Not supported");
  425. return NULL;
  426. #endif
  427. }
  428. void Internal::Free(void* ptr)
  429. {
  430. #if BF_USE_STOMP_ALLOC
  431. StompFree(ptr);
  432. #elif BF_TRACK_SIZES
  433. uint8* allocPtr = ((uint8*)ptr) - 16;
  434. sAllocSizes[0] -= *((int*)allocPtr);
  435. free(allocPtr);
  436. #else
  437. free(ptr);
  438. #endif
  439. }
  440. BFRT_EXPORT int64 Internal::GetTickCountMicro()
  441. {
  442. return BFGetTickCountMicro();
  443. }
  444. void Internal::BfDelegateTargetCheck(void* target)
  445. {
  446. if (target != NULL)
  447. {
  448. SETUP_ERROR("Attempting pass non-static method reference to extern method", 2);
  449. BF_DEBUG_BREAK();
  450. gBfRtCallbacks.DebugMessageData_Fatal();
  451. }
  452. }
  453. void* Internal::LoadSharedLibrary(char* libName)
  454. {
  455. //::MessageBox(NULL, "Hey", "Dude", 0);
  456. void* libHandle = BfpDynLib_Load(libName);
  457. if (libHandle == NULL)
  458. {
  459. if (gBfRtCallbacks.CheckErrorHandler != NULL)
  460. {
  461. if (gBfRtCallbacks.CheckErrorHandler("LoadSharedLibrary", libName, NULL, 0) == 1)
  462. return NULL;
  463. }
  464. Beefy::String errorStr = StrFormat("Failed to load shared library: %s", libName);
  465. SETUP_ERROR(errorStr.c_str(), 1);
  466. BF_DEBUG_BREAK();
  467. gBfRtCallbacks.DebugMessageData_Fatal();
  468. }
  469. return libHandle;
  470. }
  471. void Internal::LoadSharedLibraryInto(char* libName, void** libDest)
  472. {
  473. if (*libDest == NULL)
  474. *libDest = LoadSharedLibrary(libName);
  475. }
  476. void* Internal::GetSharedProcAddress(void* libHandle, char* procName)
  477. {
  478. if (libHandle == NULL)
  479. return NULL;
  480. void* procAddr = BfpDynLib_GetProcAddress((BfpDynLib*)libHandle, procName);
  481. if (procAddr == NULL)
  482. {
  483. char libFileName[4096];
  484. int libFileNameLen = 4096;
  485. BfpDynLib_GetFilePath((BfpDynLib*)libHandle, libFileName, &libFileNameLen, NULL);
  486. if (gBfRtCallbacks.CheckErrorHandler != NULL)
  487. {
  488. if (gBfRtCallbacks.CheckErrorHandler("GetSharedProcAddress", libFileName, procName, 0) == 1)
  489. return NULL;
  490. }
  491. Beefy::String errorStr = StrFormat("Failed to load shared procedure '%s' from '%s'", procName, libFileName);
  492. SETUP_ERROR(errorStr.c_str(), 1);
  493. BF_DEBUG_BREAK();
  494. gBfRtCallbacks.DebugMessageData_Fatal();
  495. }
  496. return procAddr;
  497. }
  498. void Internal::GetSharedProcAddressInto(void* libHandle, char* procName, void** procDest)
  499. {
  500. *procDest = GetSharedProcAddress(libHandle, procName);
  501. }
  502. char* Internal::GetCommandLineArgs()
  503. {
  504. if (!gCmdLineStringHandled)
  505. {
  506. Beefy::String cmdLine;
  507. BfpSystemResult result;
  508. BFP_GETSTR_HELPER(cmdLine, result, BfpSystem_GetCommandLine(__STR, __STRLEN, &result));
  509. char* cmdLineStr = (char*)cmdLine.c_str();
  510. //::MessageBoxA(NULL, cmdLineStr, "BFRT", 0);
  511. char* useCmdLineStr = cmdLineStr;
  512. if (cmdLineStr[0] != 0)
  513. {
  514. bool nameQuoted = cmdLineStr[0] == '\"';
  515. Beefy::String passedName;
  516. int i;
  517. for (i = (nameQuoted ? 1 : 0); cmdLineStr[i] != 0; i++)
  518. {
  519. wchar_t c = cmdLineStr[i];
  520. if (((nameQuoted) && (c == '"')) ||
  521. ((!nameQuoted) && (c == ' ')))
  522. {
  523. i++;
  524. break;
  525. }
  526. passedName += cmdLineStr[i];
  527. }
  528. useCmdLineStr += i;
  529. while (*useCmdLineStr == L' ')
  530. useCmdLineStr++;
  531. }
  532. gCmdLineString = useCmdLineStr;
  533. gCmdLineStringHandled = true;
  534. }
  535. return (char*)gCmdLineString.c_str();
  536. }
  537. void Internal::BfLog(char* str)
  538. {
  539. // static int lineNum = 0;
  540. // lineNum++;
  541. //
  542. // static FILE* fp = fopen("dbg_internal.txt", "wb");
  543. //
  544. // Beefy::String aResult = StrFormat("%d ", lineNum) + str;
  545. // fwrite(aResult.c_str(), 1, aResult.length(), fp);
  546. // fflush(fp);
  547. }
  548. void Internal::ProfilerCmd(char* str)
  549. {
  550. if (!::IsDebuggerPresent())
  551. return;
  552. gBfRtCallbacks.DebugMessageData_SetupProfilerCmd(str);
  553. BF_DEBUG_BREAK();
  554. }
  555. void Internal::ReportMemory()
  556. {
  557. int totalMem = 0;
  558. #if BF_TRACK_SIZES
  559. for (int i = 0; i <= sHighestId; i++)
  560. totalMem += sAllocSizes[i];
  561. OutputDebugStrF("Beef Object Memory: %dk\n", totalMem / 1024);
  562. #endif
  563. }
  564. static void TestString(const StringImpl& str)
  565. {
  566. BfpFileResult fileResult;
  567. BfpFile_Write(gClientPipe, str.c_str(), str.length(), -1, &fileResult);
  568. BF_ASSERT_REL(fileResult == BfpFileResult_Ok);
  569. }
  570. static void TestReadCmd(Beefy::String& str)
  571. {
  572. while (true)
  573. {
  574. int crPos = (int)gTestInBuffer.IndexOf('\n');
  575. if (crPos != -1)
  576. {
  577. str = gTestInBuffer.Substring(0, crPos);
  578. gTestInBuffer.Remove(0, crPos + 1);
  579. return;
  580. }
  581. char data[1024];
  582. BfpFileResult fileResult;
  583. int readSize = (int)BfpFile_Read(gClientPipe, data, 1024, -1, &fileResult);
  584. if ((fileResult == BfpFileResult_Ok) || (fileResult == BfpFileResult_PartialData))
  585. {
  586. gTestInBuffer.Append(data, readSize);
  587. }
  588. else
  589. {
  590. BF_FATAL("Failed to read pipe to test manager");
  591. }
  592. }
  593. }
  594. void TestFailed(const Beefy::StringView& error, int stackOffset)
  595. {
  596. if (gClientPipe != NULL)
  597. {
  598. Beefy::StringSimple errorString = error;
  599. if (gTestBreakOnFailure)
  600. {
  601. SETUP_ERROR(errorString.c_str(), (int)(2 + stackOffset));
  602. BF_DEBUG_BREAK();
  603. }
  604. Beefy::String str = ":TestFail\t";
  605. str += errorString.c_str();
  606. str.Replace('\n', '\r');
  607. str += "\n";
  608. TestString(str);
  609. exit(1);
  610. }
  611. }
  612. void Internal::Test_Init(char* testData)
  613. {
  614. BfpSystem_SetCrashReportKind(BfpCrashReportKind_None);
  615. Beefy::String args = GetCommandLineArgs();
  616. BfpFileResult fileResult;
  617. gClientPipe = BfpFile_Create(args.c_str(), BfpFileCreateKind_OpenExisting, (BfpFileCreateFlags)(BfpFileCreateFlag_Read | BfpFileCreateFlag_Write | BfpFileCreateFlag_Pipe), BfpFileAttribute_None, &fileResult);
  618. if (fileResult != BfpFileResult_Ok)
  619. BF_FATAL("Test_Init failed to create pipe to test manager");
  620. gClientPipeErrorFunc = TestFailed;
  621. Beefy::String outStr;
  622. outStr += ":TestInit\n";
  623. outStr += testData;
  624. outStr += "\n";
  625. outStr += ":TestBegin\n";
  626. TestString(outStr);
  627. }
  628. void Internal::Test_Error(char* error)
  629. {
  630. if (gTestBreakOnFailure)
  631. {
  632. SETUP_ERROR(error, 3);
  633. BF_DEBUG_BREAK();
  634. }
  635. if (gClientPipe != NULL)
  636. {
  637. Beefy::String str = ":TestFail\t";
  638. str += error;
  639. str.Replace('\n', '\r');
  640. str += "\n";
  641. TestString(str);
  642. }
  643. else
  644. Internal_FatalError(error);
  645. }
  646. void Internal::Test_Write(char* strPtr)
  647. {
  648. if (gClientPipe != NULL)
  649. {
  650. Beefy::String str = ":TestWrite\t";
  651. str += strPtr;
  652. str.Replace('\n', '\r');
  653. str += "\n";
  654. TestString(str);
  655. }
  656. }
  657. int32 Internal::Test_Query()
  658. {
  659. if (gTestMethodIdx != -1)
  660. {
  661. uint32 tickEnd = BfpSystem_TickCount();
  662. TestString(StrFormat(":TestResult\t%d\n", tickEnd - gTestStartTick));
  663. }
  664. TestString(":TestQuery\n");
  665. Beefy::String result;
  666. TestReadCmd(result);
  667. Beefy::String param;
  668. int tabPos = (int)result.IndexOf('\t');
  669. if (tabPos != -1)
  670. {
  671. param = result.Substring(tabPos + 1);
  672. result.RemoveToEnd(tabPos);
  673. }
  674. if (result == ":TestRun")
  675. {
  676. gTestStartTick = BfpSystem_TickCount();
  677. Beefy::String options;
  678. int tabPos = (int)param.IndexOf('\t');
  679. if (tabPos != -1)
  680. {
  681. options = param.Substring(tabPos + 1);
  682. param.RemoveToEnd(tabPos);
  683. }
  684. gTestMethodIdx = atoi(param.c_str());
  685. gTestBreakOnFailure = options.Contains("FailBreak");
  686. return gTestMethodIdx;
  687. }
  688. else if (result == ":TestFinish")
  689. {
  690. return -1;
  691. }
  692. else
  693. {
  694. printf("Command Str: %s\n", result.c_str());
  695. BF_FATAL("Invalid test command string from test manager");
  696. }
  697. return false;
  698. }
  699. void Internal::Test_Finish()
  700. {
  701. TestString(":TestFinish\n");
  702. if (gClientPipe != NULL)
  703. {
  704. BfpFile_Release(gClientPipe);
  705. gClientPipe = NULL;
  706. }
  707. }
  708. ///
  709. int GetStackTrace(void **result, int max_depth, int skip_count);
  710. void BfLog(const char* fmt ...);
  711. static const int cMaxStackTraceCount = 1024;
  712. struct PendingAllocState
  713. {
  714. bool mHasData;
  715. void* mStackTrace[cMaxStackTraceCount];
  716. int mStackTraceCount;
  717. int mMetadataBytes;
  718. bool IsSmall(intptr curAllocBytes)
  719. {
  720. if ((mStackTraceCount > 255) || (mMetadataBytes > 255))
  721. return false;
  722. const intptr maxSmallObjectSize = ((intptr)1 << ((sizeof(intptr) - 2) * 8)) - 1;
  723. if (curAllocBytes <= maxSmallObjectSize)
  724. return true;
  725. intptr objBytes = curAllocBytes - mStackTraceCount*sizeof(intptr) - mMetadataBytes;
  726. return (objBytes < maxSmallObjectSize);
  727. }
  728. };
  729. void Internal::ObjectDynCheck(bf::System::Object* object, int typeId, bool allowNull)
  730. {
  731. return;
  732. if (object == NULL)
  733. {
  734. if (allowNull)
  735. return;
  736. SETUP_ERROR("Attempting unboxing on null object", 1);
  737. BF_DEBUG_BREAK();
  738. gBfRtCallbacks.DebugMessageData_Fatal();
  739. return;
  740. }
  741. auto result = gBfRtCallbacks.Object_DynamicCastToTypeId(object, typeId);
  742. if (result == NULL)
  743. {
  744. Beefy::String errorStr = "Attempting invalid cast on object";
  745. errorStr += StrFormat("\x1LEAK\t0x%@\n (%s)0x%@\n", object, "System.Object", object);
  746. SETUP_ERROR(errorStr.c_str(), 2);
  747. BF_DEBUG_BREAK();
  748. gBfRtCallbacks.DebugMessageData_Fatal();
  749. }
  750. }
  751. void Internal::ObjectDynCheckFailed(bf::System::Object* object, int typeId)
  752. {
  753. if (object == NULL)
  754. {
  755. SETUP_ERROR("Attempting unboxing on null object", 1);
  756. BF_DEBUG_BREAK();
  757. gBfRtCallbacks.DebugMessageData_Fatal();
  758. return;
  759. }
  760. Beefy::String errorStr = "Attempting invalid cast on object";
  761. errorStr += StrFormat("\x1LEAK\t0x%@\n (%s)0x%@\n", object, "System.Object", object);
  762. SETUP_ERROR(errorStr.c_str(), 2);
  763. BF_DEBUG_BREAK();
  764. gBfRtCallbacks.DebugMessageData_Fatal();
  765. }
  766. extern "C" BFRT_EXPORT int PrintF(const char* fmt, ...)
  767. {
  768. int ret;
  769. /* Declare a va_list type variable */
  770. va_list myargs;
  771. /* Initialise the va_list variable with the ... after fmt */
  772. va_start(myargs, fmt);
  773. /* Forward the '...' to vprintf */
  774. ret = vprintf(fmt, myargs);
  775. /* Clean up the va_list */
  776. va_end(myargs);
  777. return ret;
  778. }
  779. ///
  780. using namespace bf::System::Diagnostics::Contracts;
  781. void Contract::ReportFailure(Contract::ContractFailureKind failureKind, char* userMessage, int userMessageLen, char* conditionText, int conditionTextLen)
  782. {
  783. Beefy::String userMessageStr;
  784. if (userMessageLen > 0)
  785. userMessageStr.Reference(userMessage, userMessageLen);
  786. Beefy::String conditionTextStr;
  787. if (conditionTextLen > 0)
  788. conditionTextStr.Reference(conditionText, conditionTextLen);
  789. Beefy::String errorMsg = "Contract";
  790. if (failureKind == Contract::ContractFailureKind_Assert)
  791. errorMsg += ": Assert failed";
  792. if (userMessage != NULL)
  793. errorMsg += Beefy::String(": ") + userMessageStr;
  794. if (conditionText != NULL)
  795. errorMsg += Beefy::String(": ") + conditionTextStr;
  796. if (::IsDebuggerPresent())
  797. {
  798. SETUP_ERROR(errorMsg.c_str(), 3);
  799. BF_DEBUG_BREAK();
  800. gBfRtCallbacks.DebugMessageData_Fatal();
  801. }
  802. Internal_FatalError(errorMsg.c_str());
  803. return;
  804. }
  805. void bf::System::Diagnostics::Debug::Write(char* str, intptr strLen)
  806. {
  807. Beefy::String strVal(str, strLen);
  808. OutputDebugStr(strVal);
  809. }
  810. //////////////////////////////////////////////////////////////////////////
  811. bool IO::File::Exists(char* fileName)
  812. {
  813. return BfpFile_Exists(fileName);
  814. }
  815. bool IO::Directory::Exists(char* fileName)
  816. {
  817. return BfpDirectory_Exists(fileName);
  818. }
  819. //////////////////////////////////////////////////////////////////////////
  820. void* bf::System::FFI::FFILIB::ClosureAlloc(intptr size, void** outFunc)
  821. {
  822. #ifndef BF_DISABLE_FFI
  823. return ffi_closure_alloc(size, outFunc);
  824. #else
  825. return NULL;
  826. #endif
  827. }
  828. bf::System::FFI::FFIResult bf::System::FFI::FFILIB::PrepCif(bf::System::FFI::FFILIB::FFICIF* cif, bf::System::FFI::FFIABI abi, int32 nargs, bf::System::FFI::FFIType* rtype, bf::System::FFI::FFIType** argTypes)
  829. {
  830. #ifndef BF_DISABLE_FFI
  831. return (bf::System::FFI::FFIResult)ffi_prep_cif((ffi_cif*)cif, (ffi_abi)abi, nargs, (ffi_type*)rtype, (ffi_type**)argTypes);
  832. #else
  833. return (bf::System::FFI::FFIResult)0;
  834. #endif
  835. }
  836. void bf::System::FFI::FFILIB::Call(bf::System::FFI::FFILIB::FFICIF* cif, void* funcPtr, void* rvalue, void** args)
  837. {
  838. #ifndef BF_DISABLE_FFI
  839. ffi_call((ffi_cif*)cif, (void(*)())funcPtr, rvalue, args);
  840. #endif
  841. }
  842. //////////////////////////////////////////////////////////////////////////
  843. static int ToString(float d, char* outStr, bool roundTrip)
  844. {
  845. if (!roundTrip)
  846. {
  847. int digits;
  848. if (d > 100000)
  849. digits = 1;
  850. else if (d > 10000)
  851. digits = 2;
  852. else if (d > 1000)
  853. digits = 3;
  854. else if (d > 100)
  855. digits = 4;
  856. else if (d > 10)
  857. digits = 5;
  858. else
  859. digits = 6;
  860. sprintf(outStr, "%1.*f", digits, d);
  861. }
  862. else
  863. sprintf(outStr, "%1.9g", d);
  864. int len = (int)strlen(outStr);
  865. for (int i = 0; outStr[i] != 0; i++)
  866. {
  867. if (outStr[i] == '.')
  868. {
  869. int checkC = len - 1;
  870. while (true)
  871. {
  872. char c = outStr[checkC];
  873. if (c == '.')
  874. {
  875. return checkC;
  876. }
  877. else if (c == 'e')
  878. {
  879. return len;
  880. }
  881. else if (c != '0')
  882. {
  883. for (int j = i + 1; j <= checkC; j++)
  884. if (outStr[j] == 'e')
  885. return len;
  886. return checkC + 1;
  887. }
  888. checkC--;
  889. }
  890. }
  891. }
  892. if ((len == 3) && (outStr[0] == 'i'))
  893. {
  894. strcpy(outStr, "Infinity");
  895. return 8;
  896. }
  897. if ((len == 4) && (outStr[0] == '-') && (outStr[1] == 'i'))
  898. {
  899. strcpy(outStr, "-Infinity");
  900. return 9;
  901. }
  902. if ((len == 9) && (outStr[0] == '-') && (outStr[1] == 'n')) //-nan(xxx)
  903. {
  904. strcpy(outStr, "NaN");
  905. return 3;
  906. }
  907. return len;
  908. }
  909. static int ToString(double d, char* outStr, bool roundTrip)
  910. {
  911. if (!roundTrip)
  912. {
  913. int digits;
  914. if (d < 0)
  915. {
  916. if (d < -10000000000)
  917. {
  918. sprintf(outStr, "%g", d);
  919. }
  920. else
  921. {
  922. if (d < -1000000000)
  923. digits = 1;
  924. else if (d < -100000000)
  925. digits = 2;
  926. else if (d < -10000000)
  927. digits = 3;
  928. else if (d < -1000000)
  929. digits = 4;
  930. else if (d < -100000)
  931. digits = 5;
  932. else if (d < -10000)
  933. digits = 6;
  934. else if (d < -1000)
  935. digits = 7;
  936. else if (d < -100)
  937. digits = 8;
  938. else if (d < -10)
  939. digits = 9;
  940. else
  941. digits = 10;
  942. sprintf(outStr, "%1.*f", digits, d);
  943. }
  944. }
  945. else
  946. {
  947. if (d > 10000000000)
  948. {
  949. sprintf(outStr, "%g", d);
  950. }
  951. else
  952. {
  953. if (d > 1000000000)
  954. digits = 1;
  955. else if (d > 100000000)
  956. digits = 2;
  957. else if (d > 10000000)
  958. digits = 3;
  959. else if (d > 1000000)
  960. digits = 4;
  961. else if (d > 100000)
  962. digits = 5;
  963. else if (d > 10000)
  964. digits = 6;
  965. else if (d > 1000)
  966. digits = 7;
  967. else if (d > 100)
  968. digits = 8;
  969. else if (d > 10)
  970. digits = 9;
  971. else
  972. digits = 10;
  973. sprintf(outStr, "%1.*f", digits, d);
  974. }
  975. }
  976. }
  977. else
  978. sprintf(outStr, "%1.17g", d);
  979. int len = (int)strlen(outStr);
  980. for (int i = 0; outStr[i] != 0; i++)
  981. {
  982. if (outStr[i] == '.')
  983. {
  984. int checkC = len - 1;
  985. while (true)
  986. {
  987. char c = outStr[checkC];
  988. if (c == '.')
  989. {
  990. return checkC;
  991. }
  992. else if (c == 'e')
  993. {
  994. return len;
  995. }
  996. else if (c != '0')
  997. {
  998. for (int j = i + 1; j <= checkC; j++)
  999. if (outStr[j] == 'e')
  1000. return len;
  1001. return checkC + 1;
  1002. }
  1003. checkC--;
  1004. }
  1005. }
  1006. }
  1007. if ((len == 3) && (outStr[0] == 'i'))
  1008. {
  1009. strcpy(outStr, "Infinity");
  1010. return 8;
  1011. }
  1012. if ((len == 4) && (outStr[0] == '-') && (outStr[1] == 'i'))
  1013. {
  1014. strcpy(outStr, "-Infinity");
  1015. return 9;
  1016. }
  1017. if ((len == 9) && (outStr[0] == '-') && (outStr[1] == 'n')) //-nan(xxx)
  1018. {
  1019. strcpy(outStr, "NaN");
  1020. return 3;
  1021. }
  1022. return len;
  1023. }
  1024. int Float::ToString(float f, char* outStr, bool roundTrip)
  1025. {
  1026. #ifdef USE_CHARCONV
  1027. auto result = std::to_chars(outStr, outStr + 256, f);
  1028. return (int)(result.ptr - outStr);
  1029. #else
  1030. return ::ToString(f, outStr, roundTrip);
  1031. #endif
  1032. }
  1033. int Double::ToString(double d, char* outStr, bool roundTrip)
  1034. {
  1035. #ifdef USE_CHARCONV
  1036. auto result = std::to_chars(outStr, outStr + 256, d);
  1037. return (int)(result.ptr - outStr);
  1038. #else
  1039. return ::ToString(d, outStr, roundTrip);
  1040. #endif
  1041. }