ch.cpp 28 KB

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