WScriptJsrt.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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. MessageQueue* WScriptJsrt::messageQueue = nullptr;
  7. DWORD_PTR WScriptJsrt::sourceContext = 0;
  8. DWORD_PTR WScriptJsrt::GetNextSourceContext()
  9. {
  10. return sourceContext++;
  11. }
  12. bool WScriptJsrt::CreateArgumentsObject(JsValueRef *argsObject)
  13. {
  14. LPWSTR *argv = HostConfigFlags::argsVal;
  15. JsValueRef retArr;
  16. Assert(argsObject);
  17. *argsObject = nullptr;
  18. IfJsrtErrorFail(ChakraRTInterface::JsCreateArray(HostConfigFlags::argsCount, &retArr), false);
  19. for (int i = 0; i < HostConfigFlags::argsCount; i++)
  20. {
  21. JsValueRef value;
  22. JsValueRef index;
  23. IfJsrtErrorFail(ChakraRTInterface::JsPointerToString(argv[i], wcslen(argv[i]), &value), false);
  24. IfJsrtErrorFail(ChakraRTInterface::JsDoubleToNumber(i, &index), false);
  25. IfJsrtErrorFail(ChakraRTInterface::JsSetIndexedProperty(retArr, index, value), false);
  26. }
  27. *argsObject = retArr;
  28. return true;
  29. }
  30. JsValueRef __stdcall WScriptJsrt::EchoCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  31. {
  32. for (unsigned int i = 1; i < argumentCount; i++)
  33. {
  34. JsValueRef strValue;
  35. JsErrorCode error = ChakraRTInterface::JsConvertValueToString(arguments[i], &strValue);
  36. if (error == JsNoError)
  37. {
  38. LPCWSTR str = nullptr;
  39. size_t length;
  40. error = ChakraRTInterface::JsStringToPointer(strValue, &str, &length);
  41. if (error == JsNoError)
  42. {
  43. if (i > 1)
  44. {
  45. wprintf(_u(" "));
  46. }
  47. wprintf(_u("%ls"), str);
  48. }
  49. }
  50. if (error == JsErrorScriptException)
  51. {
  52. return nullptr;
  53. }
  54. }
  55. wprintf(_u("\n"));
  56. fflush(stdout);
  57. JsValueRef undefinedValue;
  58. if (ChakraRTInterface::JsGetUndefinedValue(&undefinedValue) == JsNoError)
  59. {
  60. return undefinedValue;
  61. }
  62. else
  63. {
  64. return nullptr;
  65. }
  66. }
  67. JsValueRef __stdcall WScriptJsrt::QuitCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  68. {
  69. int exitCode = 0;
  70. if (argumentCount > 1)
  71. {
  72. double exitCodeDouble;
  73. IfJsrtErrorFail(ChakraRTInterface::JsNumberToDouble(arguments[1], &exitCodeDouble), JS_INVALID_REFERENCE);
  74. exitCode = (int)exitCodeDouble;
  75. }
  76. ExitProcess(exitCode);
  77. }
  78. JsValueRef __stdcall WScriptJsrt::LoadModuleFileCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  79. {
  80. return LoadScriptFileHelper(callee, arguments, argumentCount, true);
  81. }
  82. JsValueRef __stdcall WScriptJsrt::LoadScriptFileCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  83. {
  84. return LoadScriptFileHelper(callee, arguments, argumentCount, false);
  85. }
  86. JsValueRef WScriptJsrt::LoadScriptFileHelper(JsValueRef callee, JsValueRef *arguments, unsigned short argumentCount, bool isSourceModule)
  87. {
  88. HRESULT hr = E_FAIL;
  89. JsValueRef returnValue = JS_INVALID_REFERENCE;
  90. JsErrorCode errorCode = JsNoError;
  91. LPCWSTR errorMessage = _u("");
  92. if (argumentCount < 2 || argumentCount > 4)
  93. {
  94. errorCode = JsErrorInvalidArgument;
  95. errorMessage = _u("Need more or fewer arguments for WScript.LoadScript");
  96. }
  97. else
  98. {
  99. const wchar_t *fileContent;
  100. const wchar_t *fileName;
  101. const wchar_t *scriptInjectType = _u("self");
  102. size_t fileNameLength;
  103. size_t scriptInjectTypeLength;
  104. char *fileNameNarrow;
  105. IfJsrtErrorSetGo(ChakraRTInterface::JsStringToPointer(arguments[1], &fileName, &fileNameLength));
  106. if (argumentCount > 2)
  107. {
  108. IfJsrtErrorSetGo(ChakraRTInterface::JsStringToPointer(arguments[2], &scriptInjectType, &scriptInjectTypeLength));
  109. }
  110. if (errorCode == JsNoError)
  111. {
  112. IfFailGo(Helpers::WideStringToNarrowDynamic(fileName, &fileNameNarrow));
  113. hr = Helpers::LoadScriptFromFile(fileNameNarrow, fileContent);
  114. if (FAILED(hr))
  115. {
  116. fwprintf(stderr, _u("Couldn't load file.\n"));
  117. }
  118. else
  119. {
  120. returnValue = LoadScript(callee, fileNameNarrow, fileContent, scriptInjectType, isSourceModule);
  121. free(fileNameNarrow);
  122. }
  123. }
  124. }
  125. Error:
  126. if (errorCode != JsNoError)
  127. {
  128. JsValueRef errorObject;
  129. JsValueRef errorMessageString;
  130. if (wcscmp(errorMessage, _u("")) == 0) {
  131. errorMessage = ConvertErrorCodeToMessage(errorCode);
  132. }
  133. ChakraRTInterface::JsPointerToString(errorMessage, wcslen(errorMessage), &errorMessageString);
  134. ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  135. ChakraRTInterface::JsSetException(errorObject);
  136. }
  137. return returnValue;
  138. }
  139. JsValueRef __stdcall WScriptJsrt::LoadScriptCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  140. {
  141. return LoadScriptHelper(callee, isConstructCall, arguments, argumentCount, callbackState, false);
  142. }
  143. JsValueRef __stdcall WScriptJsrt::LoadModuleCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  144. {
  145. return LoadScriptHelper(callee, isConstructCall, arguments, argumentCount, callbackState, true);
  146. }
  147. JsValueRef WScriptJsrt::LoadScriptHelper(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState, bool isSourceModule)
  148. {
  149. HRESULT hr = E_FAIL;
  150. JsErrorCode errorCode = JsNoError;
  151. LPCWSTR errorMessage = _u("");
  152. JsValueRef returnValue = JS_INVALID_REFERENCE;
  153. if (argumentCount < 2 || argumentCount > 4)
  154. {
  155. errorCode = JsErrorInvalidArgument;
  156. errorMessage = _u("Need more or fewer arguments for WScript.LoadScript");
  157. }
  158. else
  159. {
  160. const wchar_t *fileContent;
  161. char *fileName = (char*) "script.js";
  162. const wchar_t *scriptInjectType = _u("self");
  163. size_t fileContentLength;
  164. size_t scriptInjectTypeLength;
  165. bool freeFileName = false;
  166. IfJsrtErrorSetGo(ChakraRTInterface::JsStringToPointer(arguments[1], &fileContent, &fileContentLength));
  167. if (argumentCount > 2)
  168. {
  169. IfJsrtErrorSetGo(ChakraRTInterface::JsStringToPointer(arguments[2], &scriptInjectType, &scriptInjectTypeLength));
  170. if (argumentCount > 3)
  171. {
  172. size_t fileNameWideLength = 0;
  173. const wchar_t* fileNameWide = nullptr;
  174. IfJsrtErrorSetGo(ChakraRTInterface::JsStringToPointer(arguments[3], &fileNameWide, &fileNameWideLength));
  175. IfFailGo(Helpers::WideStringToNarrowDynamic(fileNameWide, &fileName));
  176. freeFileName = true;
  177. }
  178. }
  179. returnValue = LoadScript(callee, fileName, fileContent, scriptInjectType, isSourceModule);
  180. if (freeFileName)
  181. {
  182. free(fileName);
  183. }
  184. }
  185. Error:
  186. if (errorCode != JsNoError)
  187. {
  188. JsValueRef errorObject;
  189. JsValueRef errorMessageString;
  190. if (wcscmp(errorMessage, _u("")) == 0) {
  191. errorMessage = ConvertErrorCodeToMessage(errorCode);
  192. }
  193. ChakraRTInterface::JsPointerToString(errorMessage, wcslen(errorMessage), &errorMessageString);
  194. ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  195. ChakraRTInterface::JsSetException(errorObject);
  196. }
  197. return returnValue;
  198. }
  199. JsValueRef WScriptJsrt::LoadScript(JsValueRef callee, LPCSTR fileName, LPCWSTR fileContent, LPCWSTR scriptInjectType, bool isSourceModule)
  200. {
  201. HRESULT hr = E_FAIL;
  202. JsErrorCode errorCode = JsNoError;
  203. LPCWSTR errorMessage = _u("Internal error.");
  204. size_t errorMessageLength = wcslen(errorMessage);
  205. JsValueRef returnValue = JS_INVALID_REFERENCE;
  206. JsErrorCode innerErrorCode = JsNoError;
  207. JsContextRef currentContext = JS_INVALID_REFERENCE;
  208. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  209. wchar_t* fullPath = nullptr;
  210. char fullPathNarrow[_MAX_PATH];
  211. size_t len = 0;
  212. IfJsrtErrorSetGo(ChakraRTInterface::JsGetCurrentContext(&currentContext));
  213. IfJsrtErrorSetGo(ChakraRTInterface::JsGetRuntime(currentContext, &runtime));
  214. if (_fullpath(fullPathNarrow, fileName, _MAX_PATH) == nullptr)
  215. {
  216. IfFailGo(E_FAIL);
  217. }
  218. // canonicalize that path name to lower case for the profile storage
  219. // REVIEW: This doesn't work for UTF8...
  220. len = strlen(fullPathNarrow);
  221. for (size_t i = 0; i < len; i++)
  222. {
  223. fullPathNarrow[i] = (char) tolower(fullPathNarrow[i]);
  224. }
  225. // TODO: Remove when we have utf8 versions of the Jsrt APIs
  226. Helpers::NarrowStringToWideDynamic(fullPathNarrow, &fullPath);
  227. if (wcscmp(scriptInjectType, _u("self")) == 0)
  228. {
  229. JsContextRef calleeContext;
  230. IfJsrtErrorSetGo(ChakraRTInterface::JsGetContextOfObject(callee, &calleeContext));
  231. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(calleeContext));
  232. if (isSourceModule)
  233. {
  234. errorCode = ChakraRTInterface::JsRunModule(fileContent, GetNextSourceContext(), fullPath, &returnValue);
  235. }
  236. else
  237. {
  238. errorCode = ChakraRTInterface::JsRunScript(fileContent, GetNextSourceContext(), fullPath, &returnValue);
  239. }
  240. if (errorCode == JsNoError)
  241. {
  242. errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
  243. }
  244. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(currentContext));
  245. }
  246. else if (wcscmp(scriptInjectType, _u("samethread")) == 0)
  247. {
  248. JsValueRef newContext = JS_INVALID_REFERENCE;
  249. // Create a new context and set it as the current context
  250. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateContext(runtime, &newContext));
  251. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(newContext));
  252. // Initialize the host objects
  253. Initialize();
  254. if (isSourceModule)
  255. {
  256. errorCode = ChakraRTInterface::JsRunModule(fileContent, GetNextSourceContext(), fullPath, &returnValue);
  257. }
  258. else
  259. {
  260. errorCode = ChakraRTInterface::JsRunScript(fileContent, GetNextSourceContext(), fullPath, &returnValue);
  261. }
  262. if (errorCode == JsNoError)
  263. {
  264. errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
  265. }
  266. // Set the context back to the old one
  267. ChakraRTInterface::JsSetCurrentContext(currentContext);
  268. }
  269. else
  270. {
  271. errorCode = JsErrorInvalidArgument;
  272. errorMessage = _u("Unsupported argument type inject type.");
  273. }
  274. Error:
  275. JsValueRef value = returnValue;
  276. if (errorCode != JsNoError)
  277. {
  278. if (innerErrorCode != JsNoError)
  279. {
  280. // Failed to retrieve the inner error message, so set a custom error string
  281. errorMessage = ConvertErrorCodeToMessage(errorCode);
  282. }
  283. JsValueRef error = JS_INVALID_REFERENCE;
  284. JsValueRef messageProperty = JS_INVALID_REFERENCE;
  285. errorMessageLength = wcslen(errorMessage);
  286. innerErrorCode = ChakraRTInterface::JsPointerToString(errorMessage, errorMessageLength, &messageProperty);
  287. if (innerErrorCode == JsNoError)
  288. {
  289. innerErrorCode = ChakraRTInterface::JsCreateError(messageProperty, &error);
  290. if (innerErrorCode == JsNoError)
  291. {
  292. innerErrorCode = ChakraRTInterface::JsSetException(error);
  293. }
  294. }
  295. ChakraRTInterface::JsDoubleToNumber(errorCode, &value);
  296. }
  297. _flushall();
  298. return value;
  299. }
  300. JsValueRef WScriptJsrt::SetTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  301. {
  302. LPCWSTR errorMessage = _u("invalid call to WScript.SetTimeout");
  303. JsValueRef function;
  304. JsValueRef timerId;
  305. unsigned int time;
  306. double tmp;
  307. CallbackMessage *msg = nullptr;
  308. if (argumentCount != 3)
  309. {
  310. goto Error;
  311. }
  312. function = arguments[1];
  313. IfJsrtError(ChakraRTInterface::JsNumberToDouble(arguments[2], &tmp));
  314. time = static_cast<int>(tmp);
  315. msg = new CallbackMessage(time, function);
  316. messageQueue->InsertSorted(msg);
  317. IfJsrtError(ChakraRTInterface::JsDoubleToNumber(static_cast<double>(msg->GetId()), &timerId));
  318. return timerId;
  319. Error:
  320. JsValueRef errorObject;
  321. JsValueRef errorMessageString;
  322. JsErrorCode errorCode = ChakraRTInterface::JsPointerToString(errorMessage, wcslen(errorMessage), &errorMessageString);
  323. if (errorCode != JsNoError)
  324. {
  325. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  326. if (errorCode != JsNoError)
  327. {
  328. ChakraRTInterface::JsSetException(errorObject);
  329. }
  330. }
  331. return JS_INVALID_REFERENCE;
  332. }
  333. JsValueRef WScriptJsrt::ClearTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  334. {
  335. LPCWSTR errorMessage = _u("invalid call to WScript.ClearTimeout");
  336. if (argumentCount != 2)
  337. {
  338. goto Error;
  339. }
  340. unsigned int timerId;
  341. double tmp;
  342. JsValueRef undef;
  343. JsValueRef global;
  344. IfJsrtError(ChakraRTInterface::JsNumberToDouble(arguments[1], &tmp));
  345. timerId = static_cast<int>(tmp);
  346. messageQueue->RemoveById(timerId);
  347. IfJsrtError(ChakraRTInterface::JsGetGlobalObject(&global));
  348. IfJsrtError(ChakraRTInterface::JsGetUndefinedValue(&undef));
  349. return undef;
  350. Error:
  351. JsValueRef errorObject;
  352. JsValueRef errorMessageString;
  353. JsErrorCode errorCode = ChakraRTInterface::JsPointerToString(errorMessage, wcslen(errorMessage), &errorMessageString);
  354. if (errorCode != JsNoError)
  355. {
  356. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  357. if (errorCode != JsNoError)
  358. {
  359. ChakraRTInterface::JsSetException(errorObject);
  360. }
  361. }
  362. return JS_INVALID_REFERENCE;
  363. }
  364. template <class DebugOperationFunc>
  365. void QueueDebugOperation(JsValueRef function, const DebugOperationFunc& operation)
  366. {
  367. WScriptJsrt::PushMessage(WScriptJsrt::CallbackMessage::Create(function, operation));
  368. }
  369. JsValueRef WScriptJsrt::AttachCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  370. {
  371. LPCWSTR errorMessage = _u("WScript.Attach requires a function, like WScript.Attach(foo);");
  372. JsValueType argumentType = JsUndefined;
  373. if (argumentCount != 2)
  374. {
  375. goto Error;
  376. }
  377. IfJsrtError(ChakraRTInterface::JsGetValueType(arguments[1], &argumentType));
  378. if (argumentType != JsFunction)
  379. {
  380. goto Error;
  381. }
  382. QueueDebugOperation(arguments[1], [](WScriptJsrt::CallbackMessage& msg)
  383. {
  384. JsContextRef currentContext = JS_INVALID_REFERENCE;
  385. ChakraRTInterface::JsGetCurrentContext(&currentContext);
  386. JsRuntimeHandle currentRuntime = JS_INVALID_RUNTIME_HANDLE;
  387. ChakraRTInterface::JsGetRuntime(currentContext, &currentRuntime);
  388. Debugger* debugger = Debugger::GetDebugger(currentRuntime);
  389. debugger->StartDebugging(currentRuntime);
  390. debugger->SourceRunDown();
  391. return msg.CallFunction("");
  392. });
  393. Error:
  394. JsValueRef errorObject;
  395. JsValueRef errorMessageString;
  396. JsErrorCode errorCode = ChakraRTInterface::JsPointerToString(errorMessage, wcslen(errorMessage), &errorMessageString);
  397. if (errorCode != JsNoError)
  398. {
  399. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  400. if (errorCode != JsNoError)
  401. {
  402. ChakraRTInterface::JsSetException(errorObject);
  403. }
  404. }
  405. return JS_INVALID_REFERENCE;
  406. }
  407. JsValueRef WScriptJsrt::DetachCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  408. {
  409. LPCWSTR errorMessage = _u("WScript.Detach requires a function, like WScript.Detach(foo);");
  410. JsValueType argumentType = JsUndefined;
  411. if (argumentCount != 2)
  412. {
  413. goto Error;
  414. }
  415. IfJsrtError(ChakraRTInterface::JsGetValueType(arguments[1], &argumentType));
  416. if (argumentType != JsFunction)
  417. {
  418. goto Error;
  419. }
  420. QueueDebugOperation(arguments[1], [](WScriptJsrt::CallbackMessage& msg)
  421. {
  422. JsContextRef currentContext = JS_INVALID_REFERENCE;
  423. ChakraRTInterface::JsGetCurrentContext(&currentContext);
  424. JsRuntimeHandle currentRuntime = JS_INVALID_RUNTIME_HANDLE;
  425. ChakraRTInterface::JsGetRuntime(currentContext, &currentRuntime);
  426. if (Debugger::debugger != nullptr)
  427. {
  428. Debugger* debugger = Debugger::GetDebugger(currentRuntime);
  429. debugger->StopDebugging(currentRuntime);
  430. }
  431. return msg.CallFunction("");
  432. });
  433. Error:
  434. JsValueRef errorObject;
  435. JsValueRef errorMessageString;
  436. JsErrorCode errorCode = ChakraRTInterface::JsPointerToString(errorMessage, wcslen(errorMessage), &errorMessageString);
  437. if (errorCode != JsNoError)
  438. {
  439. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  440. if (errorCode != JsNoError)
  441. {
  442. ChakraRTInterface::JsSetException(errorObject);
  443. }
  444. }
  445. return JS_INVALID_REFERENCE;
  446. }
  447. JsValueRef WScriptJsrt::DumpFunctionPositionCallback(JsValueRef callee, bool isConstructCall, JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  448. {
  449. JsValueRef functionPosition = JS_INVALID_REFERENCE;
  450. if (argumentCount > 1)
  451. {
  452. if (ChakraRTInterface::JsDiagGetFunctionPosition(arguments[1], &functionPosition) != JsNoError)
  453. {
  454. // If we can't get the functionPosition pass undefined
  455. IfJsErrorFailLogAndRet(ChakraRTInterface::JsGetUndefinedValue(&functionPosition));
  456. }
  457. if (Debugger::debugger != nullptr)
  458. {
  459. Debugger::debugger->DumpFunctionPosition(functionPosition);
  460. }
  461. }
  462. return JS_INVALID_REFERENCE;
  463. }
  464. JsValueRef WScriptJsrt::RequestAsyncBreakCallback(JsValueRef callee, bool isConstructCall, JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  465. {
  466. if (Debugger::debugger != nullptr && !Debugger::debugger->IsDetached())
  467. {
  468. IfJsErrorFailLogAndRet(ChakraRTInterface::JsDiagRequestAsyncBreak(Debugger::GetRuntime()));
  469. }
  470. else
  471. {
  472. Helpers::LogError(_u("RequestAsyncBreak can only be called when debugger is attached"));
  473. }
  474. return JS_INVALID_REFERENCE;
  475. }
  476. JsValueRef WScriptJsrt::EmptyCallback(JsValueRef callee, bool isConstructCall, JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  477. {
  478. return JS_INVALID_REFERENCE;
  479. }
  480. bool WScriptJsrt::CreateNamedFunction(const char16* nameString, JsNativeFunction callback, JsValueRef* functionVar)
  481. {
  482. JsValueRef nameVar;
  483. IfJsrtErrorFail(ChakraRTInterface::JsPointerToString(nameString, wcslen(nameString), &nameVar), false);
  484. IfJsrtErrorFail(ChakraRTInterface::JsCreateNamedFunction(nameVar, callback, nullptr, functionVar), false);
  485. return true;
  486. }
  487. bool WScriptJsrt::InstallObjectsOnObject(JsValueRef object, const char16* name, JsNativeFunction nativeFunction)
  488. {
  489. JsValueRef propertyValueRef;
  490. JsPropertyIdRef propertyId;
  491. IfJsrtErrorFail(ChakraRTInterface::JsGetPropertyIdFromName(name, &propertyId), false);
  492. CreateNamedFunction(name, nativeFunction, &propertyValueRef);
  493. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(object, propertyId, propertyValueRef, true), false);
  494. return true;
  495. }
  496. bool WScriptJsrt::Initialize()
  497. {
  498. HRESULT hr = S_OK;
  499. JsValueRef wscript;
  500. IfJsrtErrorFail(ChakraRTInterface::JsCreateObject(&wscript), false);
  501. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("Echo"), EchoCallback));
  502. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("Quit"), QuitCallback));
  503. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("LoadScriptFile"), LoadScriptFileCallback));
  504. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("LoadModuleFile"), LoadModuleFileCallback));
  505. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("LoadScript"), LoadScriptCallback));
  506. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("LoadModule"), LoadModuleCallback));
  507. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("SetTimeout"), SetTimeoutCallback));
  508. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("ClearTimeout"), ClearTimeoutCallback));
  509. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("Attach"), AttachCallback));
  510. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("Detach"), DetachCallback));
  511. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("DumpFunctionPosition"), DumpFunctionPositionCallback));
  512. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("RequestAsyncBreak"), RequestAsyncBreakCallback));
  513. // ToDo Remove
  514. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, _u("Edit"), EmptyCallback));
  515. JsValueRef argsObject;
  516. if (!CreateArgumentsObject(&argsObject))
  517. {
  518. return false;
  519. }
  520. JsPropertyIdRef argsName;
  521. IfJsrtErrorFail(ChakraRTInterface::JsGetPropertyIdFromName(_u("Arguments"), &argsName), false);
  522. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(wscript, argsName, argsObject, true), false);
  523. JsPropertyIdRef wscriptName;
  524. IfJsrtErrorFail(ChakraRTInterface::JsGetPropertyIdFromName(_u("WScript"), &wscriptName), false);
  525. JsValueRef global;
  526. IfJsrtErrorFail(ChakraRTInterface::JsGetGlobalObject(&global), false);
  527. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(global, wscriptName, wscript, true), false);
  528. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(global, _u("print"), EchoCallback));
  529. Error:
  530. return hr == S_OK;
  531. }
  532. bool WScriptJsrt::PrintException(LPCSTR fileName, JsErrorCode jsErrorCode)
  533. {
  534. LPCWSTR errorTypeString = ConvertErrorCodeToMessage(jsErrorCode);
  535. JsValueRef exception;
  536. ChakraRTInterface::JsGetAndClearException(&exception);
  537. if (exception != nullptr)
  538. {
  539. if (jsErrorCode == JsErrorCode::JsErrorScriptCompile || jsErrorCode == JsErrorCode::JsErrorScriptException)
  540. {
  541. LPCWSTR errorMessage = nullptr;
  542. size_t errorMessageLength = 0;
  543. JsValueRef errorString = JS_INVALID_REFERENCE;
  544. IfJsrtErrorFail(ChakraRTInterface::JsConvertValueToString(exception, &errorString), false);
  545. IfJsrtErrorFail(ChakraRTInterface::JsStringToPointer(errorString, &errorMessage, &errorMessageLength), false);
  546. if (jsErrorCode == JsErrorCode::JsErrorScriptCompile)
  547. {
  548. JsPropertyIdRef linePropertyId = JS_INVALID_REFERENCE;
  549. JsValueRef lineProperty = JS_INVALID_REFERENCE;
  550. JsPropertyIdRef columnPropertyId = JS_INVALID_REFERENCE;
  551. JsValueRef columnProperty = JS_INVALID_REFERENCE;
  552. int line;
  553. int column;
  554. IfJsrtErrorFail(ChakraRTInterface::JsGetPropertyIdFromName(_u("line"), &linePropertyId), false);
  555. IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, linePropertyId, &lineProperty), false);
  556. IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(lineProperty, &line), false);
  557. IfJsrtErrorFail(ChakraRTInterface::JsGetPropertyIdFromName(_u("column"), &columnPropertyId), false);
  558. IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, columnPropertyId, &columnProperty), false);
  559. IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(columnProperty, &column), false);
  560. CHAR shortFileName[_MAX_PATH];
  561. CHAR ext[_MAX_EXT];
  562. _splitpath_s(fileName, nullptr, 0, nullptr, 0, shortFileName, _countof(shortFileName), ext, _countof(ext));
  563. fwprintf(stderr, _u("%ls\n\tat code (%S%S:%d:%d)\n"), errorMessage, shortFileName, ext, (int)line + 1, (int)column + 1);
  564. }
  565. else
  566. {
  567. JsValueType propertyType = JsUndefined;
  568. JsPropertyIdRef stackPropertyId = JS_INVALID_REFERENCE;
  569. JsValueRef stackProperty = JS_INVALID_REFERENCE;
  570. LPCWSTR errorStack = nullptr;
  571. size_t errorStackLength = 0;
  572. IfJsrtErrorFail(ChakraRTInterface::JsGetPropertyIdFromName(_u("stack"), &stackPropertyId), false);
  573. IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, stackPropertyId, &stackProperty), false);
  574. IfJsrtErrorFail(ChakraRTInterface::JsGetValueType(stackProperty, &propertyType), false);
  575. if (propertyType == JsUndefined)
  576. {
  577. fwprintf(stderr, _u("%ls\n"), errorMessage);
  578. }
  579. else
  580. {
  581. IfJsrtErrorFail(ChakraRTInterface::JsStringToPointer(stackProperty, &errorStack, &errorStackLength), false);
  582. fwprintf(stderr, _u("%ls\n"), errorStack);
  583. }
  584. }
  585. }
  586. else
  587. {
  588. fwprintf(stderr, _u("Error : %ls\n"), errorTypeString);
  589. }
  590. return true;
  591. }
  592. else
  593. {
  594. fwprintf(stderr, _u("Error : %ls\n"), errorTypeString);
  595. }
  596. return false;
  597. }
  598. void WScriptJsrt::AddMessageQueue(MessageQueue *_messageQueue)
  599. {
  600. Assert(messageQueue == nullptr);
  601. messageQueue = _messageQueue;
  602. }
  603. WScriptJsrt::CallbackMessage::CallbackMessage(unsigned int time, JsValueRef function) : MessageBase(time), m_function(function)
  604. {
  605. JsErrorCode error = ChakraRTInterface::JsAddRef(m_function, nullptr);
  606. if (error != JsNoError)
  607. {
  608. // Simply report a fatal error and exit because continuing from this point would result in inconsistent state
  609. // and FailFast telemetry would not be useful.
  610. wprintf(_u("FATAL ERROR: ChakraRTInterface::JsAddRef failed in WScriptJsrt::CallbackMessage::`ctor`. error=0x%x\n"), error);
  611. exit(1);
  612. }
  613. }
  614. WScriptJsrt::CallbackMessage::~CallbackMessage()
  615. {
  616. bool hasException = false;
  617. ChakraRTInterface::JsHasException(&hasException);
  618. if (hasException)
  619. {
  620. WScriptJsrt::PrintException("", JsErrorScriptException);
  621. }
  622. JsErrorCode errorCode = ChakraRTInterface::JsRelease(m_function, nullptr);
  623. Assert(errorCode == JsNoError);
  624. m_function = JS_INVALID_REFERENCE;
  625. }
  626. HRESULT WScriptJsrt::CallbackMessage::Call(LPCSTR fileName)
  627. {
  628. return CallFunction(fileName);
  629. }
  630. HRESULT WScriptJsrt::CallbackMessage::CallFunction(LPCSTR fileName)
  631. {
  632. HRESULT hr = S_OK;
  633. JsValueRef global;
  634. JsValueRef result;
  635. JsValueRef stringValue;
  636. JsValueType type;
  637. JsErrorCode errorCode = JsNoError;
  638. IfJsrtErrorHR(ChakraRTInterface::JsGetGlobalObject(&global));
  639. IfJsrtErrorHR(ChakraRTInterface::JsGetValueType(m_function, &type));
  640. if (type == JsString)
  641. {
  642. LPCWSTR script = nullptr;
  643. size_t length = 0;
  644. IfJsrtErrorHR(ChakraRTInterface::JsConvertValueToString(m_function, &stringValue));
  645. IfJsrtErrorHR(ChakraRTInterface::JsStringToPointer(stringValue, &script, &length));
  646. // Run the code
  647. errorCode = ChakraRTInterface::JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u("") /*sourceUrl*/, nullptr /*no result needed*/);
  648. }
  649. else
  650. {
  651. errorCode = ChakraRTInterface::JsCallFunction(m_function, &global, 1, &result);
  652. }
  653. if (errorCode != JsNoError)
  654. {
  655. hr = E_FAIL;
  656. PrintException(fileName, errorCode);
  657. }
  658. Error:
  659. return hr;
  660. }