WScriptJsrt.cpp 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. 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. #if defined(_X86_) || defined(_M_IX86)
  7. #define CPU_ARCH_TEXT "x86"
  8. #elif defined(_AMD64_) || defined(_IA64_) || defined(_M_AMD64) || defined(_M_IA64)
  9. #define CPU_ARCH_TEXT "x86_64"
  10. #elif defined(_ARM_) || defined(_M_ARM)
  11. #define CPU_ARCH_TEXT "ARM"
  12. #elif defined(_ARM64_) || defined(_M_ARM64)
  13. #define CPU_ARCH_TEXT "ARM64"
  14. #endif
  15. // do not change the order below
  16. // otherwise, i.e. android system can be marked as posix? etc..
  17. #ifdef _WIN32
  18. #define DEST_PLATFORM_TEXT "win32"
  19. #else // ! _WIN32
  20. #if defined(__APPLE__)
  21. #ifdef __IOS__
  22. #define DEST_PLATFORM_TEXT "ios"
  23. #else // ! iOS
  24. #define DEST_PLATFORM_TEXT "darwin"
  25. #endif // iOS ?
  26. #elif defined(__ANDROID__)
  27. #define DEST_PLATFORM_TEXT "android"
  28. #elif defined(__linux__)
  29. #define DEST_PLATFORM_TEXT "posix"
  30. #elif defined(__FreeBSD__) || defined(__unix__)
  31. #define DEST_PLATFORM_TEXT "bsd"
  32. #endif // FreeBSD or unix ?
  33. #endif // _WIN32 ?
  34. MessageQueue* WScriptJsrt::messageQueue = nullptr;
  35. std::map<std::string, JsModuleRecord> WScriptJsrt::moduleRecordMap;
  36. DWORD_PTR WScriptJsrt::sourceContext = 0;
  37. #define ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString) \
  38. JsErrorCode errorCode = JsNoError; \
  39. do \
  40. { \
  41. const char *outOfMemoryString = \
  42. "Failed to convert wide string. Out of memory?";\
  43. \
  44. char *errorMessageNarrow; \
  45. if (FAILED(WideStringToNarrowDynamic(errorMessage, &errorMessageNarrow))) \
  46. { \
  47. errorCode = ChakraRTInterface::JsCreateString(outOfMemoryString, \
  48. strlen(outOfMemoryString), &errorMessageString); \
  49. } \
  50. else \
  51. { \
  52. errorCode = ChakraRTInterface::JsCreateString(errorMessageNarrow, \
  53. strlen(errorMessageNarrow), &errorMessageString); \
  54. free(errorMessageNarrow); \
  55. } \
  56. } \
  57. while(0)
  58. DWORD_PTR WScriptJsrt::GetNextSourceContext()
  59. {
  60. return sourceContext++;
  61. }
  62. bool WScriptJsrt::CreateArgumentsObject(JsValueRef *argsObject)
  63. {
  64. LPWSTR *argv = HostConfigFlags::argsVal;
  65. JsValueRef retArr;
  66. Assert(argsObject);
  67. *argsObject = nullptr;
  68. IfJsrtErrorFail(ChakraRTInterface::JsCreateArray(HostConfigFlags::argsCount, &retArr), false);
  69. for (int i = 0; i < HostConfigFlags::argsCount; i++)
  70. {
  71. JsValueRef value;
  72. JsValueRef index;
  73. char *argNarrow;
  74. if (FAILED(WideStringToNarrowDynamic(argv[i], &argNarrow)))
  75. {
  76. return false;
  77. }
  78. JsErrorCode errCode = ChakraRTInterface::JsCreateString(
  79. argNarrow,
  80. strlen(argNarrow), &value);
  81. free(argNarrow);
  82. IfJsrtErrorFail(errCode, false);
  83. IfJsrtErrorFail(ChakraRTInterface::JsDoubleToNumber(i, &index), false);
  84. IfJsrtErrorFail(ChakraRTInterface::JsSetIndexedProperty(retArr, index, value), false);
  85. }
  86. *argsObject = retArr;
  87. return true;
  88. }
  89. JsValueRef __stdcall WScriptJsrt::EchoCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  90. {
  91. for (unsigned int i = 1; i < argumentCount; i++)
  92. {
  93. JsValueRef strValue;
  94. JsErrorCode error = ChakraRTInterface::JsConvertValueToString(arguments[i], &strValue);
  95. if (error == JsNoError)
  96. {
  97. AutoString str(strValue);
  98. if (str.GetError() == JsNoError)
  99. {
  100. if (i > 1)
  101. {
  102. wprintf(_u(" "));
  103. }
  104. wprintf(_u("%ls"), str.GetWideString());
  105. }
  106. }
  107. if (error == JsErrorScriptException)
  108. {
  109. return nullptr;
  110. }
  111. }
  112. wprintf(_u("\n"));
  113. fflush(stdout);
  114. JsValueRef undefinedValue;
  115. if (ChakraRTInterface::JsGetUndefinedValue(&undefinedValue) == JsNoError)
  116. {
  117. return undefinedValue;
  118. }
  119. else
  120. {
  121. return nullptr;
  122. }
  123. }
  124. JsValueRef __stdcall WScriptJsrt::QuitCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  125. {
  126. int exitCode = 0;
  127. if (argumentCount > 1)
  128. {
  129. double exitCodeDouble;
  130. IfJsrtErrorFail(ChakraRTInterface::JsNumberToDouble(arguments[1], &exitCodeDouble), JS_INVALID_REFERENCE);
  131. exitCode = (int)exitCodeDouble;
  132. }
  133. ExitProcess(exitCode);
  134. }
  135. JsValueRef __stdcall WScriptJsrt::LoadScriptFileCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  136. {
  137. return LoadScriptFileHelper(callee, arguments, argumentCount, false);
  138. }
  139. JsValueRef WScriptJsrt::LoadScriptFileHelper(JsValueRef callee, JsValueRef *arguments, unsigned short argumentCount, bool isSourceModule)
  140. {
  141. HRESULT hr = E_FAIL;
  142. JsValueRef returnValue = JS_INVALID_REFERENCE;
  143. JsErrorCode errorCode = JsNoError;
  144. LPCWSTR errorMessage = _u("");
  145. if (argumentCount < 2 || argumentCount > 4)
  146. {
  147. errorCode = JsErrorInvalidArgument;
  148. errorMessage = _u("Need more or fewer arguments for WScript.LoadScript");
  149. }
  150. else
  151. {
  152. LPCSTR fileContent;
  153. AutoString fileName(arguments[1]);
  154. IfJsrtErrorSetGo(fileName.GetError());
  155. AutoString scriptInjectType;
  156. if (argumentCount > 2)
  157. {
  158. IfJsrtErrorSetGo(scriptInjectType.Initialize(arguments[2]));
  159. }
  160. if (errorCode == JsNoError)
  161. {
  162. hr = Helpers::LoadScriptFromFile(*fileName, fileContent);
  163. if (FAILED(hr))
  164. {
  165. fwprintf(stderr, _u("Couldn't load file.\n"));
  166. }
  167. else
  168. {
  169. returnValue = LoadScript(callee, *fileName, fileContent, *scriptInjectType ? *scriptInjectType : "self", isSourceModule);
  170. }
  171. }
  172. }
  173. Error:
  174. if (errorCode != JsNoError)
  175. {
  176. JsValueRef errorObject;
  177. JsValueRef errorMessageString;
  178. if (wcscmp(errorMessage, _u("")) == 0) {
  179. errorMessage = ConvertErrorCodeToMessage(errorCode);
  180. }
  181. ERROR_MESSAGE_TO_STRING(errCode, errorMessage, errorMessageString);
  182. ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  183. ChakraRTInterface::JsSetException(errorObject);
  184. }
  185. return returnValue;
  186. }
  187. JsValueRef __stdcall WScriptJsrt::LoadScriptCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  188. {
  189. return LoadScriptHelper(callee, isConstructCall, arguments, argumentCount, callbackState, false);
  190. }
  191. JsValueRef __stdcall WScriptJsrt::LoadModuleCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  192. {
  193. return LoadScriptHelper(callee, isConstructCall, arguments, argumentCount, callbackState, true);
  194. }
  195. JsValueRef WScriptJsrt::LoadScriptHelper(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState, bool isSourceModule)
  196. {
  197. HRESULT hr = E_FAIL;
  198. JsErrorCode errorCode = JsNoError;
  199. LPCWSTR errorMessage = _u("");
  200. JsValueRef returnValue = JS_INVALID_REFERENCE;
  201. if (argumentCount < 2 || argumentCount > 4)
  202. {
  203. errorCode = JsErrorInvalidArgument;
  204. errorMessage = _u("Need more or fewer arguments for WScript.LoadScript");
  205. }
  206. else
  207. {
  208. AutoString fileContent;
  209. char *fileNameNarrow = nullptr;
  210. AutoString fileName;
  211. AutoString scriptInjectType;
  212. char fileNameBuffer[MAX_PATH];
  213. IfJsrtErrorSetGo(fileContent.Initialize(arguments[1]));
  214. // ExternalArrayBuffer Finalize will clean this up
  215. fileContent.MakePersistent();
  216. if (argumentCount > 2)
  217. {
  218. IfJsrtErrorSetGo(scriptInjectType.Initialize(arguments[2]));
  219. if (argumentCount > 3)
  220. {
  221. IfJsrtErrorSetGo(fileName.Initialize(arguments[3]));
  222. fileNameNarrow = *fileName;
  223. }
  224. }
  225. if (!fileNameNarrow && isSourceModule)
  226. {
  227. sprintf_s(fileNameBuffer, MAX_PATH, "moduleScript%i.js", (int)sourceContext);
  228. fileNameNarrow = fileNameBuffer;
  229. }
  230. if (*fileContent)
  231. {
  232. // TODO: This is CESU-8. How to tell the engine?
  233. // TODO: How to handle this source (script) life time?
  234. returnValue = LoadScript(callee, fileNameNarrow, *fileContent, *scriptInjectType ? *scriptInjectType : "self", isSourceModule);
  235. }
  236. }
  237. Error:
  238. if (errorCode != JsNoError)
  239. {
  240. JsValueRef errorObject;
  241. JsValueRef errorMessageString;
  242. if (wcscmp(errorMessage, _u("")) == 0) {
  243. errorMessage = ConvertErrorCodeToMessage(errorCode);
  244. }
  245. ERROR_MESSAGE_TO_STRING(errCode, errorMessage, errorMessageString);
  246. ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  247. ChakraRTInterface::JsSetException(errorObject);
  248. }
  249. return returnValue;
  250. }
  251. JsErrorCode WScriptJsrt::InitializeModuleInfo(JsValueRef specifier, JsModuleRecord moduleRecord)
  252. {
  253. JsErrorCode errorCode = JsNoError;
  254. errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_FetchImportedModuleCallback, (void*)WScriptJsrt::FetchImportedModule);
  255. if (errorCode == JsNoError)
  256. {
  257. errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_NotifyModuleReadyCallback, (void*)WScriptJsrt::NotifyModuleReadyCallback);
  258. }
  259. if (errorCode == JsNoError)
  260. {
  261. errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_HostDefined, specifier);
  262. }
  263. IfJsrtErrorFailLogAndRetErrorCode(errorCode);
  264. return JsNoError;
  265. }
  266. JsErrorCode WScriptJsrt::LoadModuleFromString(LPCSTR fileName, LPCSTR fileContent)
  267. {
  268. DWORD_PTR dwSourceCookie = WScriptJsrt::GetNextSourceContext();
  269. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  270. auto moduleRecordEntry = moduleRecordMap.find(std::string(fileName));
  271. JsErrorCode errorCode = JsNoError;
  272. // we need to create a new moduleRecord if the specifier (fileName) is not found;
  273. // otherwise we'll use the old one.
  274. if (moduleRecordEntry == moduleRecordMap.end())
  275. {
  276. JsValueRef specifier;
  277. errorCode = ChakraRTInterface::JsCreateString(
  278. fileName, strlen(fileName), &specifier);
  279. if (errorCode == JsNoError)
  280. {
  281. errorCode = ChakraRTInterface::JsInitializeModuleRecord(
  282. nullptr, specifier, &requestModule);
  283. }
  284. if (errorCode == JsNoError)
  285. {
  286. errorCode = InitializeModuleInfo(specifier, requestModule);
  287. }
  288. if (errorCode == JsNoError)
  289. {
  290. moduleRecordMap[std::string(fileName)] = requestModule;
  291. }
  292. }
  293. else
  294. {
  295. requestModule = moduleRecordEntry->second;
  296. }
  297. IfJsrtErrorFailLogAndRetErrorCode(errorCode);
  298. JsValueRef errorObject = JS_INVALID_REFERENCE;
  299. // ParseModuleSource is sync, while additional fetch & evaluation are async.
  300. errorCode = ChakraRTInterface::JsParseModuleSource(requestModule, dwSourceCookie, (LPBYTE)fileContent,
  301. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  302. if ((errorCode != JsNoError) && errorObject != JS_INVALID_REFERENCE)
  303. {
  304. ChakraRTInterface::JsSetException(errorObject);
  305. return errorCode;
  306. }
  307. return JsNoError;
  308. }
  309. JsValueRef WScriptJsrt::LoadScript(JsValueRef callee, LPCSTR fileName,
  310. LPCSTR fileContent, LPCSTR scriptInjectType, bool isSourceModule)
  311. {
  312. HRESULT hr = E_FAIL;
  313. JsErrorCode errorCode = JsNoError;
  314. LPCWSTR errorMessage = _u("Internal error.");
  315. JsValueRef returnValue = JS_INVALID_REFERENCE;
  316. JsErrorCode innerErrorCode = JsNoError;
  317. JsContextRef currentContext = JS_INVALID_REFERENCE;
  318. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  319. char fullPathNarrow[_MAX_PATH];
  320. size_t len = 0;
  321. IfJsrtErrorSetGo(ChakraRTInterface::JsGetCurrentContext(&currentContext));
  322. IfJsrtErrorSetGo(ChakraRTInterface::JsGetRuntime(currentContext, &runtime));
  323. if (fileName)
  324. {
  325. if (_fullpath(fullPathNarrow, fileName, _MAX_PATH) == nullptr)
  326. {
  327. IfFailGo(E_FAIL);
  328. }
  329. // canonicalize that path name to lower case for the profile storage
  330. // REVIEW: This doesn't work for UTF8...
  331. len = strlen(fullPathNarrow);
  332. for (size_t i = 0; i < len; i++)
  333. {
  334. fullPathNarrow[i] = (char)tolower(fullPathNarrow[i]);
  335. }
  336. }
  337. else
  338. {
  339. // No fileName provided (WScript.LoadScript()), use dummy "script.js"
  340. strcpy_s(fullPathNarrow, "script.js");
  341. }
  342. // this is called with LoadModuleCallback method as well where caller pass in a string that should be
  343. // treated as a module source text instead of opening a new file.
  344. if (isSourceModule || (strcmp(scriptInjectType, "module") == 0))
  345. {
  346. errorCode = LoadModuleFromString(fileName, fileContent);
  347. }
  348. else if (strcmp(scriptInjectType, "self") == 0)
  349. {
  350. JsContextRef calleeContext;
  351. IfJsrtErrorSetGo(ChakraRTInterface::JsGetContextOfObject(callee, &calleeContext));
  352. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(calleeContext));
  353. JsValueRef scriptSource;
  354. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContent,
  355. (unsigned int)strlen(fileContent), nullptr, nullptr, &scriptSource));
  356. JsValueRef fname;
  357. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateString(fullPathNarrow,
  358. strlen(fullPathNarrow), &fname));
  359. errorCode = ChakraRTInterface::JsRun(scriptSource, GetNextSourceContext(),
  360. fname, JsParseScriptAttributeNone, &returnValue);
  361. if(errorCode == JsNoError)
  362. {
  363. errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
  364. }
  365. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(currentContext));
  366. }
  367. else if (strcmp(scriptInjectType, "samethread") == 0)
  368. {
  369. JsValueRef newContext = JS_INVALID_REFERENCE;
  370. // Create a new context and set it as the current context
  371. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateContext(runtime, &newContext));
  372. #if ENABLE_TTD
  373. //We need this here since this context is created in record
  374. IfJsrtErrorSetGo(ChakraRTInterface::JsSetObjectBeforeCollectCallback(newContext, nullptr, WScriptJsrt::JsContextBeforeCollectCallback));
  375. #endif
  376. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(newContext));
  377. // Initialize the host objects
  378. Initialize();
  379. JsValueRef scriptSource;
  380. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContent,
  381. (unsigned int)strlen(fileContent), nullptr, nullptr, &scriptSource));
  382. JsValueRef fname;
  383. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateString(fullPathNarrow,
  384. strlen(fullPathNarrow), &fname));
  385. errorCode = ChakraRTInterface::JsRun(scriptSource, GetNextSourceContext(),
  386. fname, JsParseScriptAttributeNone, &returnValue);
  387. if (errorCode == JsNoError)
  388. {
  389. errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
  390. }
  391. // Set the context back to the old one
  392. ChakraRTInterface::JsSetCurrentContext(currentContext);
  393. }
  394. else
  395. {
  396. errorCode = JsErrorInvalidArgument;
  397. errorMessage = _u("Unsupported argument type inject type.");
  398. }
  399. Error:
  400. JsValueRef value = returnValue;
  401. if (errorCode != JsNoError)
  402. {
  403. if (innerErrorCode != JsNoError)
  404. {
  405. // Failed to retrieve the inner error message, so set a custom error string
  406. errorMessage = ConvertErrorCodeToMessage(errorCode);
  407. }
  408. JsValueRef error = JS_INVALID_REFERENCE;
  409. JsValueRef messageProperty = JS_INVALID_REFERENCE;
  410. ERROR_MESSAGE_TO_STRING(errCode, errorMessage, messageProperty);
  411. if (errCode == JsNoError)
  412. {
  413. errCode = ChakraRTInterface::JsCreateError(messageProperty, &error);
  414. if (errCode == JsNoError)
  415. {
  416. errCode = ChakraRTInterface::JsSetException(error);
  417. }
  418. }
  419. ChakraRTInterface::JsDoubleToNumber(errorCode, &value);
  420. }
  421. _flushall();
  422. return value;
  423. }
  424. JsValueRef WScriptJsrt::SetTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  425. {
  426. LPCWSTR errorMessage = _u("invalid call to WScript.SetTimeout");
  427. JsValueRef function;
  428. JsValueRef timerId;
  429. unsigned int time;
  430. double tmp;
  431. CallbackMessage *msg = nullptr;
  432. if (argumentCount != 3)
  433. {
  434. goto Error;
  435. }
  436. function = arguments[1];
  437. IfJsrtError(ChakraRTInterface::JsNumberToDouble(arguments[2], &tmp));
  438. time = static_cast<int>(tmp);
  439. msg = new CallbackMessage(time, function);
  440. messageQueue->InsertSorted(msg);
  441. IfJsrtError(ChakraRTInterface::JsDoubleToNumber(static_cast<double>(msg->GetId()), &timerId));
  442. return timerId;
  443. Error:
  444. JsValueRef errorObject;
  445. JsValueRef errorMessageString;
  446. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  447. if (errorCode != JsNoError)
  448. {
  449. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  450. if (errorCode != JsNoError)
  451. {
  452. ChakraRTInterface::JsSetException(errorObject);
  453. }
  454. }
  455. return JS_INVALID_REFERENCE;
  456. }
  457. JsValueRef WScriptJsrt::ClearTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  458. {
  459. LPCWSTR errorMessage = _u("invalid call to WScript.ClearTimeout");
  460. if (argumentCount != 2)
  461. {
  462. goto Error;
  463. }
  464. unsigned int timerId;
  465. double tmp;
  466. JsValueRef undef;
  467. JsValueRef global;
  468. IfJsrtError(ChakraRTInterface::JsNumberToDouble(arguments[1], &tmp));
  469. timerId = static_cast<int>(tmp);
  470. messageQueue->RemoveById(timerId);
  471. IfJsrtError(ChakraRTInterface::JsGetGlobalObject(&global));
  472. IfJsrtError(ChakraRTInterface::JsGetUndefinedValue(&undef));
  473. return undef;
  474. Error:
  475. JsValueRef errorObject;
  476. JsValueRef errorMessageString;
  477. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  478. if (errorCode != JsNoError)
  479. {
  480. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  481. if (errorCode != JsNoError)
  482. {
  483. ChakraRTInterface::JsSetException(errorObject);
  484. }
  485. }
  486. return JS_INVALID_REFERENCE;
  487. }
  488. template <class DebugOperationFunc>
  489. void QueueDebugOperation(JsValueRef function, const DebugOperationFunc& operation)
  490. {
  491. WScriptJsrt::PushMessage(WScriptJsrt::CallbackMessage::Create(function, operation));
  492. }
  493. JsValueRef WScriptJsrt::AttachCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  494. {
  495. LPCWSTR errorMessage = _u("WScript.Attach requires a function, like WScript.Attach(foo);");
  496. JsValueType argumentType = JsUndefined;
  497. if (argumentCount != 2)
  498. {
  499. goto Error;
  500. }
  501. IfJsrtError(ChakraRTInterface::JsGetValueType(arguments[1], &argumentType));
  502. if (argumentType != JsFunction)
  503. {
  504. goto Error;
  505. }
  506. QueueDebugOperation(arguments[1], [](WScriptJsrt::CallbackMessage& msg)
  507. {
  508. JsContextRef currentContext = JS_INVALID_REFERENCE;
  509. ChakraRTInterface::JsGetCurrentContext(&currentContext);
  510. JsRuntimeHandle currentRuntime = JS_INVALID_RUNTIME_HANDLE;
  511. ChakraRTInterface::JsGetRuntime(currentContext, &currentRuntime);
  512. Debugger* debugger = Debugger::GetDebugger(currentRuntime);
  513. debugger->StartDebugging(currentRuntime);
  514. debugger->SourceRunDown();
  515. return msg.CallFunction("");
  516. });
  517. Error:
  518. JsValueRef errorObject;
  519. JsValueRef errorMessageString;
  520. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  521. if (errorCode != JsNoError)
  522. {
  523. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  524. if (errorCode != JsNoError)
  525. {
  526. ChakraRTInterface::JsSetException(errorObject);
  527. }
  528. }
  529. return JS_INVALID_REFERENCE;
  530. }
  531. JsValueRef WScriptJsrt::DetachCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  532. {
  533. LPCWSTR errorMessage = _u("WScript.Detach requires a function, like WScript.Detach(foo);");
  534. JsValueType argumentType = JsUndefined;
  535. if (argumentCount != 2)
  536. {
  537. goto Error;
  538. }
  539. IfJsrtError(ChakraRTInterface::JsGetValueType(arguments[1], &argumentType));
  540. if (argumentType != JsFunction)
  541. {
  542. goto Error;
  543. }
  544. QueueDebugOperation(arguments[1], [](WScriptJsrt::CallbackMessage& msg)
  545. {
  546. JsContextRef currentContext = JS_INVALID_REFERENCE;
  547. ChakraRTInterface::JsGetCurrentContext(&currentContext);
  548. JsRuntimeHandle currentRuntime = JS_INVALID_RUNTIME_HANDLE;
  549. ChakraRTInterface::JsGetRuntime(currentContext, &currentRuntime);
  550. if (Debugger::debugger != nullptr)
  551. {
  552. Debugger* debugger = Debugger::GetDebugger(currentRuntime);
  553. debugger->StopDebugging(currentRuntime);
  554. }
  555. return msg.CallFunction("");
  556. });
  557. Error:
  558. JsValueRef errorObject;
  559. JsValueRef errorMessageString;
  560. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  561. if (errorCode != JsNoError)
  562. {
  563. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  564. if (errorCode != JsNoError)
  565. {
  566. ChakraRTInterface::JsSetException(errorObject);
  567. }
  568. }
  569. return JS_INVALID_REFERENCE;
  570. }
  571. JsValueRef WScriptJsrt::DumpFunctionPositionCallback(JsValueRef callee, bool isConstructCall, JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  572. {
  573. JsValueRef functionPosition = JS_INVALID_REFERENCE;
  574. if (argumentCount > 1)
  575. {
  576. if (ChakraRTInterface::JsDiagGetFunctionPosition(arguments[1], &functionPosition) != JsNoError)
  577. {
  578. // If we can't get the functionPosition pass undefined
  579. IfJsErrorFailLogAndRet(ChakraRTInterface::JsGetUndefinedValue(&functionPosition));
  580. }
  581. if (Debugger::debugger != nullptr)
  582. {
  583. Debugger::debugger->DumpFunctionPosition(functionPosition);
  584. }
  585. }
  586. return JS_INVALID_REFERENCE;
  587. }
  588. JsValueRef WScriptJsrt::RequestAsyncBreakCallback(JsValueRef callee, bool isConstructCall,
  589. JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  590. {
  591. if (Debugger::debugger != nullptr && !Debugger::debugger->IsDetached())
  592. {
  593. IfJsErrorFailLogAndRet(ChakraRTInterface::JsDiagRequestAsyncBreak(Debugger::GetRuntime()));
  594. }
  595. else
  596. {
  597. Helpers::LogError(_u("RequestAsyncBreak can only be called when debugger is attached"));
  598. }
  599. return JS_INVALID_REFERENCE;
  600. }
  601. JsValueRef WScriptJsrt::EmptyCallback(JsValueRef callee, bool isConstructCall,
  602. JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  603. {
  604. return JS_INVALID_REFERENCE;
  605. }
  606. bool WScriptJsrt::CreateNamedFunction(const char* nameString, JsNativeFunction callback,
  607. JsValueRef* functionVar)
  608. {
  609. JsValueRef nameVar;
  610. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  611. nameString, strlen(nameString), &nameVar), false);
  612. IfJsrtErrorFail(ChakraRTInterface::JsCreateNamedFunction(nameVar, callback,
  613. nullptr, functionVar), false);
  614. return true;
  615. }
  616. bool WScriptJsrt::InstallObjectsOnObject(JsValueRef object, const char* name,
  617. JsNativeFunction nativeFunction)
  618. {
  619. JsValueRef propertyValueRef;
  620. JsPropertyIdRef propertyId;
  621. IfJsrtErrorFail(CreatePropertyIdFromString(name, &propertyId), false);
  622. CreateNamedFunction(name, nativeFunction, &propertyValueRef);
  623. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(object, propertyId,
  624. propertyValueRef, true), false);
  625. return true;
  626. }
  627. bool WScriptJsrt::Initialize()
  628. {
  629. HRESULT hr = S_OK;
  630. char CH_BINARY_LOCATION[2048];
  631. #ifdef CHAKRA_STATIC_LIBRARY
  632. const char* LINK_TYPE = "static";
  633. #else
  634. const char* LINK_TYPE = "shared";
  635. #endif
  636. JsValueRef wscript;
  637. IfJsrtErrorFail(ChakraRTInterface::JsCreateObject(&wscript), false);
  638. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Echo", EchoCallback));
  639. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Quit", QuitCallback));
  640. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadScriptFile", LoadScriptFileCallback));
  641. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadScript", LoadScriptCallback));
  642. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadModule", LoadModuleCallback));
  643. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "SetTimeout", SetTimeoutCallback));
  644. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "ClearTimeout", ClearTimeoutCallback));
  645. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Attach", AttachCallback));
  646. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Detach", DetachCallback));
  647. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "DumpFunctionPosition", DumpFunctionPositionCallback));
  648. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "RequestAsyncBreak", RequestAsyncBreakCallback));
  649. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadBinaryFile", LoadBinaryFileCallback));
  650. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadTextFile", LoadTextFileCallback));
  651. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Flag", FlagCallback));
  652. // ToDo Remove
  653. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Edit", EmptyCallback));
  654. // Platform
  655. JsValueRef platformObject;
  656. IfJsrtErrorFail(ChakraRTInterface::JsCreateObject(&platformObject), false);
  657. JsPropertyIdRef platformProperty;
  658. IfJsrtErrorFail(CreatePropertyIdFromString("Platform", &platformProperty), false);
  659. // Set CPU arch
  660. JsPropertyIdRef archProperty;
  661. IfJsrtErrorFail(CreatePropertyIdFromString("ARCH", &archProperty), false);
  662. JsValueRef archValue;
  663. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  664. CPU_ARCH_TEXT, strlen(CPU_ARCH_TEXT), &archValue), false);
  665. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, archProperty,
  666. archValue, true), false);
  667. // Set Build Type
  668. JsPropertyIdRef buildProperty;
  669. IfJsrtErrorFail(CreatePropertyIdFromString("BUILD_TYPE", &buildProperty), false);
  670. JsValueRef buildValue;
  671. #ifdef _DEBUG
  672. #define BUILD_TYPE_STRING_CH "Debug" // (O0)
  673. #elif defined(ENABLE_DEBUG_CONFIG_OPTIONS)
  674. #define BUILD_TYPE_STRING_CH "Test" // (O3 with debug config options)
  675. #else
  676. #define BUILD_TYPE_STRING_CH "Release" // (O3)
  677. #endif
  678. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  679. BUILD_TYPE_STRING_CH, strlen(BUILD_TYPE_STRING_CH), &buildValue), false);
  680. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, buildProperty,
  681. buildValue, true), false);
  682. #undef BUILD_TYPE_STRING_CH
  683. // Set Link Type [static / shared]
  684. JsPropertyIdRef linkProperty;
  685. IfJsrtErrorFail(CreatePropertyIdFromString("LINK_TYPE", &linkProperty), false);
  686. JsValueRef linkValue;
  687. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  688. LINK_TYPE, strlen(LINK_TYPE), &linkValue), false);
  689. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, linkProperty,
  690. linkValue, true), false);
  691. // Set Binary Location
  692. JsValueRef binaryPathValue;
  693. GetBinaryLocation(CH_BINARY_LOCATION, sizeof(CH_BINARY_LOCATION));
  694. JsPropertyIdRef binaryPathProperty;
  695. IfJsrtErrorFail(CreatePropertyIdFromString("BINARY_PATH", &binaryPathProperty), false);
  696. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  697. CH_BINARY_LOCATION,
  698. strlen(CH_BINARY_LOCATION), &binaryPathValue), false);
  699. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(
  700. platformObject, binaryPathProperty, binaryPathValue, true), false);
  701. // Set destination OS
  702. JsPropertyIdRef osProperty;
  703. IfJsrtErrorFail(CreatePropertyIdFromString("OS", &osProperty), false);
  704. JsValueRef osValue;
  705. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  706. DEST_PLATFORM_TEXT, strlen(DEST_PLATFORM_TEXT), &osValue), false);
  707. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, osProperty,
  708. osValue, true), false);
  709. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(wscript, platformProperty,
  710. platformObject, true), false);
  711. JsValueRef argsObject;
  712. if (!CreateArgumentsObject(&argsObject))
  713. {
  714. return false;
  715. }
  716. JsPropertyIdRef argsName;
  717. IfJsrtErrorFail(CreatePropertyIdFromString("Arguments", &argsName), false);
  718. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(wscript, argsName, argsObject, true), false);
  719. JsPropertyIdRef wscriptName;
  720. IfJsrtErrorFail(CreatePropertyIdFromString("WScript", &wscriptName), false);
  721. JsValueRef global;
  722. IfJsrtErrorFail(ChakraRTInterface::JsGetGlobalObject(&global), false);
  723. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(global, wscriptName, wscript, true), false);
  724. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(global, "print", EchoCallback));
  725. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(global, "read", LoadTextFileCallback));
  726. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(global, "readbuffer", LoadBinaryFileCallback));
  727. JsValueRef console;
  728. IfJsrtErrorFail(ChakraRTInterface::JsCreateObject(&console), false);
  729. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(console, "log", EchoCallback));
  730. JsPropertyIdRef consoleName;
  731. IfJsrtErrorFail(CreatePropertyIdFromString("console", &consoleName), false);
  732. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(global, consoleName, console, true), false);
  733. Error:
  734. return hr == S_OK;
  735. }
  736. bool WScriptJsrt::Uninitialize()
  737. {
  738. // moduleRecordMap is a global std::map, its destructor may access overrided
  739. // "operator delete" / global HeapAllocator::Instance. Clear it manually here
  740. // to avoid worrying about global destructor order.
  741. moduleRecordMap.clear();
  742. return true;
  743. }
  744. #if ENABLE_TTD
  745. void CALLBACK WScriptJsrt::JsContextBeforeCollectCallback(JsRef contextRef, void *data)
  746. {
  747. ChakraRTInterface::JsTTDNotifyContextDestroy(contextRef);
  748. }
  749. #endif
  750. JsValueRef __stdcall WScriptJsrt::LoadTextFileCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  751. {
  752. HRESULT hr = E_FAIL;
  753. JsValueRef returnValue = JS_INVALID_REFERENCE;
  754. JsErrorCode errorCode = JsNoError;
  755. if (argumentCount < 2)
  756. {
  757. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  758. }
  759. else
  760. {
  761. const char *fileContent;
  762. AutoString fileName;
  763. IfJsrtErrorSetGo(fileName.Initialize(arguments[1]));
  764. if (errorCode == JsNoError)
  765. {
  766. UINT lengthBytes = 0;
  767. hr = Helpers::LoadScriptFromFile(*fileName, fileContent, &lengthBytes);
  768. if (FAILED(hr))
  769. {
  770. fwprintf(stderr, _u("Couldn't load file.\n"));
  771. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  772. }
  773. else
  774. {
  775. JsValueRef stringObject;
  776. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateString(
  777. fileContent, lengthBytes, &stringObject));
  778. return stringObject;
  779. }
  780. }
  781. }
  782. Error:
  783. return returnValue;
  784. }
  785. JsValueRef __stdcall WScriptJsrt::LoadBinaryFileCallback(JsValueRef callee,
  786. bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  787. {
  788. HRESULT hr = E_FAIL;
  789. JsValueRef returnValue = JS_INVALID_REFERENCE;
  790. JsErrorCode errorCode = JsNoError;
  791. if (argumentCount < 2)
  792. {
  793. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  794. }
  795. else
  796. {
  797. const char *fileContent;
  798. AutoString fileName;
  799. IfJsrtErrorSetGo(fileName.Initialize(arguments[1]));
  800. if (errorCode == JsNoError)
  801. {
  802. UINT lengthBytes = 0;
  803. hr = Helpers::LoadBinaryFile(*fileName, fileContent, lengthBytes);
  804. if (FAILED(hr))
  805. {
  806. fwprintf(stderr, _u("Couldn't load file.\n"));
  807. }
  808. else
  809. {
  810. JsValueRef arrayBuffer;
  811. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateArrayBuffer(lengthBytes, &arrayBuffer));
  812. BYTE* buffer;
  813. unsigned int bufferLength;
  814. IfJsrtErrorSetGo(ChakraRTInterface::JsGetArrayBufferStorage(arrayBuffer, &buffer, &bufferLength));
  815. if (bufferLength < lengthBytes)
  816. {
  817. fwprintf(stderr, _u("Array buffer size is insufficient to store the binary file.\n"));
  818. }
  819. else
  820. {
  821. if (memcpy_s(buffer, bufferLength, (BYTE*)fileContent, lengthBytes) == 0)
  822. {
  823. returnValue = arrayBuffer;
  824. }
  825. }
  826. }
  827. }
  828. }
  829. Error:
  830. return returnValue;
  831. }
  832. JsValueRef __stdcall WScriptJsrt::FlagCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  833. {
  834. HRESULT hr = E_FAIL;
  835. JsValueRef returnValue = JS_INVALID_REFERENCE;
  836. JsErrorCode errorCode = JsNoError;
  837. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  838. #if ENABLE_DEBUG_CONFIG_OPTIONS
  839. if (argumentCount > 1)
  840. {
  841. AutoString cmd;
  842. IfJsrtErrorSetGo(cmd.Initialize(arguments[1]));
  843. char16* argv[] = { nullptr, cmd.GetWideString() };
  844. ChakraRTInterface::SetConfigFlags(2, argv, nullptr);
  845. }
  846. #endif
  847. Error:
  848. return returnValue;
  849. }
  850. bool WScriptJsrt::PrintException(LPCSTR fileName, JsErrorCode jsErrorCode)
  851. {
  852. LPCWSTR errorTypeString = ConvertErrorCodeToMessage(jsErrorCode);
  853. JsValueRef exception;
  854. ChakraRTInterface::JsGetAndClearException(&exception);
  855. if (exception != nullptr)
  856. {
  857. if (jsErrorCode == JsErrorCode::JsErrorScriptCompile || jsErrorCode == JsErrorCode::JsErrorScriptException)
  858. {
  859. AutoString errorMessage;
  860. IfJsrtErrorFail(errorMessage.Initialize(exception), false);
  861. if (jsErrorCode == JsErrorCode::JsErrorScriptCompile)
  862. {
  863. JsPropertyIdRef linePropertyId = JS_INVALID_REFERENCE;
  864. JsValueRef lineProperty = JS_INVALID_REFERENCE;
  865. JsPropertyIdRef columnPropertyId = JS_INVALID_REFERENCE;
  866. JsValueRef columnProperty = JS_INVALID_REFERENCE;
  867. int line;
  868. int column;
  869. IfJsrtErrorFail(CreatePropertyIdFromString("line", &linePropertyId), false);
  870. IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, linePropertyId, &lineProperty), false);
  871. IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(lineProperty, &line), false);
  872. IfJsrtErrorFail(CreatePropertyIdFromString("column", &columnPropertyId), false);
  873. IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, columnPropertyId, &columnProperty), false);
  874. IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(columnProperty, &column), false);
  875. CHAR shortFileName[_MAX_PATH];
  876. CHAR ext[_MAX_EXT];
  877. _splitpath_s(fileName, nullptr, 0, nullptr, 0, shortFileName, _countof(shortFileName), ext, _countof(ext));
  878. fwprintf(stderr, _u("%ls\n\tat code (%S%S:%d:%d)\n"),
  879. errorMessage.GetWideString(), shortFileName, ext, (int)line + 1,
  880. (int)column + 1);
  881. }
  882. else
  883. {
  884. JsValueType propertyType = JsUndefined;
  885. JsPropertyIdRef stackPropertyId = JS_INVALID_REFERENCE;
  886. JsValueRef stackProperty = JS_INVALID_REFERENCE;
  887. AutoString errorStack;
  888. JsErrorCode errorCode = CreatePropertyIdFromString("stack", &stackPropertyId);
  889. if (errorCode == JsErrorCode::JsNoError)
  890. {
  891. errorCode = ChakraRTInterface::JsGetProperty(exception, stackPropertyId, &stackProperty);
  892. if (errorCode == JsErrorCode::JsNoError)
  893. {
  894. errorCode = ChakraRTInterface::JsGetValueType(stackProperty, &propertyType);
  895. }
  896. }
  897. if (errorCode != JsErrorCode::JsNoError || propertyType == JsUndefined)
  898. {
  899. const char *fName = fileName != nullptr ? fileName : "(unknown)";
  900. // do not mix char/wchar. print them separately
  901. fprintf(stderr, "thrown at %s:\n^\n", fName);
  902. fwprintf(stderr, _u("%ls\n"), errorMessage.GetWideString());
  903. }
  904. else
  905. {
  906. IfJsrtErrorFail(errorStack.Initialize(stackProperty), false);
  907. fwprintf(stderr, _u("%ls\n"), errorStack.GetWideString());
  908. }
  909. }
  910. }
  911. else
  912. {
  913. fwprintf(stderr, _u("Error : %ls\n"), errorTypeString);
  914. }
  915. return true;
  916. }
  917. else
  918. {
  919. fwprintf(stderr, _u("Error : %ls\n"), errorTypeString);
  920. }
  921. return false;
  922. }
  923. void WScriptJsrt::AddMessageQueue(MessageQueue *_messageQueue)
  924. {
  925. Assert(messageQueue == nullptr);
  926. messageQueue = _messageQueue;
  927. }
  928. WScriptJsrt::CallbackMessage::CallbackMessage(unsigned int time, JsValueRef function) : MessageBase(time), m_function(function)
  929. {
  930. JsErrorCode error = ChakraRTInterface::JsAddRef(m_function, nullptr);
  931. if (error != JsNoError)
  932. {
  933. // Simply report a fatal error and exit because continuing from this point would result in inconsistent state
  934. // and FailFast telemetry would not be useful.
  935. wprintf(_u("FATAL ERROR: ChakraRTInterface::JsAddRef failed in WScriptJsrt::CallbackMessage::`ctor`. error=0x%x\n"), error);
  936. exit(1);
  937. }
  938. }
  939. WScriptJsrt::CallbackMessage::~CallbackMessage()
  940. {
  941. bool hasException = false;
  942. ChakraRTInterface::JsHasException(&hasException);
  943. if (hasException)
  944. {
  945. WScriptJsrt::PrintException("", JsErrorScriptException);
  946. }
  947. JsErrorCode errorCode = ChakraRTInterface::JsRelease(m_function, nullptr);
  948. Assert(errorCode == JsNoError);
  949. m_function = JS_INVALID_REFERENCE;
  950. }
  951. HRESULT WScriptJsrt::CallbackMessage::Call(LPCSTR fileName)
  952. {
  953. return CallFunction(fileName);
  954. }
  955. HRESULT WScriptJsrt::CallbackMessage::CallFunction(LPCSTR fileName)
  956. {
  957. HRESULT hr = S_OK;
  958. JsValueRef global;
  959. JsValueRef result;
  960. JsValueRef stringValue;
  961. JsValueType type;
  962. JsErrorCode errorCode = JsNoError;
  963. IfJsrtErrorHR(ChakraRTInterface::JsGetGlobalObject(&global));
  964. IfJsrtErrorHR(ChakraRTInterface::JsGetValueType(m_function, &type));
  965. if (type == JsString)
  966. {
  967. IfJsrtErrorHR(ChakraRTInterface::JsConvertValueToString(m_function, &stringValue));
  968. JsValueRef fname;
  969. ChakraRTInterface::JsCreateString("", strlen(""), &fname);
  970. // Run the code
  971. errorCode = ChakraRTInterface::JsRun(stringValue, JS_SOURCE_CONTEXT_NONE,
  972. fname, JsParseScriptAttributeArrayBufferIsUtf16Encoded,
  973. nullptr /*no result needed*/);
  974. }
  975. else
  976. {
  977. errorCode = ChakraRTInterface::JsCallFunction(m_function, &global, 1, &result);
  978. }
  979. if (errorCode != JsNoError)
  980. {
  981. hr = E_FAIL;
  982. PrintException(fileName, errorCode);
  983. }
  984. Error:
  985. return hr;
  986. }
  987. WScriptJsrt::ModuleMessage::ModuleMessage(JsModuleRecord module, JsValueRef specifier)
  988. : MessageBase(0), moduleRecord(module), specifier(specifier)
  989. {
  990. ChakraRTInterface::JsAddRef(module, nullptr);
  991. if (specifier != nullptr)
  992. {
  993. // nullptr specifier means a Promise to execute; non-nullptr means a "fetch" operation.
  994. ChakraRTInterface::JsAddRef(specifier, nullptr);
  995. }
  996. }
  997. WScriptJsrt::ModuleMessage::~ModuleMessage()
  998. {
  999. ChakraRTInterface::JsRelease(moduleRecord, nullptr);
  1000. if (specifier != nullptr)
  1001. {
  1002. ChakraRTInterface::JsRelease(specifier, nullptr);
  1003. }
  1004. }
  1005. HRESULT WScriptJsrt::ModuleMessage::Call(LPCSTR fileName)
  1006. {
  1007. JsErrorCode errorCode;
  1008. JsValueRef result = JS_INVALID_REFERENCE;
  1009. HRESULT hr;
  1010. if (specifier == nullptr)
  1011. {
  1012. errorCode = ChakraRTInterface::JsModuleEvaluation(moduleRecord, &result);
  1013. if (errorCode != JsNoError)
  1014. {
  1015. PrintException(fileName, errorCode);
  1016. }
  1017. }
  1018. else
  1019. {
  1020. LPCSTR fileContent = nullptr;
  1021. AutoString specifierStr(specifier);
  1022. errorCode = specifierStr.GetError();
  1023. if (errorCode == JsNoError)
  1024. {
  1025. hr = Helpers::LoadScriptFromFile(specifierStr.GetString(), fileContent);
  1026. if (FAILED(hr))
  1027. {
  1028. fprintf(stderr, "Couldn't load file.\n");
  1029. }
  1030. else
  1031. {
  1032. LoadScript(nullptr, specifierStr.GetString(), fileContent, "module", true);
  1033. }
  1034. }
  1035. }
  1036. return errorCode;
  1037. }
  1038. // Callback from chakracore to fetch dependent module. In the test harness,
  1039. // we are not doing any translation, just treat the specifier as fileName.
  1040. // While this call will come back directly from ParseModuleSource, the additional
  1041. // task are treated as Promise that will be executed later.
  1042. JsErrorCode WScriptJsrt::FetchImportedModule(_In_ JsModuleRecord referencingModule,
  1043. _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1044. {
  1045. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1046. AutoString specifierStr;
  1047. *dependentModuleRecord = nullptr;
  1048. if (specifierStr.Initialize(specifier) != JsNoError)
  1049. {
  1050. return specifierStr.GetError();
  1051. }
  1052. auto moduleEntry = moduleRecordMap.find(std::string(*specifierStr));
  1053. if (moduleEntry != moduleRecordMap.end())
  1054. {
  1055. *dependentModuleRecord = moduleEntry->second;
  1056. return JsNoError;
  1057. }
  1058. JsErrorCode errorCode = ChakraRTInterface::JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1059. if (errorCode == JsNoError)
  1060. {
  1061. InitializeModuleInfo(specifier, moduleRecord);
  1062. moduleRecordMap[std::string(*specifierStr)] = moduleRecord;
  1063. ModuleMessage* moduleMessage =
  1064. WScriptJsrt::ModuleMessage::Create(referencingModule, specifier);
  1065. if (moduleMessage == nullptr)
  1066. {
  1067. return JsErrorOutOfMemory;
  1068. }
  1069. WScriptJsrt::PushMessage(moduleMessage);
  1070. *dependentModuleRecord = moduleRecord;
  1071. }
  1072. return errorCode;
  1073. }
  1074. // Callback from chakraCore when the module resolution is finished, either successfuly or unsuccessfully.
  1075. JsErrorCode WScriptJsrt::NotifyModuleReadyCallback(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  1076. {
  1077. if (exceptionVar != nullptr)
  1078. {
  1079. ChakraRTInterface::JsSetException(exceptionVar);
  1080. JsValueRef specifier = JS_INVALID_REFERENCE;
  1081. ChakraRTInterface::JsGetModuleHostInfo(referencingModule, JsModuleHostInfo_HostDefined, &specifier);
  1082. AutoString fileName;
  1083. if (specifier != JS_INVALID_REFERENCE)
  1084. {
  1085. fileName.Initialize(specifier);
  1086. }
  1087. PrintException(*fileName, JsErrorScriptException);
  1088. }
  1089. else
  1090. {
  1091. WScriptJsrt::ModuleMessage* moduleMessage =
  1092. WScriptJsrt::ModuleMessage::Create(referencingModule, nullptr);
  1093. if (moduleMessage == nullptr)
  1094. {
  1095. return JsErrorOutOfMemory;
  1096. }
  1097. WScriptJsrt::PushMessage(moduleMessage);
  1098. }
  1099. return JsNoError;
  1100. }