ch.cpp 44 KB

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