ch.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #include "stdafx.h"
  7. #include "Core/AtomLockGuids.h"
  8. #ifdef _WIN32
  9. #include <winver.h>
  10. #include <process.h>
  11. #include <fcntl.h>
  12. #else
  13. #include <pthread.h>
  14. #endif
  15. #ifdef __linux__
  16. #include <sys/sysinfo.h>
  17. #elif defined(__APPLE__)
  18. #include <sys/sysctl.h>
  19. #endif
  20. unsigned int MessageBase::s_messageCount = 0;
  21. Debugger* Debugger::debugger = nullptr;
  22. #ifdef _WIN32
  23. LPCWSTR hostName = _u("ch.exe");
  24. #else
  25. LPCWSTR hostName = _u("ch");
  26. #endif
  27. JsRuntimeHandle chRuntime = JS_INVALID_RUNTIME_HANDLE;
  28. BOOL doTTRecord = false;
  29. BOOL doTTReplay = false;
  30. const size_t ttUriBufferLength = MAX_PATH * 3;
  31. char ttUri[ttUriBufferLength];
  32. size_t ttUriLength = 0;
  33. UINT32 snapInterval = MAXUINT32;
  34. UINT32 snapHistoryLength = MAXUINT32;
  35. LPCWSTR connectionUuidString = NULL;
  36. UINT32 startEventCount = 1;
  37. HRESULT RunBgParseSync(LPCSTR fileContents, UINT lengthBytes, const char* fileName);
  38. extern "C"
  39. HRESULT __stdcall OnChakraCoreLoadedEntry(TestHooks& testHooks)
  40. {
  41. return ChakraRTInterface::OnChakraCoreLoaded(testHooks);
  42. }
  43. JsRuntimeAttributes jsrtAttributes = JsRuntimeAttributeNone;
  44. int HostExceptionFilter(int exceptionCode, _EXCEPTION_POINTERS *ep)
  45. {
  46. ChakraRTInterface::NotifyUnhandledException(ep);
  47. #if ENABLE_NATIVE_CODEGEN && _WIN32
  48. JITProcessManager::TerminateJITServer();
  49. #endif
  50. bool crashOnException = false;
  51. ChakraRTInterface::GetCrashOnExceptionFlag(&crashOnException);
  52. if (exceptionCode == EXCEPTION_BREAKPOINT || (crashOnException && exceptionCode != 0xE06D7363))
  53. {
  54. return EXCEPTION_CONTINUE_SEARCH;
  55. }
  56. fwprintf(stderr, _u("FATAL ERROR: %ls failed due to exception code %x\n"), hostName, exceptionCode);
  57. _flushall();
  58. // Exception happened, so we probably didn't clean up properly,
  59. // Don't exit normally, just terminate
  60. TerminateProcess(::GetCurrentProcess(), exceptionCode);
  61. return EXCEPTION_CONTINUE_SEARCH;
  62. }
  63. void __stdcall PrintUsageFormat()
  64. {
  65. wprintf(_u("\nUsage: %s [-v|-version] [-h|-help] [-?] [flaglist] <source file>\n"), hostName);
  66. wprintf(_u("\t-v|-version\t\tDisplays version info\n"));
  67. wprintf(_u("\t-h|-help\t\tDisplays this help message\n"));
  68. wprintf(_u("\t-?\t\t\tDisplays this help message with complete [flaglist] info\n"));
  69. }
  70. #if !defined(ENABLE_DEBUG_CONFIG_OPTIONS)
  71. void __stdcall PrintReleaseUsage()
  72. {
  73. wprintf(_u("\nUsage: %s [-v|-version] [-h|-help|-?] <source file> %s"), hostName,
  74. _u("\nNote: [flaglist] is not supported in Release builds; try a Debug or Test build to enable these flags.\n"));
  75. wprintf(_u("\t-v|-version\t\tDisplays version info\n"));
  76. wprintf(_u("\t-h|-help|-?\t\tDisplays this help message\n"));
  77. }
  78. #endif
  79. void __stdcall PrintUsage()
  80. {
  81. #if !defined(ENABLE_DEBUG_CONFIG_OPTIONS)
  82. PrintReleaseUsage();
  83. #else
  84. PrintUsageFormat();
  85. #endif
  86. }
  87. void __stdcall PrintChVersion()
  88. {
  89. #if CHAKRA_CORE_VERSION_RELEASE
  90. wprintf(_u("%s version %d.%d.%d.0\n"),
  91. #else
  92. wprintf(_u("%s version %d.%d.%d.0-beta\n"),
  93. #endif
  94. hostName, CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION);
  95. }
  96. #ifdef _WIN32
  97. void __stdcall PrintChakraCoreVersion()
  98. {
  99. char16 filename[_MAX_PATH];
  100. char16 drive[_MAX_DRIVE];
  101. char16 dir[_MAX_DIR];
  102. LPCWSTR chakraDllName = GetChakraDllNameW();
  103. char16 modulename[_MAX_PATH];
  104. if (!PlatformAgnostic::SystemInfo::GetBinaryLocation(modulename, _MAX_PATH))
  105. {
  106. return;
  107. }
  108. _wsplitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
  109. _wmakepath_s(filename, drive, dir, chakraDllName, nullptr);
  110. UINT size = 0;
  111. LPBYTE lpBuffer = NULL;
  112. DWORD verSize = GetFileVersionInfoSizeW(filename, NULL);
  113. if (verSize != NULL)
  114. {
  115. LPSTR verData = new char[verSize];
  116. if (GetFileVersionInfoW(filename, NULL, verSize, verData) &&
  117. VerQueryValueW(verData, _u("\\"), (VOID FAR * FAR *)&lpBuffer, &size) &&
  118. (size != 0))
  119. {
  120. VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
  121. if (verInfo->dwSignature == VS_FFI_SIGNATURE)
  122. {
  123. // Doesn't matter if you are on 32 bit or 64 bit,
  124. // DWORD is always 32 bits, so first two revision numbers
  125. // come from dwFileVersionMS, last two come from dwFileVersionLS
  126. wprintf(_u("%s version %lu.%lu.%lu.%lu\n"),
  127. chakraDllName,
  128. (verInfo->dwFileVersionMS >> 16) & 0xffff,
  129. (verInfo->dwFileVersionMS >> 0) & 0xffff,
  130. (verInfo->dwFileVersionLS >> 16) & 0xffff,
  131. (verInfo->dwFileVersionLS >> 0) & 0xffff);
  132. }
  133. }
  134. delete[] verData;
  135. }
  136. }
  137. #endif
  138. void __stdcall PrintVersion()
  139. {
  140. PrintChVersion();
  141. #ifdef _WIN32
  142. PrintChakraCoreVersion();
  143. #endif
  144. }
  145. // On success the param byteCodeBuffer will be allocated in the function.
  146. HRESULT GetSerializedBuffer(LPCSTR fileContents, JsFinalizeCallback fileContentFinalizeCallback, JsValueRef *byteCodeBuffer)
  147. {
  148. HRESULT hr = S_OK;
  149. JsValueRef scriptSource;
  150. IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
  151. (unsigned int)strlen(fileContents), fileContentFinalizeCallback, (void*)fileContents, &scriptSource));
  152. IfJsErrorFailLog(ChakraRTInterface::JsSerialize(scriptSource, byteCodeBuffer,
  153. JsParseScriptAttributeNone));
  154. Error:
  155. return hr;
  156. }
  157. HANDLE GetFileHandle(LPCWSTR filename)
  158. {
  159. if (filename != nullptr)
  160. {
  161. return CreateFile(filename, GENERIC_WRITE, FILE_SHARE_DELETE,
  162. nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
  163. }
  164. return GetStdHandle(STD_OUTPUT_HANDLE);
  165. }
  166. HRESULT CreateLibraryByteCode(const char* contentsRaw)
  167. {
  168. JsValueRef bufferVal;
  169. BYTE *bcBuffer = nullptr;
  170. unsigned int bcBufferSize = 0;
  171. HRESULT hr = E_FAIL;
  172. // Windows can't do the below with printf - so use windows API on windows but printf on posix
  173. #ifdef _WIN32
  174. HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
  175. DWORD written = 0;
  176. #define print_format(format, element, size) \
  177. { \
  178. auto scratchLen = size; \
  179. char scratch[size]; \
  180. int len = _snprintf_s(scratch, scratchLen, _countof(scratch), format, element); \
  181. IfFalseGo(WriteFile(out, scratch, (DWORD)(len), &written, nullptr)); \
  182. }
  183. #define print(text) \
  184. WriteFile(out, text, (DWORD)strlen(text), &written, nullptr);
  185. #else
  186. #define print_format(format, element, size) printf(format, element)
  187. #define print printf
  188. #endif
  189. // Generate the bytecode, free the original buffer then retrieve the generated bytecode
  190. IfFailGo(GetSerializedBuffer(contentsRaw, WScriptJsrt::FinalizeFree, &bufferVal));
  191. IfFailGo(ChakraRTInterface::JsGetArrayBufferStorage(bufferVal, &bcBuffer, &bcBufferSize));
  192. // Write out the bytecode
  193. print("[] = {\n/* 00000000 */");
  194. for (unsigned int i = 0; i < bcBufferSize; i++)
  195. {
  196. print_format(" 0x%02X", bcBuffer[i], 6);
  197. // Add a comma if this is not the last item
  198. if (i < bcBufferSize - 1)
  199. {
  200. print(",");
  201. }
  202. // Add a line break every 16 scratches, primarily so the compiler doesn't complain about the string being too long.
  203. // Also, won't add for the last scratch
  204. if (i % 16 == 15 && i < bcBufferSize - 1)
  205. {
  206. print_format("\n/* %08X */", i + 1, 17);
  207. }
  208. }
  209. print("};\n\n");
  210. #undef print
  211. #undef print_format
  212. hr = S_OK;
  213. Error:
  214. return hr;
  215. }
  216. // Used becuase of what's likely a deficiency in the API
  217. typedef struct {
  218. void* scriptBody;
  219. JsFinalizeCallback scriptBodyFinalizeCallback;
  220. bool freeingHandled;
  221. } SerializedCallbackInfo;
  222. static bool CHAKRA_CALLBACK DummyJsSerializedScriptLoadUtf8Source(
  223. JsSourceContext sourceContext,
  224. JsValueRef* scriptBuffer,
  225. JsParseScriptAttributes *parseAttributes)
  226. {
  227. SerializedCallbackInfo* serializedCallbackInfo = reinterpret_cast<SerializedCallbackInfo*>(sourceContext);
  228. Assert(!serializedCallbackInfo->freeingHandled);
  229. serializedCallbackInfo->freeingHandled = true;
  230. size_t length = strlen(reinterpret_cast<const char*>(serializedCallbackInfo->scriptBody));
  231. // sourceContext is source ptr, see RunScript below
  232. if (ChakraRTInterface::JsCreateExternalArrayBuffer(serializedCallbackInfo->scriptBody, (unsigned int)length,
  233. serializedCallbackInfo->scriptBodyFinalizeCallback, serializedCallbackInfo->scriptBody, scriptBuffer) != JsNoError)
  234. {
  235. return false;
  236. }
  237. *parseAttributes = JsParseScriptAttributeNone;
  238. return true;
  239. }
  240. HRESULT RunScript(const char* fileName, LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, JsValueRef bufferValue, char *fullPath, JsValueRef parserStateCache)
  241. {
  242. HRESULT hr = S_OK;
  243. MessageQueue * messageQueue = new MessageQueue();
  244. WScriptJsrt::AddMessageQueue(messageQueue);
  245. IfJsErrorFailLogLabel(ChakraRTInterface::JsSetPromiseContinuationCallback(WScriptJsrt::PromiseContinuationCallback, (void*)messageQueue), ErrorRunFinalize);
  246. if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0)
  247. {
  248. if(fileContentsFinalizeCallback != nullptr)
  249. {
  250. fileContentsFinalizeCallback((void*)fileContents);
  251. }
  252. #if !ENABLE_TTD
  253. wprintf(_u("Sential js file is only ok when in TTDebug mode!!!\n"));
  254. return E_FAIL;
  255. #else
  256. if(!doTTReplay)
  257. {
  258. wprintf(_u("Sential js file is only ok when in TTReplay mode!!!\n"));
  259. return E_FAIL;
  260. }
  261. IfFailedReturn(ChakraRTInterface::JsTTDStart());
  262. try
  263. {
  264. JsTTDMoveMode moveMode = JsTTDMoveMode::JsTTDMoveKthEvent;
  265. int64_t snapEventTime = -1;
  266. int64_t nextEventTime = -2;
  267. while(true)
  268. {
  269. JsErrorCode error = ChakraRTInterface::JsTTDGetSnapTimeTopLevelEventMove(chRuntime, moveMode, startEventCount, &nextEventTime, &snapEventTime, nullptr);
  270. if(error != JsNoError)
  271. {
  272. if(error == JsErrorCategoryUsage)
  273. {
  274. wprintf(_u("Start time not in log range.\n"));
  275. }
  276. return error;
  277. }
  278. IfFailedReturn(ChakraRTInterface::JsTTDMoveToTopLevelEvent(chRuntime, moveMode, snapEventTime, nextEventTime));
  279. JsErrorCode res = ChakraRTInterface::JsTTDReplayExecution(&moveMode, &nextEventTime);
  280. //handle any uncaught exception by immediately time-traveling to the throwing line in the debugger -- in replay just report and exit
  281. if(res == JsErrorCategoryScript)
  282. {
  283. wprintf(_u("An unhandled script exception occurred!!!\n"));
  284. ExitProcess(0);
  285. }
  286. if(nextEventTime == -1)
  287. {
  288. wprintf(_u("\nReached end of Execution -- Exiting.\n"));
  289. break;
  290. }
  291. }
  292. }
  293. catch(...)
  294. {
  295. wprintf(_u("Terminal exception in Replay -- exiting.\n"));
  296. ExitProcess(0);
  297. }
  298. #endif
  299. }
  300. else
  301. {
  302. Assert(fileContents != nullptr || bufferValue != nullptr);
  303. JsErrorCode runScript;
  304. JsValueRef fname;
  305. IfJsErrorFailLogLabel(ChakraRTInterface::JsCreateString(fullPath,
  306. strlen(fullPath), &fname), ErrorRunFinalize);
  307. // memory management for serialized script case - need to define these here
  308. SerializedCallbackInfo serializedCallbackInfo;
  309. serializedCallbackInfo.freeingHandled = true;
  310. if (bufferValue != nullptr)
  311. {
  312. if (fileContents == nullptr)
  313. {
  314. // if we have no fileContents, no worry about freeing them, and the call is simple.
  315. runScript = ChakraRTInterface::JsRunSerialized(
  316. bufferValue,
  317. nullptr /*JsSerializedLoadScriptCallback*/,
  318. 0 /*SourceContext*/,
  319. fname,
  320. nullptr /*result*/
  321. );
  322. }
  323. else // fileContents != nullptr
  324. {
  325. // Memory management is a little more complex here
  326. serializedCallbackInfo.scriptBody = (void*)fileContents;
  327. serializedCallbackInfo.scriptBodyFinalizeCallback = fileContentsFinalizeCallback;
  328. serializedCallbackInfo.freeingHandled = false;
  329. // Now we can run our script, with this serializedCallbackInfo as the sourcecontext
  330. runScript = ChakraRTInterface::JsRunSerialized(
  331. bufferValue,
  332. DummyJsSerializedScriptLoadUtf8Source,
  333. reinterpret_cast<JsSourceContext>(&serializedCallbackInfo),
  334. // Use source ptr as sourceContext
  335. fname,
  336. nullptr /*result*/);
  337. }
  338. }
  339. else if (parserStateCache != nullptr)
  340. {
  341. JsValueRef scriptSource;
  342. IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
  343. (unsigned int)fileLength,
  344. fileContentsFinalizeCallback, (void*)fileContents, &scriptSource));
  345. // TODO: Support TTD
  346. runScript = ChakraRTInterface::JsRunScriptWithParserState(
  347. scriptSource,
  348. WScriptJsrt::GetNextSourceContext(),
  349. fname,
  350. JsParseScriptAttributeNone,
  351. parserStateCache,
  352. nullptr);
  353. }
  354. else if (HostConfigFlags::flags.Module)
  355. {
  356. runScript = WScriptJsrt::ModuleEntryPoint(fileName, fileContents, fullPath);
  357. }
  358. else if (HostConfigFlags::flags.ExecuteWithBgParse && !HostConfigFlags::flags.DebugLaunch)
  359. {
  360. unsigned int lengthBytes = (unsigned int) fileLength;
  361. runScript = (JsErrorCode)RunBgParseSync(fileContents, lengthBytes, fileName);
  362. }
  363. else // bufferValue == nullptr && parserStateCache == nullptr
  364. {
  365. JsValueRef scriptSource;
  366. IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
  367. (unsigned int)fileLength,
  368. fileContentsFinalizeCallback, (void*)fileContents, &scriptSource));
  369. #if ENABLE_TTD
  370. if (doTTRecord)
  371. {
  372. JsPropertyIdRef ttProperty = nullptr;
  373. JsValueRef ttString = nullptr;
  374. JsValueRef global = nullptr;
  375. IfFailedReturn(ChakraRTInterface::JsCreatePropertyId("ttdLogURI", strlen("ttdLogURI"), &ttProperty));
  376. IfFailedReturn(ChakraRTInterface::JsCreateString(ttUri, ttUriLength, &ttString));
  377. IfFailedReturn(ChakraRTInterface::JsGetGlobalObject(&global));
  378. IfFailedReturn(ChakraRTInterface::JsSetProperty(global, ttProperty, ttString, false));
  379. IfFailedReturn(ChakraRTInterface::JsTTDStart());
  380. }
  381. auto sourceContext = WScriptJsrt::GetNextSourceContext();
  382. WScriptJsrt::RegisterScriptDir(sourceContext, fullPath);
  383. runScript = ChakraRTInterface::JsRun(scriptSource,
  384. sourceContext, fname,
  385. JsParseScriptAttributeNone, nullptr /*result*/);
  386. if (runScript == JsErrorCategoryUsage)
  387. {
  388. wprintf(_u("FATAL ERROR: Core was compiled without ENABLE_TTD is defined. CH is trying to use TTD interface\n"));
  389. abort();
  390. }
  391. #else
  392. runScript = ChakraRTInterface::JsRun(scriptSource,
  393. WScriptJsrt::GetNextSourceContext(), fname,
  394. JsParseScriptAttributeNone,
  395. nullptr /*result*/);
  396. #endif
  397. }
  398. //Do a yield after the main script body executes
  399. ChakraRTInterface::JsTTDNotifyYield();
  400. if(runScript != JsNoError)
  401. {
  402. WScriptJsrt::PrintException(fileName, runScript);
  403. }
  404. else
  405. {
  406. // Repeatedly flush the message queue until it's empty. It is necessary to loop on this
  407. // because setTimeout can add scripts to execute.
  408. do
  409. {
  410. IfFailGo(messageQueue->ProcessAll(fileName));
  411. } while(!messageQueue->IsEmpty());
  412. }
  413. // free the source for the serialized script case if it's not been handed to a managed object
  414. if (!serializedCallbackInfo.freeingHandled && fileContentsFinalizeCallback != nullptr)
  415. {
  416. fileContentsFinalizeCallback((void*)fileContents);
  417. }
  418. }
  419. if(false)
  420. {
  421. ErrorRunFinalize:
  422. if(fileContentsFinalizeCallback != nullptr)
  423. {
  424. fileContentsFinalizeCallback((void*)fileContents);
  425. }
  426. }
  427. Error:
  428. #if ENABLE_TTD
  429. if(doTTRecord)
  430. {
  431. IfFailedReturn(ChakraRTInterface::JsTTDStop());
  432. }
  433. #endif
  434. if (messageQueue != nullptr)
  435. {
  436. messageQueue->RemoveAll();
  437. // clean up possible pinned exception object on exit to avoid potential leak
  438. bool hasException;
  439. if (ChakraRTInterface::JsHasException(&hasException) == JsNoError && hasException)
  440. {
  441. JsValueRef exception = JS_INVALID_REFERENCE;
  442. ChakraRTInterface::JsGetAndClearException(&exception);
  443. }
  444. delete messageQueue;
  445. }
  446. // We only call RunScript() once, safe to Uninitialize()
  447. WScriptJsrt::Uninitialize();
  448. return hr;
  449. }
  450. static HRESULT CreateRuntime(JsRuntimeHandle *runtime)
  451. {
  452. HRESULT hr = E_FAIL;
  453. #ifndef _WIN32
  454. // On Posix, malloc optimistically returns a non-null address without
  455. // checking if it's actually able to back that allocation in memory
  456. // Upon use of that address however, if the address space for that allocation
  457. // can't be committed, the process is killed
  458. // See the man page for malloc
  459. //
  460. // In order to avoid having to deal with this, we set the memory limit for the
  461. // runtime to the size of the physical memory on the system
  462. // TODO:
  463. // We could move the following into its own platform agnostic API
  464. // but in this case, this is a one-time call thats not applicable
  465. // on Windows so decided to leave as is
  466. // Additionally, we can probably do better than just limit to the physical memory
  467. // size
  468. #if defined(__APPLE__) || defined(__linux__)
  469. size_t memoryLimit;
  470. #ifdef __APPLE__
  471. int totalRamHW[] = { CTL_HW, HW_MEMSIZE };
  472. size_t length = sizeof(memoryLimit);
  473. if (sysctl(totalRamHW, 2, &memoryLimit, &length, NULL, 0) == -1)
  474. {
  475. memoryLimit = 0;
  476. }
  477. #else
  478. struct sysinfo sysInfo;
  479. if (sysinfo(&sysInfo) == -1)
  480. {
  481. memoryLimit = 0;
  482. }
  483. else
  484. {
  485. memoryLimit = sysInfo.totalram;
  486. }
  487. #endif // __APPLE__
  488. #endif // __APPLE__ || __linux
  489. #endif // !_WIN32
  490. IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, runtime));
  491. #ifndef _WIN32
  492. IfJsErrorFailLog(ChakraRTInterface::JsSetRuntimeMemoryLimit(*runtime, memoryLimit));
  493. #endif
  494. hr = S_OK;
  495. Error:
  496. return hr;
  497. }
  498. HRESULT GetParserStateBuffer(LPCSTR fileContents, JsFinalizeCallback fileContentsFinalizeCallback, JsValueRef *parserStateBuffer)
  499. {
  500. HRESULT hr = S_OK;
  501. JsValueRef scriptSource = nullptr;
  502. IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
  503. (unsigned int)strlen(fileContents), fileContentsFinalizeCallback, (void*)fileContents, &scriptSource));
  504. IfJsErrorFailLog(ChakraRTInterface::JsSerializeParserState(scriptSource, parserStateBuffer, JsParseScriptAttributeNone));
  505. Error:
  506. return hr;
  507. }
  508. HRESULT CreateParserState(LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, LPCWSTR fullPath)
  509. {
  510. HRESULT hr = S_OK;
  511. HANDLE fileHandle = nullptr;
  512. JsValueRef parserStateBuffer = nullptr;
  513. BYTE *buffer = nullptr;
  514. unsigned int bufferSize = 0;
  515. IfFailedGoLabel(GetParserStateBuffer(fileContents, fileContentsFinalizeCallback, &parserStateBuffer), Error);
  516. IfJsErrorFailLog(ChakraRTInterface::JsGetArrayBufferStorage(parserStateBuffer, &buffer, &bufferSize));
  517. fileHandle = GetFileHandle(fullPath);
  518. IfFalseGo(fileHandle != INVALID_HANDLE_VALUE && fileHandle != nullptr);
  519. for (unsigned int i = 0; i < bufferSize; i++)
  520. {
  521. const unsigned int BYTES_PER_LINE = 32;
  522. DWORD written = 0;
  523. char scratch[3];
  524. auto scratchLen = sizeof(scratch);
  525. int num = _snprintf_s(scratch, scratchLen, _countof(scratch), "%02X", buffer[i]);
  526. Assert(num == 2);
  527. IfFalseGo(WriteFile(fileHandle, scratch, (DWORD)(scratchLen - 1), &written, nullptr));
  528. // Add line breaks so this block can be readable
  529. if (i % BYTES_PER_LINE == (BYTES_PER_LINE - 1) && i < bufferSize - 1)
  530. {
  531. IfFalseGo(WriteFile(fileHandle, "\n", 1, &written, nullptr));
  532. }
  533. }
  534. Error:
  535. if (fileHandle != nullptr)
  536. {
  537. CloseHandle(fileHandle);
  538. }
  539. return hr;
  540. }
  541. HRESULT CreateParserStateAndRunScript(const char* fileName, LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, char *fullPath)
  542. {
  543. HRESULT hr = S_OK;
  544. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  545. JsContextRef context = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
  546. JsValueRef bufferVal;
  547. // We don't want this to free fileContents when it completes, so the finalizeCallback is nullptr
  548. IfFailedGoLabel(GetParserStateBuffer(fileContents, nullptr, &bufferVal), ErrorRunFinalize);
  549. // Bytecode buffer is created in one runtime and will be executed on different runtime.
  550. IfFailedGoLabel(CreateRuntime(&runtime), ErrorRunFinalize);
  551. chRuntime = runtime;
  552. IfJsErrorFailLogLabel(ChakraRTInterface::JsCreateContext(runtime, &context), ErrorRunFinalize);
  553. IfJsErrorFailLogLabel(ChakraRTInterface::JsGetCurrentContext(&current), ErrorRunFinalize);
  554. IfJsErrorFailLogLabel(ChakraRTInterface::JsSetCurrentContext(context), ErrorRunFinalize);
  555. // Initialized the WScript object on the new context
  556. if (!WScriptJsrt::Initialize())
  557. {
  558. IfFailedGoLabel(E_FAIL, ErrorRunFinalize);
  559. }
  560. // This is our last call to use fileContents, so pass in the finalizeCallback
  561. IfFailGo(RunScript(fileName, fileContents, fileLength, fileContentsFinalizeCallback, nullptr, fullPath, bufferVal));
  562. if (false)
  563. {
  564. ErrorRunFinalize:
  565. if (fileContentsFinalizeCallback != nullptr)
  566. {
  567. fileContentsFinalizeCallback((void*)fileContents);
  568. }
  569. }
  570. Error:
  571. if (current != JS_INVALID_REFERENCE)
  572. {
  573. ChakraRTInterface::JsSetCurrentContext(current);
  574. }
  575. if (runtime != JS_INVALID_RUNTIME_HANDLE)
  576. {
  577. ChakraRTInterface::JsDisposeRuntime(runtime);
  578. }
  579. return hr;
  580. }
  581. HRESULT CreateAndRunSerializedScript(const char* fileName, LPCSTR fileContents, size_t fileLength, JsFinalizeCallback fileContentsFinalizeCallback, char *fullPath)
  582. {
  583. HRESULT hr = S_OK;
  584. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  585. JsContextRef context = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
  586. JsValueRef bufferVal;
  587. // We don't want this to free fileContents when it completes, so the finalizeCallback is nullptr
  588. IfFailedGoLabel(GetSerializedBuffer(fileContents, nullptr, &bufferVal), ErrorRunFinalize);
  589. // Bytecode buffer is created in one runtime and will be executed on different runtime.
  590. IfFailedGoLabel(CreateRuntime(&runtime), ErrorRunFinalize);
  591. chRuntime = runtime;
  592. IfJsErrorFailLogLabel(ChakraRTInterface::JsCreateContext(runtime, &context), ErrorRunFinalize);
  593. IfJsErrorFailLogLabel(ChakraRTInterface::JsGetCurrentContext(&current), ErrorRunFinalize);
  594. IfJsErrorFailLogLabel(ChakraRTInterface::JsSetCurrentContext(context), ErrorRunFinalize);
  595. // Initialized the WScript object on the new context
  596. if (!WScriptJsrt::Initialize())
  597. {
  598. IfFailedGoLabel(E_FAIL, ErrorRunFinalize);
  599. }
  600. // This is our last call to use fileContents, so pass in the finalizeCallback
  601. IfFailGo(RunScript(fileName, fileContents, fileLength, fileContentsFinalizeCallback, bufferVal, fullPath, nullptr));
  602. if(false)
  603. {
  604. ErrorRunFinalize:
  605. if(fileContentsFinalizeCallback != nullptr)
  606. {
  607. fileContentsFinalizeCallback((void*)fileContents);
  608. }
  609. }
  610. Error:
  611. if (current != JS_INVALID_REFERENCE)
  612. {
  613. ChakraRTInterface::JsSetCurrentContext(current);
  614. }
  615. if (runtime != JS_INVALID_RUNTIME_HANDLE)
  616. {
  617. ChakraRTInterface::JsDisposeRuntime(runtime);
  618. }
  619. return hr;
  620. }
  621. // Use the asynchronous BGParse JSRT APIs in a synchronous call
  622. HRESULT RunBgParseSync(LPCSTR fileContents, UINT lengthBytes, const char* fileName)
  623. {
  624. JsValueRef scriptSource;
  625. JsErrorCode e = (ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
  626. (unsigned int)lengthBytes,
  627. nullptr, (void*)fileContents, &scriptSource));
  628. // What's the preferred way of doing this?
  629. WCHAR fileNameWide[MAX_PATH] = { 0 };
  630. size_t fileNameLength = strlen(fileName);
  631. for (size_t i = 0; i < fileNameLength; i++)
  632. {
  633. fileNameWide[i] = fileName[i];
  634. }
  635. JsScriptContents scriptContents = { 0 };
  636. scriptContents.container = (LPVOID)fileContents;
  637. scriptContents.containerType = JsScriptContainerType::HeapAllocatedBuffer;
  638. scriptContents.encodingType = JsScriptEncodingType::Utf8;
  639. scriptContents.contentLengthInBytes = lengthBytes;
  640. scriptContents.fullPath = fileNameWide;
  641. DWORD cookie = 0;
  642. e = ChakraRTInterface::JsQueueBackgroundParse_Experimental(&scriptContents, &cookie);
  643. Assert(e == JsErrorCode::JsNoError);
  644. JsValueRef bgResult = nullptr;
  645. e = ChakraRTInterface::JsExecuteBackgroundParse_Experimental(
  646. cookie,
  647. scriptSource,
  648. WScriptJsrt::GetNextSourceContext(),
  649. (WCHAR*)scriptContents.fullPath,
  650. JsParseScriptAttributes::JsParseScriptAttributeNone,
  651. nullptr,//_In_ JsValueRef parserState,
  652. &bgResult
  653. );
  654. return e;
  655. }
  656. HRESULT ExecuteTest(const char* fileName)
  657. {
  658. HRESULT hr = S_OK;
  659. LPCSTR fileContents = nullptr;
  660. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  661. UINT lengthBytes = 0;
  662. if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0)
  663. {
  664. #if !ENABLE_TTD
  665. wprintf(_u("Sentinel js file is only ok when in TTDebug mode!!!\n"));
  666. return E_FAIL;
  667. #else
  668. if(!doTTReplay)
  669. {
  670. wprintf(_u("Sentinel js file is only ok when in TTReplay mode!!!\n"));
  671. return E_FAIL;
  672. }
  673. jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures);
  674. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateReplayRuntime(jsrtAttributes, ttUri, ttUriLength, Helpers::TTCreateStreamCallback, Helpers::TTReadBytesFromStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime));
  675. chRuntime = runtime;
  676. JsContextRef context = JS_INVALID_REFERENCE;
  677. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context));
  678. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  679. IfFailGo(RunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr, nullptr, nullptr));
  680. unsigned int rcount = 0;
  681. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(nullptr));
  682. ChakraRTInterface::JsRelease(context, &rcount);
  683. AssertMsg(rcount == 0, "Should only have had 1 ref from replay code and one ref from current context??");
  684. #endif
  685. }
  686. else
  687. {
  688. LPCOLESTR contentsRaw = nullptr;
  689. char fullPath[_MAX_PATH];
  690. size_t len = 0;
  691. hr = Helpers::LoadScriptFromFile(fileName, fileContents, &lengthBytes);
  692. contentsRaw; lengthBytes; // Unused for now.
  693. IfFailGo(hr);
  694. if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled)
  695. {
  696. jsrtAttributes = (JsRuntimeAttributes)(jsrtAttributes | JsRuntimeAttributeSerializeLibraryByteCode);
  697. }
  698. #if ENABLE_TTD
  699. if (doTTRecord)
  700. {
  701. //Ensure we run with experimental features (as that is what Node does right now).
  702. jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures);
  703. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateRecordRuntime(jsrtAttributes, snapInterval, snapHistoryLength, Helpers::TTCreateStreamCallback, Helpers::TTWriteBytesToStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime));
  704. chRuntime = runtime;
  705. JsContextRef context = JS_INVALID_REFERENCE;
  706. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context));
  707. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  708. #if ENABLE_TTD
  709. //We need this here since this context is created in record
  710. IfJsErrorFailLog(ChakraRTInterface::JsSetObjectBeforeCollectCallback(context, nullptr, WScriptJsrt::JsContextBeforeCollectCallback));
  711. #endif
  712. }
  713. else
  714. {
  715. AssertMsg(!doTTReplay, "Should be handled in the else case above!!!");
  716. IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime));
  717. chRuntime = runtime;
  718. if (HostConfigFlags::flags.DebugLaunch)
  719. {
  720. Debugger* debugger = Debugger::GetDebugger(runtime);
  721. debugger->StartDebugging(runtime);
  722. }
  723. JsContextRef context = JS_INVALID_REFERENCE;
  724. IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context));
  725. //Don't need collect callback since this is always in replay
  726. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  727. }
  728. #else
  729. IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime));
  730. chRuntime = runtime;
  731. if (HostConfigFlags::flags.DebugLaunch)
  732. {
  733. Debugger* debugger = Debugger::GetDebugger(runtime);
  734. debugger->StartDebugging(runtime);
  735. }
  736. JsContextRef context = JS_INVALID_REFERENCE;
  737. IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context));
  738. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  739. #endif
  740. #ifdef DEBUG
  741. ChakraRTInterface::SetCheckOpHelpersFlag(true);
  742. #endif
  743. if (!WScriptJsrt::Initialize())
  744. {
  745. IfFailGo(E_FAIL);
  746. }
  747. if (_fullpath(fullPath, fileName, _MAX_PATH) == nullptr)
  748. {
  749. IfFailGo(E_FAIL);
  750. }
  751. if (HostConfigFlags::flags.TrackRejectedPromises)
  752. {
  753. ChakraRTInterface::JsSetHostPromiseRejectionTracker(WScriptJsrt::PromiseRejectionTrackerCallback, nullptr);
  754. }
  755. len = strlen(fullPath);
  756. if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled)
  757. {
  758. IfFailGo(CreateLibraryByteCode(fileContents));
  759. }
  760. else if (HostConfigFlags::flags.SerializedIsEnabled)
  761. {
  762. CreateAndRunSerializedScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, fullPath);
  763. }
  764. else if (HostConfigFlags::flags.GenerateParserStateCacheIsEnabled)
  765. {
  766. CreateParserState(fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr);
  767. }
  768. else if (HostConfigFlags::flags.UseParserStateCacheIsEnabled)
  769. {
  770. CreateParserStateAndRunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, fullPath);
  771. }
  772. else
  773. {
  774. IfFailGo(RunScript(fileName, fileContents, lengthBytes, WScriptJsrt::FinalizeFree, nullptr, fullPath, nullptr));
  775. }
  776. }
  777. Error:
  778. if (Debugger::debugger != nullptr)
  779. {
  780. Debugger::debugger->CompareOrWriteBaselineFile(fileName);
  781. Debugger::CloseDebugger();
  782. }
  783. ChakraRTInterface::JsSetCurrentContext(nullptr);
  784. if (runtime != JS_INVALID_RUNTIME_HANDLE)
  785. {
  786. ChakraRTInterface::JsDisposeRuntime(runtime);
  787. }
  788. _flushall();
  789. return hr;
  790. }
  791. HRESULT ExecuteTestWithMemoryCheck(char* fileName)
  792. {
  793. HRESULT hr = E_FAIL;
  794. #ifdef _WIN32 // looks on linux it always leak ThreadContextTLSEntry since there's no DllMain
  795. #ifdef CHECK_MEMORY_LEAK
  796. // Always check memory leak, unless user specified the flag already
  797. if (!ChakraRTInterface::IsEnabledCheckMemoryFlag())
  798. {
  799. ChakraRTInterface::SetCheckMemoryLeakFlag(true);
  800. }
  801. // Disable the output in case an unhandled exception happens
  802. // We will re-enable it if there is no unhandled exceptions
  803. ChakraRTInterface::SetEnableCheckMemoryLeakOutput(false);
  804. #endif
  805. #endif
  806. #ifdef _WIN32
  807. __try
  808. {
  809. hr = ExecuteTest(fileName);
  810. }
  811. __except (HostExceptionFilter(GetExceptionCode(), GetExceptionInformation()))
  812. {
  813. Assert(false);
  814. }
  815. #else
  816. // REVIEW: Do we need a SEH handler here?
  817. hr = ExecuteTest(fileName);
  818. if (FAILED(hr)) exit(0);
  819. #endif // _WIN32
  820. _flushall();
  821. #ifdef CHECK_MEMORY_LEAK
  822. ChakraRTInterface::SetEnableCheckMemoryLeakOutput(true);
  823. #endif
  824. return hr;
  825. }
  826. #ifdef _WIN32
  827. bool HandleJITServerFlag(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[])
  828. {
  829. LPCWSTR flag = _u("-jitserver:");
  830. LPCWSTR flagWithoutColon = _u("-jitserver");
  831. size_t flagLen = wcslen(flag);
  832. int i = 0;
  833. for (i = 1; i < argc; ++i)
  834. {
  835. if (!_wcsicmp(argv[i], flagWithoutColon))
  836. {
  837. connectionUuidString = _u("");
  838. break;
  839. }
  840. else if (!_wcsnicmp(argv[i], flag, flagLen))
  841. {
  842. connectionUuidString = argv[i] + flagLen;
  843. if (wcslen(connectionUuidString) == 0)
  844. {
  845. fwprintf(stdout, _u("[FAILED]: must pass a UUID to -jitserver:\n"));
  846. return false;
  847. }
  848. else
  849. {
  850. break;
  851. }
  852. }
  853. }
  854. if (i == argc)
  855. {
  856. return false;
  857. }
  858. // remove this flag now
  859. HostConfigFlags::RemoveArg(argc, argv, i);
  860. return true;
  861. }
  862. typedef HRESULT(WINAPI *JsInitializeJITServerPtr)(UUID* connectionUuid, void* securityDescriptor, void* alpcSecurityDescriptor);
  863. int _cdecl RunJITServer(int argc, __in_ecount(argc) LPWSTR argv[])
  864. {
  865. ChakraRTInterface::ArgInfo argInfo = { argc, argv, PrintUsage, nullptr };
  866. HINSTANCE chakraLibrary = nullptr;
  867. bool success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary);
  868. int status = 0;
  869. JsInitializeJITServerPtr initRpcServer = nullptr;
  870. if (!success)
  871. {
  872. wprintf(_u("\nDll load failed\n"));
  873. return ERROR_DLL_INIT_FAILED;
  874. }
  875. UUID connectionUuid;
  876. status = UuidFromStringW((RPC_WSTR)connectionUuidString, &connectionUuid);
  877. if (status != RPC_S_OK)
  878. {
  879. goto cleanup;
  880. }
  881. initRpcServer = (JsInitializeJITServerPtr)GetProcAddress(chakraLibrary, "JsInitializeJITServer");
  882. status = initRpcServer(&connectionUuid, nullptr, nullptr);
  883. if (FAILED(status))
  884. {
  885. wprintf(_u("InitializeJITServer failed by 0x%x\n"), status);
  886. goto cleanup;
  887. }
  888. status = 0;
  889. cleanup:
  890. if (chakraLibrary)
  891. {
  892. ChakraRTInterface::UnloadChakraDll(chakraLibrary);
  893. }
  894. return status;
  895. }
  896. #endif
  897. unsigned int WINAPI StaticThreadProc(void *lpParam)
  898. {
  899. ChakraRTInterface::ArgInfo* argInfo = static_cast<ChakraRTInterface::ArgInfo* >(lpParam);
  900. return ExecuteTestWithMemoryCheck(argInfo->filename);
  901. }
  902. #ifndef _WIN32
  903. static char16** argv = nullptr;
  904. int main(int argc, char** c_argv)
  905. {
  906. #ifndef CHAKRA_STATIC_LIBRARY
  907. // xplat-todo: PAL free CH ?
  908. PAL_InitializeChakraCore();
  909. #endif
  910. int origargc = argc; // store for clean-up later
  911. argv = new char16*[argc];
  912. for (int i = 0; i < argc; i++)
  913. {
  914. NarrowStringToWideDynamic(c_argv[i], &argv[i]);
  915. }
  916. #else
  917. #define PAL_Shutdown()
  918. int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[])
  919. {
  920. #endif
  921. #ifdef _WIN32
  922. // Set the output mode of stdout so we can display non-ASCII characters on the console and redirect to file as UTF-8
  923. {
  924. int result = _setmode(_fileno(stdout), _O_U8TEXT); // set stdout to UTF-8 mode
  925. if (result == -1)
  926. {
  927. // Failed to set mode. Undefined behavior may result, so exit now.
  928. wprintf(_u("Failed to set output stream mode. Exiting...\n"));
  929. return EXIT_FAILURE;
  930. }
  931. }
  932. bool runJITServer = HandleJITServerFlag(argc, argv);
  933. #endif
  934. int retval = -1;
  935. HRESULT exitCode = E_FAIL;
  936. int cpos = 1;
  937. HINSTANCE chakraLibrary = nullptr;
  938. bool success = false;
  939. ChakraRTInterface::ArgInfo argInfo;
  940. #ifdef _WIN32
  941. ATOM lock;
  942. #endif
  943. if (argc < 2)
  944. {
  945. PrintUsage();
  946. PAL_Shutdown();
  947. retval = EXIT_FAILURE;
  948. goto return_cleanup;
  949. }
  950. #ifdef _WIN32
  951. if (runJITServer)
  952. {
  953. retval = RunJITServer(argc, argv);
  954. goto return_cleanup;
  955. }
  956. #endif
  957. for(int i = 1; i < argc; ++i)
  958. {
  959. const wchar *arg = argv[i];
  960. size_t arglen = wcslen(arg);
  961. // support - or / prefix for flags
  962. if (arglen >= 1 && (arg[0] == _u('-')
  963. #ifdef _WIN32
  964. || arg[0] == _u('/') // '/' prefix for legacy (Windows-only because it starts a path on Unix)
  965. #endif
  966. ))
  967. {
  968. // support -- prefix for flags
  969. if (arglen >= 2 && arg[0] == _u('-') && arg[1] == _u('-'))
  970. {
  971. arg += 2; // advance past -- prefix
  972. }
  973. else
  974. {
  975. arg += 1; // advance past - or / prefix
  976. }
  977. }
  978. arglen = wcslen(arg); // get length of flag after prefix
  979. if ((arglen == 1 && wcsncmp(arg, _u("v"), arglen) == 0) ||
  980. (arglen == 7 && wcsncmp(arg, _u("version"), arglen) == 0))
  981. {
  982. PrintVersion();
  983. PAL_Shutdown();
  984. retval = EXIT_SUCCESS;
  985. goto return_cleanup;
  986. }
  987. else if (
  988. #if !defined(ENABLE_DEBUG_CONFIG_OPTIONS) // release builds can display some kind of help message
  989. (arglen == 1 && wcsncmp(arg, _u("?"), arglen) == 0) ||
  990. #endif
  991. (arglen == 1 && wcsncmp(arg, _u("h"), arglen) == 0) ||
  992. (arglen == 4 && wcsncmp(arg, _u("help"), arglen) == 0)
  993. )
  994. {
  995. PrintUsage();
  996. PAL_Shutdown();
  997. retval = EXIT_SUCCESS;
  998. goto return_cleanup;
  999. }
  1000. else if(wcsstr(argv[i], _u("-TTRecord=")) == argv[i])
  1001. {
  1002. doTTRecord = true;
  1003. wchar* ruri = argv[i] + wcslen(_u("-TTRecord="));
  1004. Helpers::GetTTDDirectory(ruri, &ttUriLength, ttUri, ttUriBufferLength);
  1005. }
  1006. else if(wcsstr(argv[i], _u("-TTReplay=")) == argv[i])
  1007. {
  1008. doTTReplay = true;
  1009. wchar* ruri = argv[i] + wcslen(_u("-TTReplay="));
  1010. Helpers::GetTTDDirectory(ruri, &ttUriLength, ttUri, ttUriBufferLength);
  1011. }
  1012. else if(wcsstr(argv[i], _u("-TTSnapInterval=")) == argv[i])
  1013. {
  1014. LPCWSTR intervalStr = argv[i] + wcslen(_u("-TTSnapInterval="));
  1015. snapInterval = (UINT32)_wtoi(intervalStr);
  1016. }
  1017. else if(wcsstr(argv[i], _u("-TTHistoryLength=")) == argv[i])
  1018. {
  1019. LPCWSTR historyStr = argv[i] + wcslen(_u("-TTHistoryLength="));
  1020. snapHistoryLength = (UINT32)_wtoi(historyStr);
  1021. }
  1022. else if(wcsstr(argv[i], _u("-TTDStartEvent=")) == argv[i])
  1023. {
  1024. LPCWSTR startEventStr = argv[i] + wcslen(_u("-TTDStartEvent="));
  1025. startEventCount = (UINT32)_wtoi(startEventStr);
  1026. }
  1027. else
  1028. {
  1029. wchar *temp = argv[cpos];
  1030. argv[cpos] = argv[i];
  1031. argv[i] = temp;
  1032. cpos++;
  1033. }
  1034. }
  1035. argc = cpos;
  1036. if(doTTRecord & doTTReplay)
  1037. {
  1038. fwprintf(stderr, _u("Cannot run in record and replay at same time!!!"));
  1039. ExitProcess(0);
  1040. }
  1041. HostConfigFlags::pfnPrintUsage = PrintUsageFormat;
  1042. // The following code is present to make sure we don't load
  1043. // jscript9.dll etc with ch. Since that isn't a concern on non-Windows
  1044. // builds, it's safe to conditionally compile it out.
  1045. #ifdef _WIN32
  1046. lock = ::AddAtom(szChakraCoreLock);
  1047. AssertMsg(lock, "failed to lock chakracore.dll");
  1048. #endif // _WIN32
  1049. HostConfigFlags::HandleArgsFlag(argc, argv);
  1050. argInfo = { argc, argv, PrintUsage, nullptr };
  1051. success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary);
  1052. #if defined(CHAKRA_STATIC_LIBRARY) && !defined(NDEBUG)
  1053. // handle command line flags
  1054. OnChakraCoreLoaded(OnChakraCoreLoadedEntry);
  1055. #endif
  1056. if (argInfo.filename == nullptr)
  1057. {
  1058. WideStringToNarrowDynamic(argv[1], &argInfo.filename);
  1059. }
  1060. if (success)
  1061. {
  1062. if (HostConfigFlags::flags.CustomConfigFile != NULL)
  1063. {
  1064. ChakraRTInterface::SetConfigFile(HostConfigFlags::flags.CustomConfigFile);
  1065. }
  1066. #ifdef _WIN32
  1067. #if ENABLE_NATIVE_CODEGEN
  1068. if (HostConfigFlags::flags.OOPJIT)
  1069. {
  1070. // TODO: Error checking
  1071. JITProcessManager::StartRpcServer(argc, argv);
  1072. ChakraRTInterface::JsConnectJITProcess(JITProcessManager::GetRpcProccessHandle(), nullptr, JITProcessManager::GetRpcConnectionId());
  1073. }
  1074. #endif
  1075. HANDLE threadHandle;
  1076. threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, &StaticThreadProc, &argInfo, STACK_SIZE_PARAM_IS_A_RESERVATION, 0));
  1077. if (threadHandle != nullptr)
  1078. {
  1079. DWORD waitResult = WaitForSingleObject(threadHandle, INFINITE);
  1080. Assert(waitResult == WAIT_OBJECT_0);
  1081. DWORD threadExitCode;
  1082. GetExitCodeThread(threadHandle, &threadExitCode);
  1083. exitCode = (HRESULT)threadExitCode;
  1084. CloseHandle(threadHandle);
  1085. }
  1086. else
  1087. {
  1088. fwprintf(stderr, _u("FATAL ERROR: failed to create worker thread error code %d, exiting\n"), errno);
  1089. AssertMsg(false, "failed to create worker thread");
  1090. }
  1091. #else
  1092. // On linux, execute on the same thread
  1093. exitCode = ExecuteTestWithMemoryCheck(argInfo.filename);
  1094. #endif
  1095. ChakraRTInterface::UnloadChakraDll(chakraLibrary);
  1096. }
  1097. #if ENABLE_NATIVE_CODEGEN && defined(_WIN32)
  1098. JITProcessManager::TerminateJITServer();
  1099. #endif
  1100. PAL_Shutdown();
  1101. retval = (int)exitCode;
  1102. return_cleanup:
  1103. #ifndef _WIN32
  1104. if(argv != nullptr)
  1105. {
  1106. for(int i=0;i<origargc;i++)
  1107. {
  1108. free(argv[i]);
  1109. argv[i] = nullptr;
  1110. }
  1111. }
  1112. delete[] argv;
  1113. argv = nullptr;
  1114. #ifdef NO_SANITIZE_ADDRESS_CHECK
  1115. pthread_exit(&retval);
  1116. #else
  1117. return retval;
  1118. #endif
  1119. #else
  1120. return retval;
  1121. #endif
  1122. }