ch.cpp 29 KB

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