ch.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  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. #include <CommonPal.h>
  8. #ifdef _WIN32
  9. #include <winver.h>
  10. #include <process.h>
  11. #endif
  12. unsigned int MessageBase::s_messageCount = 0;
  13. Debugger* Debugger::debugger = nullptr;
  14. #ifdef _WIN32
  15. LPCWSTR hostName = _u("ch.exe");
  16. #else
  17. LPCWSTR hostName = _u("ch");
  18. #endif
  19. JsRuntimeHandle chRuntime = JS_INVALID_RUNTIME_HANDLE;
  20. BOOL doTTRecord = false;
  21. BOOL doTTReplay = false;
  22. const size_t ttUriBufferLength = MAX_PATH * 3;
  23. char ttUri[ttUriBufferLength];
  24. size_t ttUriLength = 0;
  25. UINT32 snapInterval = MAXUINT32;
  26. UINT32 snapHistoryLength = MAXUINT32;
  27. LPCWSTR connectionUuidString = NULL;
  28. UINT32 startEventCount = 1;
  29. extern "C"
  30. HRESULT __stdcall OnChakraCoreLoadedEntry(TestHooks& testHooks)
  31. {
  32. return ChakraRTInterface::OnChakraCoreLoaded(testHooks);
  33. }
  34. JsRuntimeAttributes jsrtAttributes = JsRuntimeAttributeAllowScriptInterrupt;
  35. int HostExceptionFilter(int exceptionCode, _EXCEPTION_POINTERS *ep)
  36. {
  37. ChakraRTInterface::NotifyUnhandledException(ep);
  38. #if ENABLE_NATIVE_CODEGEN && _WIN32
  39. JITProcessManager::TerminateJITServer();
  40. #endif
  41. bool crashOnException = false;
  42. ChakraRTInterface::GetCrashOnExceptionFlag(&crashOnException);
  43. if (exceptionCode == EXCEPTION_BREAKPOINT || (crashOnException && exceptionCode != 0xE06D7363))
  44. {
  45. return EXCEPTION_CONTINUE_SEARCH;
  46. }
  47. fwprintf(stderr, _u("FATAL ERROR: %ls failed due to exception code %x\n"), hostName, exceptionCode);
  48. _flushall();
  49. // Exception happened, so we probably didn't clean up properly,
  50. // Don't exit normally, just terminate
  51. TerminateProcess(::GetCurrentProcess(), exceptionCode);
  52. return EXCEPTION_CONTINUE_SEARCH;
  53. }
  54. void __stdcall PrintUsageFormat()
  55. {
  56. wprintf(_u("\nUsage: %s [-v|-version] [-h|-help] [-?] [flaglist] <source file>\n"), hostName);
  57. wprintf(_u("\t-v|-version\t\tDisplays version info\n"));
  58. wprintf(_u("\t-h|-help\t\tDisplays this help message\n"));
  59. wprintf(_u("\t-?\t\t\tDisplays this help message with complete [flaglist] info\n"));
  60. }
  61. #if !defined(ENABLE_DEBUG_CONFIG_OPTIONS)
  62. void __stdcall PrintReleaseUsage()
  63. {
  64. wprintf(_u("\nUsage: %s [-v|-version] [-h|-help|-?] <source file> %s"), hostName,
  65. _u("\nNote: [flaglist] is not supported in Release builds; try a Debug or Test build to enable these flags.\n"));
  66. wprintf(_u("\t-v|-version\t\tDisplays version info\n"));
  67. wprintf(_u("\t-h|-help|-?\t\tDisplays this help message\n"));
  68. }
  69. #endif
  70. void __stdcall PrintUsage()
  71. {
  72. #if !defined(ENABLE_DEBUG_CONFIG_OPTIONS)
  73. PrintReleaseUsage();
  74. #else
  75. PrintUsageFormat();
  76. #endif
  77. }
  78. void __stdcall PrintChVersion()
  79. {
  80. #if CHAKRA_CORE_VERSION_RELEASE
  81. wprintf(_u("%s version %d.%d.%d.0\n"),
  82. #else
  83. wprintf(_u("%s version %d.%d.%d.0-beta\n"),
  84. #endif
  85. hostName, CHAKRA_CORE_MAJOR_VERSION, CHAKRA_CORE_MINOR_VERSION, CHAKRA_CORE_PATCH_VERSION);
  86. }
  87. #ifdef _WIN32
  88. void __stdcall PrintChakraCoreVersion()
  89. {
  90. char filename[_MAX_PATH];
  91. char drive[_MAX_DRIVE];
  92. char dir[_MAX_DIR];
  93. LPCSTR chakraDllName = GetChakraDllName();
  94. char modulename[_MAX_PATH];
  95. GetModuleFileNameA(NULL, modulename, _MAX_PATH);
  96. _splitpath_s(modulename, drive, _MAX_DRIVE, dir, _MAX_DIR, nullptr, 0, nullptr, 0);
  97. _makepath_s(filename, drive, dir, chakraDllName, nullptr);
  98. UINT size = 0;
  99. LPBYTE lpBuffer = NULL;
  100. DWORD verSize = GetFileVersionInfoSizeA(filename, NULL);
  101. if (verSize != NULL)
  102. {
  103. LPSTR verData = new char[verSize];
  104. if (GetFileVersionInfoA(filename, NULL, verSize, verData) &&
  105. VerQueryValue(verData, _u("\\"), (VOID FAR * FAR *)&lpBuffer, &size) &&
  106. (size != 0))
  107. {
  108. VS_FIXEDFILEINFO *verInfo = (VS_FIXEDFILEINFO *)lpBuffer;
  109. if (verInfo->dwSignature == VS_FFI_SIGNATURE)
  110. {
  111. // Doesn't matter if you are on 32 bit or 64 bit,
  112. // DWORD is always 32 bits, so first two revision numbers
  113. // come from dwFileVersionMS, last two come from dwFileVersionLS
  114. printf("%s version %d.%d.%d.%d\n",
  115. chakraDllName,
  116. (verInfo->dwFileVersionMS >> 16) & 0xffff,
  117. (verInfo->dwFileVersionMS >> 0) & 0xffff,
  118. (verInfo->dwFileVersionLS >> 16) & 0xffff,
  119. (verInfo->dwFileVersionLS >> 0) & 0xffff);
  120. }
  121. }
  122. delete[] verData;
  123. }
  124. }
  125. #endif
  126. void __stdcall PrintVersion()
  127. {
  128. PrintChVersion();
  129. #ifdef _WIN32
  130. PrintChakraCoreVersion();
  131. #endif
  132. }
  133. // On success the param byteCodeBuffer will be allocated in the function.
  134. HRESULT GetSerializedBuffer(LPCSTR fileContents, JsValueRef *byteCodeBuffer)
  135. {
  136. HRESULT hr = S_OK;
  137. JsValueRef scriptSource;
  138. IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
  139. (unsigned int)strlen(fileContents), nullptr, nullptr, &scriptSource));
  140. IfJsErrorFailLog(ChakraRTInterface::JsSerialize(scriptSource, byteCodeBuffer,
  141. JsParseScriptAttributeNone));
  142. Error:
  143. return hr;
  144. }
  145. HRESULT CreateLibraryByteCodeHeader(LPCSTR contentsRaw, DWORD lengthBytes, LPCWSTR bcFullPath, LPCSTR libraryNameNarrow)
  146. {
  147. HANDLE bcFileHandle = nullptr;
  148. JsValueRef bufferVal;
  149. BYTE *bcBuffer = nullptr;
  150. unsigned int bcBufferSize = 0;
  151. DWORD written;
  152. // For validating the header file against the library file
  153. auto outputStr =
  154. "//-------------------------------------------------------------------------------------------------------\r\n"
  155. "// Copyright (C) Microsoft. All rights reserved.\r\n"
  156. "// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.\r\n"
  157. "//-------------------------------------------------------------------------------------------------------\r\n"
  158. "#if 0\r\n";
  159. HRESULT hr = GetSerializedBuffer(contentsRaw, &bufferVal);
  160. if (FAILED(hr)) return hr;
  161. IfJsrtErrorHR(ChakraRTInterface::JsGetArrayBufferStorage(bufferVal, &bcBuffer, &bcBufferSize));
  162. bcFileHandle = CreateFile(bcFullPath, GENERIC_WRITE, FILE_SHARE_DELETE,
  163. nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
  164. if (bcFileHandle == INVALID_HANDLE_VALUE)
  165. {
  166. return E_FAIL;
  167. }
  168. IfFalseGo(WriteFile(bcFileHandle, outputStr, (DWORD)strlen(outputStr), &written, nullptr));
  169. IfFalseGo(WriteFile(bcFileHandle, contentsRaw, lengthBytes, &written, nullptr));
  170. if (lengthBytes < 2 || contentsRaw[lengthBytes - 2] != '\r' || contentsRaw[lengthBytes - 1] != '\n')
  171. {
  172. outputStr = "\r\n#endif\r\n";
  173. }
  174. else
  175. {
  176. outputStr = "#endif\r\n";
  177. }
  178. IfFalseGo(WriteFile(bcFileHandle, outputStr, (DWORD)strlen(outputStr), &written, nullptr));
  179. // Write out the bytecode
  180. outputStr = "namespace Js\r\n{\r\n const char Library_Bytecode_";
  181. IfFalseGo(WriteFile(bcFileHandle, outputStr, (DWORD)strlen(outputStr), &written, nullptr));
  182. IfFalseGo(WriteFile(bcFileHandle, libraryNameNarrow, (DWORD)strlen(libraryNameNarrow), &written, nullptr));
  183. outputStr = "[] = {\r\n/* 00000000 */";
  184. IfFalseGo(WriteFile(bcFileHandle, outputStr, (DWORD)strlen(outputStr), &written, nullptr));
  185. for (unsigned int i = 0; i < bcBufferSize; i++)
  186. {
  187. char scratch[6];
  188. auto scratchLen = sizeof(scratch);
  189. int num = _snprintf_s(scratch, scratchLen, _countof(scratch), " 0x%02X", bcBuffer[i]);
  190. Assert(num == 5);
  191. IfFalseGo(WriteFile(bcFileHandle, scratch, (DWORD)(scratchLen - 1), &written, nullptr));
  192. // Add a comma and a space if this is not the last item
  193. if (i < bcBufferSize - 1)
  194. {
  195. char commaSpace[2];
  196. _snprintf_s(commaSpace, sizeof(commaSpace), _countof(commaSpace), ","); // close quote, new line, offset and open quote
  197. IfFalseGo(WriteFile(bcFileHandle, commaSpace, (DWORD)strlen(commaSpace), &written, nullptr));
  198. }
  199. // Add a line break every 16 scratches, primarily so the compiler doesn't complain about the string being too long.
  200. // Also, won't add for the last scratch
  201. if (i % 16 == 15 && i < bcBufferSize - 1)
  202. {
  203. char offset[17];
  204. _snprintf_s(offset, sizeof(offset), _countof(offset), "\r\n/* %08X */", i + 1); // close quote, new line, offset and open quote
  205. IfFalseGo(WriteFile(bcFileHandle, offset, (DWORD)strlen(offset), &written, nullptr));
  206. }
  207. }
  208. outputStr = "};\r\n\r\n";
  209. IfFalseGo(WriteFile(bcFileHandle, outputStr, (DWORD)strlen(outputStr), &written, nullptr));
  210. outputStr = "}\r\n";
  211. IfFalseGo(WriteFile(bcFileHandle, outputStr, (DWORD)strlen(outputStr), &written, nullptr));
  212. Error:
  213. if (bcFileHandle != nullptr)
  214. {
  215. CloseHandle(bcFileHandle);
  216. }
  217. return hr;
  218. }
  219. static void CALLBACK PromiseContinuationCallback(JsValueRef task, void *callbackState)
  220. {
  221. Assert(task != JS_INVALID_REFERENCE);
  222. Assert(callbackState != JS_INVALID_REFERENCE);
  223. MessageQueue * messageQueue = (MessageQueue *)callbackState;
  224. WScriptJsrt::CallbackMessage *msg = new WScriptJsrt::CallbackMessage(0, task);
  225. messageQueue->InsertSorted(msg);
  226. }
  227. static bool CHAKRA_CALLBACK DummyJsSerializedScriptLoadUtf8Source(
  228. JsSourceContext sourceContext,
  229. JsValueRef* scriptBuffer,
  230. JsParseScriptAttributes *parseAttributes)
  231. {
  232. const char* script = reinterpret_cast<const char*>(sourceContext);
  233. size_t length = strlen(script);
  234. // sourceContext is source ptr, see RunScript below
  235. if (ChakraRTInterface::JsCreateExternalArrayBuffer((void*)script, (unsigned int)length,
  236. [](void* data)
  237. {
  238. // sourceContext is source ptr, see RunScript below
  239. // source memory was originally allocated with malloc() in
  240. // Helpers::LoadScriptFromFile. No longer needed, free() it.
  241. free(data);
  242. }, nullptr, scriptBuffer) != JsNoError)
  243. {
  244. return false;
  245. }
  246. *parseAttributes = JsParseScriptAttributeNone;
  247. return true;
  248. }
  249. HRESULT RunScript(const char* fileName, LPCSTR fileContents, JsValueRef bufferValue, char *fullPath)
  250. {
  251. HRESULT hr = S_OK;
  252. MessageQueue * messageQueue = new MessageQueue();
  253. WScriptJsrt::AddMessageQueue(messageQueue);
  254. IfJsErrorFailLog(ChakraRTInterface::JsSetPromiseContinuationCallback(PromiseContinuationCallback, (void*)messageQueue));
  255. if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0)
  256. {
  257. #if !ENABLE_TTD
  258. wprintf(_u("Sential js file is only ok when in TTDebug mode!!!\n"));
  259. return E_FAIL;
  260. #else
  261. if(!doTTReplay)
  262. {
  263. wprintf(_u("Sential js file is only ok when in TTReplay mode!!!\n"));
  264. return E_FAIL;
  265. }
  266. IfFailedReturn(ChakraRTInterface::JsTTDStart());
  267. try
  268. {
  269. JsTTDMoveMode moveMode = JsTTDMoveMode::JsTTDMoveKthEvent;
  270. int64_t snapEventTime = -1;
  271. int64_t nextEventTime = -2;
  272. while(true)
  273. {
  274. JsErrorCode error = ChakraRTInterface::JsTTDGetSnapTimeTopLevelEventMove(chRuntime, moveMode, startEventCount, &nextEventTime, &snapEventTime, nullptr);
  275. if(error != JsNoError)
  276. {
  277. if(error == JsErrorCategoryUsage)
  278. {
  279. wprintf(_u("Start time not in log range.\n"));
  280. }
  281. return error;
  282. }
  283. IfFailedReturn(ChakraRTInterface::JsTTDMoveToTopLevelEvent(chRuntime, moveMode, snapEventTime, nextEventTime));
  284. JsErrorCode res = ChakraRTInterface::JsTTDReplayExecution(&moveMode, &nextEventTime);
  285. //handle any uncaught exception by immediately time-traveling to the throwing line in the debugger -- in replay just report and exit
  286. if(res == JsErrorCategoryScript)
  287. {
  288. wprintf(_u("An unhandled script exception occoured!!!\n"));
  289. ExitProcess(0);
  290. }
  291. if(nextEventTime == -1)
  292. {
  293. wprintf(_u("\nReached end of Execution -- Exiting.\n"));
  294. break;
  295. }
  296. }
  297. }
  298. catch(...)
  299. {
  300. wprintf(_u("Terminal exception in Replay -- exiting.\n"));
  301. ExitProcess(0);
  302. }
  303. #endif
  304. }
  305. else
  306. {
  307. Assert(fileContents != nullptr || bufferValue != nullptr);
  308. JsErrorCode runScript;
  309. JsValueRef fname;
  310. IfJsErrorFailLog(ChakraRTInterface::JsCreateString(fullPath,
  311. strlen(fullPath), &fname));
  312. if(bufferValue != nullptr)
  313. {
  314. runScript = ChakraRTInterface::JsRunSerialized(
  315. bufferValue,
  316. DummyJsSerializedScriptLoadUtf8Source,
  317. reinterpret_cast<JsSourceContext>(fileContents),
  318. // Use source ptr as sourceContext
  319. fname, nullptr /*result*/);
  320. }
  321. else
  322. {
  323. JsValueRef scriptSource;
  324. IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents,
  325. (unsigned int)strlen(fileContents),
  326. [](void *data)
  327. {
  328. free(data);
  329. }, nullptr, &scriptSource));
  330. #if ENABLE_TTD
  331. if(doTTRecord)
  332. {
  333. JsPropertyIdRef ttProperty = nullptr;
  334. JsValueRef ttString = nullptr;
  335. JsValueRef global = nullptr;
  336. IfFailedReturn(ChakraRTInterface::JsCreatePropertyId("ttdLogURI", strlen("ttdLogURI"), &ttProperty));
  337. IfFailedReturn(ChakraRTInterface::JsCreateString(ttUri, ttUriLength, &ttString));
  338. IfFailedReturn(ChakraRTInterface::JsGetGlobalObject(&global));
  339. IfFailedReturn(ChakraRTInterface::JsSetProperty(global, ttProperty, ttString, false));
  340. IfFailedReturn(ChakraRTInterface::JsTTDStart());
  341. }
  342. runScript = ChakraRTInterface::JsRun(scriptSource,
  343. WScriptJsrt::GetNextSourceContext(), fname,
  344. JsParseScriptAttributeNone, nullptr /*result*/);
  345. if (runScript == JsErrorCategoryUsage)
  346. {
  347. wprintf(_u("FATAL ERROR: Core was compiled without ENABLE_TTD is defined. CH is trying to use TTD interface\n"));
  348. abort();
  349. }
  350. #else
  351. runScript = ChakraRTInterface::JsRun(scriptSource,
  352. WScriptJsrt::GetNextSourceContext(), fname,
  353. JsParseScriptAttributeNone,
  354. nullptr /*result*/);
  355. #endif
  356. }
  357. //Do a yield after the main script body executes
  358. ChakraRTInterface::JsTTDNotifyYield();
  359. if(runScript != JsNoError)
  360. {
  361. WScriptJsrt::PrintException(fileName, runScript);
  362. }
  363. else
  364. {
  365. // Repeatedly flush the message queue until it's empty. It is necessary to loop on this
  366. // because setTimeout can add scripts to execute.
  367. do
  368. {
  369. IfFailGo(messageQueue->ProcessAll(fileName));
  370. } while(!messageQueue->IsEmpty());
  371. }
  372. }
  373. Error:
  374. #if ENABLE_TTD
  375. if(doTTRecord)
  376. {
  377. IfFailedReturn(ChakraRTInterface::JsTTDStop());
  378. }
  379. #endif
  380. if (messageQueue != nullptr)
  381. {
  382. messageQueue->RemoveAll();
  383. // clean up possible pinned exception object on exit to avoid potential leak
  384. bool hasException;
  385. if (ChakraRTInterface::JsHasException(&hasException) == JsNoError && hasException)
  386. {
  387. JsValueRef exception = JS_INVALID_REFERENCE;
  388. ChakraRTInterface::JsGetAndClearException(&exception);
  389. }
  390. delete messageQueue;
  391. }
  392. // We only call RunScript() once, safe to Uninitialize()
  393. WScriptJsrt::Uninitialize();
  394. return hr;
  395. }
  396. static HRESULT CreateRuntime(JsRuntimeHandle *runtime)
  397. {
  398. HRESULT hr = E_FAIL;
  399. IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, runtime));
  400. #ifndef _WIN32
  401. // On Posix, malloc may not return NULL even if there is no
  402. // memory left. However, kernel will send SIGKILL to process
  403. // in case we use that `not actually available` memory address.
  404. // (See posix man malloc and OOM)
  405. size_t memoryLimit;
  406. if (PlatformAgnostic::SystemInfo::GetTotalRam(&memoryLimit))
  407. {
  408. IfJsErrorFailLog(ChakraRTInterface::JsSetRuntimeMemoryLimit(*runtime, memoryLimit));
  409. }
  410. #endif
  411. hr = S_OK;
  412. Error:
  413. return hr;
  414. }
  415. HRESULT CreateAndRunSerializedScript(const char* fileName, LPCSTR fileContents, char *fullPath)
  416. {
  417. HRESULT hr = S_OK;
  418. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  419. JsContextRef context = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
  420. JsValueRef bufferVal;
  421. IfFailGo(GetSerializedBuffer(fileContents, &bufferVal));
  422. // Bytecode buffer is created in one runtime and will be executed on different runtime.
  423. IfFailGo(CreateRuntime(&runtime));
  424. chRuntime = runtime;
  425. IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context));
  426. IfJsErrorFailLog(ChakraRTInterface::JsGetCurrentContext(&current));
  427. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  428. // Initialized the WScript object on the new context
  429. if (!WScriptJsrt::Initialize())
  430. {
  431. IfFailGo(E_FAIL);
  432. }
  433. IfFailGo(RunScript(fileName, fileContents, bufferVal, fullPath));
  434. Error:
  435. if (current != JS_INVALID_REFERENCE)
  436. {
  437. ChakraRTInterface::JsSetCurrentContext(current);
  438. }
  439. if (runtime != JS_INVALID_RUNTIME_HANDLE)
  440. {
  441. ChakraRTInterface::JsDisposeRuntime(runtime);
  442. }
  443. return hr;
  444. }
  445. HRESULT ExecuteTest(const char* fileName)
  446. {
  447. HRESULT hr = S_OK;
  448. LPCSTR fileContents = nullptr;
  449. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  450. UINT lengthBytes = 0;
  451. if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0)
  452. {
  453. #if !ENABLE_TTD
  454. wprintf(_u("Sentinel js file is only ok when in TTDebug mode!!!\n"));
  455. return E_FAIL;
  456. #else
  457. if(!doTTReplay)
  458. {
  459. wprintf(_u("Sentinel js file is only ok when in TTReplay mode!!!\n"));
  460. return E_FAIL;
  461. }
  462. jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures);
  463. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateReplayRuntime(jsrtAttributes, ttUri, ttUriLength, Helpers::TTCreateStreamCallback, Helpers::TTReadBytesFromStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime));
  464. chRuntime = runtime;
  465. JsContextRef context = JS_INVALID_REFERENCE;
  466. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context));
  467. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  468. IfFailGo(RunScript(fileName, fileContents, nullptr, nullptr));
  469. unsigned int rcount = 0;
  470. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(nullptr));
  471. ChakraRTInterface::JsRelease(context, &rcount);
  472. AssertMsg(rcount == 0, "Should only have had 1 ref from replay code and one ref from current context??");
  473. #endif
  474. }
  475. else
  476. {
  477. LPCOLESTR contentsRaw = nullptr;
  478. char fullPath[_MAX_PATH];
  479. size_t len = 0;
  480. hr = Helpers::LoadScriptFromFile(fileName, fileContents, &lengthBytes);
  481. contentsRaw; lengthBytes; // Unused for now.
  482. IfFailGo(hr);
  483. if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled)
  484. {
  485. jsrtAttributes = (JsRuntimeAttributes)(jsrtAttributes | JsRuntimeAttributeSerializeLibraryByteCode);
  486. }
  487. #if ENABLE_TTD
  488. if (doTTRecord)
  489. {
  490. //Ensure we run with experimental features (as that is what Node does right now).
  491. jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures);
  492. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateRecordRuntime(jsrtAttributes, snapInterval, snapHistoryLength, Helpers::TTCreateStreamCallback, Helpers::TTWriteBytesToStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime));
  493. chRuntime = runtime;
  494. JsContextRef context = JS_INVALID_REFERENCE;
  495. IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context));
  496. #if ENABLE_TTD
  497. //We need this here since this context is created in record
  498. IfJsErrorFailLog(ChakraRTInterface::JsSetObjectBeforeCollectCallback(context, nullptr, WScriptJsrt::JsContextBeforeCollectCallback));
  499. #endif
  500. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  501. }
  502. else
  503. {
  504. AssertMsg(!doTTReplay, "Should be handled in the else case above!!!");
  505. IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime));
  506. chRuntime = runtime;
  507. if (HostConfigFlags::flags.DebugLaunch)
  508. {
  509. Debugger* debugger = Debugger::GetDebugger(runtime);
  510. debugger->StartDebugging(runtime);
  511. }
  512. JsContextRef context = JS_INVALID_REFERENCE;
  513. IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context));
  514. //Don't need collect callback since this is always in replay
  515. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  516. }
  517. #else
  518. IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime));
  519. chRuntime = runtime;
  520. if (HostConfigFlags::flags.DebugLaunch)
  521. {
  522. Debugger* debugger = Debugger::GetDebugger(runtime);
  523. debugger->StartDebugging(runtime);
  524. }
  525. JsContextRef context = JS_INVALID_REFERENCE;
  526. IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context));
  527. IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context));
  528. #endif
  529. #ifdef DEBUG
  530. ChakraRTInterface::SetCheckOpHelpersFlag(true);
  531. #endif
  532. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  533. ChakraRTInterface::SetOOPCFGRegistrationFlag(false);
  534. #endif
  535. if (!WScriptJsrt::Initialize())
  536. {
  537. IfFailGo(E_FAIL);
  538. }
  539. if (_fullpath(fullPath, fileName, _MAX_PATH) == nullptr)
  540. {
  541. IfFailGo(E_FAIL);
  542. }
  543. // canonicalize that path name to lower case for the profile storage
  544. // REVIEW: Assuming no utf8 characters here
  545. len = strlen(fullPath);
  546. for (size_t i = 0; i < len; i++)
  547. {
  548. fullPath[i] = (char)tolower(fullPath[i]);
  549. }
  550. if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled)
  551. {
  552. if (HostConfigFlags::flags.GenerateLibraryByteCodeHeader != nullptr && *HostConfigFlags::flags.GenerateLibraryByteCodeHeader != _u('\0'))
  553. {
  554. CHAR libraryName[_MAX_PATH];
  555. CHAR ext[_MAX_EXT];
  556. _splitpath_s(fullPath, NULL, 0, NULL, 0, libraryName, _countof(libraryName), ext, _countof(ext));
  557. IfFailGo(CreateLibraryByteCodeHeader(fileContents, lengthBytes, HostConfigFlags::flags.GenerateLibraryByteCodeHeader, libraryName));
  558. }
  559. else
  560. {
  561. fwprintf(stderr, _u("FATAL ERROR: -GenerateLibraryByteCodeHeader must provide the file name, i.e., -GenerateLibraryByteCodeHeader:<bytecode file name>, exiting\n"));
  562. IfFailGo(E_FAIL);
  563. }
  564. }
  565. else if (HostConfigFlags::flags.SerializedIsEnabled)
  566. {
  567. CreateAndRunSerializedScript(fileName, fileContents, fullPath);
  568. }
  569. else
  570. {
  571. IfFailGo(RunScript(fileName, fileContents, nullptr, fullPath));
  572. }
  573. }
  574. Error:
  575. if (Debugger::debugger != nullptr)
  576. {
  577. Debugger::debugger->CompareOrWriteBaselineFile(fileName);
  578. Debugger::CloseDebugger();
  579. }
  580. ChakraRTInterface::JsSetCurrentContext(nullptr);
  581. if (runtime != JS_INVALID_RUNTIME_HANDLE)
  582. {
  583. ChakraRTInterface::JsDisposeRuntime(runtime);
  584. }
  585. _flushall();
  586. return hr;
  587. }
  588. HRESULT ExecuteTestWithMemoryCheck(char* fileName)
  589. {
  590. HRESULT hr = E_FAIL;
  591. #ifdef _WIN32 // looks on linux it always leak ThreadContextTLSEntry since there's no DllMain
  592. #ifdef CHECK_MEMORY_LEAK
  593. // Always check memory leak, unless user specified the flag already
  594. if (!ChakraRTInterface::IsEnabledCheckMemoryFlag())
  595. {
  596. ChakraRTInterface::SetCheckMemoryLeakFlag(true);
  597. }
  598. // Disable the output in case an unhandled exception happens
  599. // We will re-enable it if there is no unhandled exceptions
  600. ChakraRTInterface::SetEnableCheckMemoryLeakOutput(false);
  601. #endif
  602. #endif
  603. #ifdef _WIN32
  604. __try
  605. {
  606. hr = ExecuteTest(fileName);
  607. }
  608. __except (HostExceptionFilter(GetExceptionCode(), GetExceptionInformation()))
  609. {
  610. Assert(false);
  611. }
  612. #else
  613. // REVIEW: Do we need a SEH handler here?
  614. hr = ExecuteTest(fileName);
  615. if (FAILED(hr)) exit(0);
  616. #endif // _WIN32
  617. _flushall();
  618. #ifdef CHECK_MEMORY_LEAK
  619. ChakraRTInterface::SetEnableCheckMemoryLeakOutput(true);
  620. #endif
  621. return hr;
  622. }
  623. #ifdef _WIN32
  624. bool HandleJITServerFlag(int& argc, _Inout_updates_to_(argc, argc) LPWSTR argv[])
  625. {
  626. LPCWSTR flag = L"-jitserver:";
  627. LPCWSTR flagWithoutColon = L"-jitserver";
  628. size_t flagLen = wcslen(flag);
  629. int i = 0;
  630. for (i = 1; i < argc; ++i)
  631. {
  632. if (!_wcsicmp(argv[i], flagWithoutColon))
  633. {
  634. connectionUuidString = L"";
  635. break;
  636. }
  637. else if (!_wcsnicmp(argv[i], flag, flagLen))
  638. {
  639. connectionUuidString = argv[i] + flagLen;
  640. if (wcslen(connectionUuidString) == 0)
  641. {
  642. fwprintf(stdout, L"[FAILED]: must pass a UUID to -jitserver:\n");
  643. return false;
  644. }
  645. else
  646. {
  647. break;
  648. }
  649. }
  650. }
  651. if (i == argc)
  652. {
  653. return false;
  654. }
  655. // remove this flag now
  656. HostConfigFlags::RemoveArg(argc, argv, i);
  657. return true;
  658. }
  659. typedef HRESULT(WINAPI *JsInitializeJITServerPtr)(UUID* connectionUuid, void* securityDescriptor, void* alpcSecurityDescriptor);
  660. int _cdecl RunJITServer(int argc, __in_ecount(argc) LPWSTR argv[])
  661. {
  662. ChakraRTInterface::ArgInfo argInfo = { argc, argv, PrintUsage, nullptr };
  663. HINSTANCE chakraLibrary = nullptr;
  664. bool success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary);
  665. if (!success)
  666. {
  667. wprintf(L"\nDll load failed\n");
  668. return ERROR_DLL_INIT_FAILED;
  669. }
  670. UUID connectionUuid;
  671. DWORD status = UuidFromStringW((RPC_WSTR)connectionUuidString, &connectionUuid);
  672. if (status != RPC_S_OK)
  673. {
  674. return status;
  675. }
  676. JsInitializeJITServerPtr initRpcServer = (JsInitializeJITServerPtr)GetProcAddress(chakraLibrary, "JsInitializeJITServer");
  677. HRESULT hr = initRpcServer(&connectionUuid, nullptr, nullptr);
  678. if (FAILED(hr))
  679. {
  680. wprintf(L"InitializeJITServer failed by 0x%x\n", hr);
  681. return hr;
  682. }
  683. if (chakraLibrary)
  684. {
  685. ChakraRTInterface::UnloadChakraDll(chakraLibrary);
  686. }
  687. return 0;
  688. }
  689. #endif
  690. unsigned int WINAPI StaticThreadProc(void *lpParam)
  691. {
  692. ChakraRTInterface::ArgInfo* argInfo = static_cast<ChakraRTInterface::ArgInfo* >(lpParam);
  693. return ExecuteTestWithMemoryCheck(argInfo->filename);
  694. }
  695. #ifndef _WIN32
  696. static char16** argv = nullptr;
  697. int main(int argc, char** c_argv)
  698. {
  699. #ifndef CHAKRA_STATIC_LIBRARY
  700. // xplat-todo: PAL free CH ?
  701. PAL_InitializeChakraCore();
  702. #endif
  703. argv = new char16*[argc];
  704. for (int i = 0; i < argc; i++)
  705. {
  706. NarrowStringToWideDynamic(c_argv[i], &argv[i]);
  707. }
  708. #else
  709. #define PAL_Shutdown()
  710. int _cdecl wmain(int argc, __in_ecount(argc) LPWSTR argv[])
  711. {
  712. #endif
  713. #ifdef _WIN32
  714. bool runJITServer = HandleJITServerFlag(argc, argv);
  715. #endif
  716. if (argc < 2)
  717. {
  718. PrintUsage();
  719. PAL_Shutdown();
  720. return EXIT_FAILURE;
  721. }
  722. #ifdef _WIN32
  723. if (runJITServer)
  724. {
  725. return RunJITServer(argc, argv);
  726. }
  727. #endif
  728. int cpos = 1;
  729. for(int i = 1; i < argc; ++i)
  730. {
  731. const wchar *arg = argv[i];
  732. size_t arglen = wcslen(arg);
  733. // support - or / prefix for flags
  734. if (arglen >= 1 && (arg[0] == _u('-')
  735. #ifdef _WIN32
  736. || arg[0] == _u('/') // '/' prefix for legacy (Windows-only because it starts a path on Unix)
  737. #endif
  738. ))
  739. {
  740. // support -- prefix for flags
  741. if (arglen >= 2 && arg[0] == _u('-') && arg[1] == _u('-'))
  742. {
  743. arg += 2; // advance past -- prefix
  744. }
  745. else
  746. {
  747. arg += 1; // advance past - or / prefix
  748. }
  749. }
  750. arglen = wcslen(arg); // get length of flag after prefix
  751. if ((arglen == 1 && wcsncmp(arg, _u("v"), arglen) == 0) ||
  752. (arglen == 7 && wcsncmp(arg, _u("version"), arglen) == 0))
  753. {
  754. PrintVersion();
  755. PAL_Shutdown();
  756. return EXIT_SUCCESS;
  757. }
  758. else if (
  759. #if !defined(ENABLE_DEBUG_CONFIG_OPTIONS) // release builds can display some kind of help message
  760. (arglen == 1 && wcsncmp(arg, _u("?"), arglen) == 0) ||
  761. #endif
  762. (arglen == 1 && wcsncmp(arg, _u("h"), arglen) == 0) ||
  763. (arglen == 4 && wcsncmp(arg, _u("help"), arglen) == 0)
  764. )
  765. {
  766. PrintUsage();
  767. PAL_Shutdown();
  768. return EXIT_SUCCESS;
  769. }
  770. else if(wcsstr(argv[i], _u("-TTRecord=")) == argv[i])
  771. {
  772. doTTRecord = true;
  773. wchar* ruri = argv[i] + wcslen(_u("-TTRecord="));
  774. Helpers::GetTTDDirectory(ruri, &ttUriLength, ttUri, ttUriBufferLength);
  775. }
  776. else if(wcsstr(argv[i], _u("-TTReplay=")) == argv[i])
  777. {
  778. doTTReplay = true;
  779. wchar* ruri = argv[i] + wcslen(_u("-TTReplay="));
  780. Helpers::GetTTDDirectory(ruri, &ttUriLength, ttUri, ttUriBufferLength);
  781. }
  782. else if(wcsstr(argv[i], _u("-TTSnapInterval=")) == argv[i])
  783. {
  784. LPCWSTR intervalStr = argv[i] + wcslen(_u("-TTSnapInterval="));
  785. snapInterval = (UINT32)_wtoi(intervalStr);
  786. }
  787. else if(wcsstr(argv[i], _u("-TTHistoryLength=")) == argv[i])
  788. {
  789. LPCWSTR historyStr = argv[i] + wcslen(_u("-TTHistoryLength="));
  790. snapHistoryLength = (UINT32)_wtoi(historyStr);
  791. }
  792. else if(wcsstr(argv[i], _u("-TTDStartEvent=")) == argv[i])
  793. {
  794. LPCWSTR startEventStr = argv[i] + wcslen(_u("-TTDStartEvent="));
  795. startEventCount = (UINT32)_wtoi(startEventStr);
  796. }
  797. else
  798. {
  799. argv[cpos] = argv[i];
  800. cpos++;
  801. }
  802. }
  803. argc = cpos;
  804. if(doTTRecord & doTTReplay)
  805. {
  806. fwprintf(stderr, _u("Cannot run in record and replay at same time!!!"));
  807. ExitProcess(0);
  808. }
  809. HostConfigFlags::pfnPrintUsage = PrintUsageFormat;
  810. // The following code is present to make sure we don't load
  811. // jscript9.dll etc with ch. Since that isn't a concern on non-Windows
  812. // builds, it's safe to conditionally compile it out.
  813. #ifdef _WIN32
  814. ATOM lock = ::AddAtom(szChakraCoreLock);
  815. AssertMsg(lock, "failed to lock chakracore.dll");
  816. #endif // _WIN32
  817. HostConfigFlags::HandleArgsFlag(argc, argv);
  818. ChakraRTInterface::ArgInfo argInfo = { argc, argv, PrintUsage, nullptr };
  819. HINSTANCE chakraLibrary = nullptr;
  820. bool success = ChakraRTInterface::LoadChakraDll(&argInfo, &chakraLibrary);
  821. #if defined(CHAKRA_STATIC_LIBRARY) && !defined(NDEBUG)
  822. // handle command line flags
  823. OnChakraCoreLoaded(OnChakraCoreLoadedEntry);
  824. #endif
  825. if (argInfo.filename == nullptr)
  826. {
  827. WideStringToNarrowDynamic(argv[1], &argInfo.filename);
  828. }
  829. HRESULT exitCode = E_FAIL;
  830. if (success)
  831. {
  832. #ifdef _WIN32
  833. #if ENABLE_NATIVE_CODEGEN
  834. if (HostConfigFlags::flags.OOPJIT)
  835. {
  836. // TODO: Error checking
  837. JITProcessManager::StartRpcServer(argc, argv);
  838. ChakraRTInterface::ConnectJITServer(JITProcessManager::GetRpcProccessHandle(), nullptr, JITProcessManager::GetRpcConnectionId());
  839. }
  840. #endif
  841. HANDLE threadHandle;
  842. threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(0, 0, &StaticThreadProc, &argInfo, STACK_SIZE_PARAM_IS_A_RESERVATION, 0));
  843. if (threadHandle != nullptr)
  844. {
  845. DWORD waitResult = WaitForSingleObject(threadHandle, INFINITE);
  846. Assert(waitResult == WAIT_OBJECT_0);
  847. DWORD threadExitCode;
  848. GetExitCodeThread(threadHandle, &threadExitCode);
  849. exitCode = (HRESULT)threadExitCode;
  850. CloseHandle(threadHandle);
  851. }
  852. else
  853. {
  854. fwprintf(stderr, _u("FATAL ERROR: failed to create worker thread error code %d, exiting\n"), errno);
  855. AssertMsg(false, "failed to create worker thread");
  856. }
  857. #else
  858. // On linux, execute on the same thread
  859. exitCode = ExecuteTestWithMemoryCheck(argInfo.filename);
  860. #endif
  861. ChakraRTInterface::UnloadChakraDll(chakraLibrary);
  862. }
  863. #if ENABLE_NATIVE_CODEGEN && defined(_WIN32)
  864. JITProcessManager::TerminateJITServer();
  865. #endif
  866. PAL_Shutdown();
  867. return (int)exitCode;
  868. }