WScriptJsrt.cpp 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757
  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. #include <vector>
  7. #if defined(_X86_) || defined(_M_IX86)
  8. #define CPU_ARCH_TEXT "x86"
  9. #elif defined(_AMD64_) || defined(_IA64_) || defined(_M_AMD64) || defined(_M_IA64)
  10. #define CPU_ARCH_TEXT "x86_64"
  11. #elif defined(_ARM_) || defined(_M_ARM)
  12. #define CPU_ARCH_TEXT "ARM"
  13. #elif defined(_ARM64_) || defined(_M_ARM64)
  14. #define CPU_ARCH_TEXT "ARM64"
  15. #endif
  16. // do not change the order below
  17. // otherwise, i.e. android system can be marked as posix? etc..
  18. #ifdef _WIN32
  19. #define DEST_PLATFORM_TEXT "win32"
  20. #else // ! _WIN32
  21. #if defined(__APPLE__)
  22. #ifdef __IOS__
  23. #define DEST_PLATFORM_TEXT "ios"
  24. #else // ! iOS
  25. #define DEST_PLATFORM_TEXT "darwin"
  26. #endif // iOS ?
  27. #elif defined(__ANDROID__)
  28. #define DEST_PLATFORM_TEXT "android"
  29. #elif defined(__linux__)
  30. #define DEST_PLATFORM_TEXT "posix"
  31. #elif defined(__FreeBSD__) || defined(__unix__)
  32. #define DEST_PLATFORM_TEXT "bsd"
  33. #endif // FreeBSD or unix ?
  34. #endif // _WIN32 ?
  35. MessageQueue* WScriptJsrt::messageQueue = nullptr;
  36. std::map<std::string, JsModuleRecord> WScriptJsrt::moduleRecordMap;
  37. std::map<JsModuleRecord, std::string> WScriptJsrt::moduleDirMap;
  38. std::map<DWORD_PTR, std::string> WScriptJsrt::scriptDirMap;
  39. DWORD_PTR WScriptJsrt::sourceContext = 0;
  40. #define ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString) \
  41. JsErrorCode errorCode = JsNoError; \
  42. do \
  43. { \
  44. const char *outOfMemoryString = \
  45. "Failed to convert wide string. Out of memory?";\
  46. \
  47. char *errorMessageNarrow; \
  48. if (FAILED(WideStringToNarrowDynamic(errorMessage, &errorMessageNarrow))) \
  49. { \
  50. errorCode = ChakraRTInterface::JsCreateString(outOfMemoryString, \
  51. strlen(outOfMemoryString), &errorMessageString); \
  52. } \
  53. else \
  54. { \
  55. errorCode = ChakraRTInterface::JsCreateString(errorMessageNarrow, \
  56. strlen(errorMessageNarrow), &errorMessageString); \
  57. free(errorMessageNarrow); \
  58. } \
  59. } \
  60. while(0)
  61. DWORD_PTR WScriptJsrt::GetNextSourceContext()
  62. {
  63. return sourceContext++;
  64. }
  65. void WScriptJsrt::RegisterScriptDir(DWORD_PTR sourceContext, LPCSTR fullDirNarrow)
  66. {
  67. GetDir(fullDirNarrow, &scriptDirMap[sourceContext]);
  68. }
  69. bool WScriptJsrt::CreateArgumentsObject(JsValueRef *argsObject)
  70. {
  71. LPWSTR *argv = HostConfigFlags::argsVal;
  72. JsValueRef retArr;
  73. Assert(argsObject);
  74. *argsObject = nullptr;
  75. IfJsrtErrorFail(ChakraRTInterface::JsCreateArray(HostConfigFlags::argsCount, &retArr), false);
  76. for (int i = 0; i < HostConfigFlags::argsCount; i++)
  77. {
  78. JsValueRef value;
  79. JsValueRef index;
  80. char *argNarrow;
  81. if (FAILED(WideStringToNarrowDynamic(argv[i], &argNarrow)))
  82. {
  83. return false;
  84. }
  85. JsErrorCode errCode = ChakraRTInterface::JsCreateString(
  86. argNarrow,
  87. strlen(argNarrow), &value);
  88. free(argNarrow);
  89. IfJsrtErrorFail(errCode, false);
  90. IfJsrtErrorFail(ChakraRTInterface::JsDoubleToNumber(i, &index), false);
  91. IfJsrtErrorFail(ChakraRTInterface::JsSetIndexedProperty(retArr, index, value), false);
  92. }
  93. *argsObject = retArr;
  94. return true;
  95. }
  96. JsValueRef __stdcall WScriptJsrt::EchoCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  97. {
  98. for (unsigned int i = 1; i < argumentCount; i++)
  99. {
  100. JsValueRef strValue;
  101. JsErrorCode error = ChakraRTInterface::JsConvertValueToString(arguments[i], &strValue);
  102. if (error == JsNoError)
  103. {
  104. AutoString str(strValue);
  105. if (str.GetError() == JsNoError)
  106. {
  107. if (i > 1)
  108. {
  109. wprintf(_u(" "));
  110. }
  111. wprintf(_u("%ls"), str.GetWideString());
  112. }
  113. }
  114. if (error == JsErrorScriptException)
  115. {
  116. return nullptr;
  117. }
  118. }
  119. wprintf(_u("\n"));
  120. fflush(stdout);
  121. JsValueRef undefinedValue;
  122. if (ChakraRTInterface::JsGetUndefinedValue(&undefinedValue) == JsNoError)
  123. {
  124. return undefinedValue;
  125. }
  126. else
  127. {
  128. return nullptr;
  129. }
  130. }
  131. JsValueRef __stdcall WScriptJsrt::QuitCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  132. {
  133. int exitCode = 0;
  134. if (argumentCount > 1)
  135. {
  136. double exitCodeDouble;
  137. IfJsrtErrorFail(ChakraRTInterface::JsNumberToDouble(arguments[1], &exitCodeDouble), JS_INVALID_REFERENCE);
  138. exitCode = (int)exitCodeDouble;
  139. }
  140. ExitProcess(exitCode);
  141. }
  142. JsValueRef __stdcall WScriptJsrt::LoadScriptFileCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  143. {
  144. return LoadScriptFileHelper(callee, arguments, argumentCount, false);
  145. }
  146. // needed because of calling convention differences between _stdcall and _cdecl
  147. void CHAKRA_CALLBACK WScriptJsrt::FinalizeFree(void* addr)
  148. {
  149. free(addr);
  150. }
  151. JsValueRef WScriptJsrt::LoadScriptFileHelper(JsValueRef callee, JsValueRef *arguments, unsigned short argumentCount, bool isSourceModule)
  152. {
  153. HRESULT hr = E_FAIL;
  154. JsValueRef returnValue = JS_INVALID_REFERENCE;
  155. JsErrorCode errorCode = JsNoError;
  156. LPCWSTR errorMessage = _u("");
  157. if (argumentCount < 2 || argumentCount > 4)
  158. {
  159. errorCode = JsErrorInvalidArgument;
  160. errorMessage = _u("Need more or fewer arguments for WScript.LoadScript");
  161. }
  162. else
  163. {
  164. LPCSTR fileContent;
  165. AutoString fileName(arguments[1]);
  166. IfJsrtErrorSetGo(fileName.GetError());
  167. AutoString scriptInjectType;
  168. if (argumentCount > 2)
  169. {
  170. IfJsrtErrorSetGo(scriptInjectType.Initialize(arguments[2]));
  171. }
  172. if (errorCode == JsNoError)
  173. {
  174. hr = Helpers::LoadScriptFromFile(*fileName, fileContent);
  175. if (FAILED(hr))
  176. {
  177. // check if have it registered
  178. fprintf(stderr, "Couldn't load file '%s'\n", fileName.GetString());
  179. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  180. return returnValue;
  181. }
  182. returnValue = LoadScript(callee, *fileName, fileContent, *scriptInjectType ? *scriptInjectType : "self", isSourceModule, WScriptJsrt::FinalizeFree, true);
  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. ERROR_MESSAGE_TO_STRING(errCode, errorMessage, errorMessageString);
  194. ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  195. ChakraRTInterface::JsSetException(errorObject);
  196. }
  197. return returnValue;
  198. }
  199. JsValueRef __stdcall WScriptJsrt::LoadScriptCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  200. {
  201. return LoadScriptHelper(callee, isConstructCall, arguments, argumentCount, callbackState, false);
  202. }
  203. JsValueRef __stdcall WScriptJsrt::LoadModuleCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  204. {
  205. return LoadScriptHelper(callee, isConstructCall, arguments, argumentCount, callbackState, true);
  206. }
  207. JsValueRef WScriptJsrt::LoadScriptHelper(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState, bool isSourceModule)
  208. {
  209. HRESULT hr = E_FAIL;
  210. JsErrorCode errorCode = JsNoError;
  211. LPCWSTR errorMessage = _u("");
  212. JsValueRef returnValue = JS_INVALID_REFERENCE;
  213. if (argumentCount < 2 || argumentCount > 4)
  214. {
  215. errorCode = JsErrorInvalidArgument;
  216. errorMessage = _u("Need more or fewer arguments for WScript.LoadScript");
  217. }
  218. else
  219. {
  220. AutoString fileContent;
  221. char *fileNameNarrow = nullptr;
  222. AutoString fileName;
  223. AutoString scriptInjectType;
  224. char fileNameBuffer[MAX_PATH];
  225. bool isFile = true;
  226. IfJsrtErrorSetGo(fileContent.Initialize(arguments[1]));
  227. // ExternalArrayBuffer Finalize will clean this up
  228. // but only if we actually register a finalizecallback for this
  229. fileContent.MakePersistent();
  230. if (argumentCount > 2)
  231. {
  232. IfJsrtErrorSetGo(scriptInjectType.Initialize(arguments[2]));
  233. if (argumentCount > 3)
  234. {
  235. IfJsrtErrorSetGo(fileName.Initialize(arguments[3]));
  236. fileNameNarrow = *fileName;
  237. }
  238. }
  239. if (!fileNameNarrow)
  240. {
  241. isFile = false;
  242. if (isSourceModule)
  243. {
  244. sprintf_s(fileNameBuffer, MAX_PATH, "moduleScript%i.js", (int)sourceContext);
  245. fileNameNarrow = fileNameBuffer;
  246. }
  247. }
  248. if (*fileContent)
  249. {
  250. // TODO: This is CESU-8. How to tell the engine?
  251. // TODO: How to handle this source (script) life time?
  252. returnValue = LoadScript(callee, fileNameNarrow, *fileContent, *scriptInjectType ? *scriptInjectType : "self", isSourceModule, WScriptJsrt::FinalizeFree, isFile);
  253. }
  254. }
  255. Error:
  256. if (errorCode != JsNoError)
  257. {
  258. JsValueRef errorObject;
  259. JsValueRef errorMessageString;
  260. if (wcscmp(errorMessage, _u("")) == 0) {
  261. errorMessage = ConvertErrorCodeToMessage(errorCode);
  262. }
  263. ERROR_MESSAGE_TO_STRING(errCode, errorMessage, errorMessageString);
  264. ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  265. ChakraRTInterface::JsSetException(errorObject);
  266. }
  267. return returnValue;
  268. }
  269. JsErrorCode WScriptJsrt::InitializeModuleInfo(JsValueRef specifier, JsModuleRecord moduleRecord)
  270. {
  271. JsErrorCode errorCode = JsNoError;
  272. errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_FetchImportedModuleCallback, (void*)WScriptJsrt::FetchImportedModule);
  273. if (errorCode == JsNoError)
  274. {
  275. errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, (void*)WScriptJsrt::FetchImportedModuleFromScript);
  276. if (errorCode == JsNoError)
  277. {
  278. errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_NotifyModuleReadyCallback, (void*)WScriptJsrt::NotifyModuleReadyCallback);
  279. if (errorCode == JsNoError)
  280. {
  281. errorCode = ChakraRTInterface::JsSetModuleHostInfo(moduleRecord, JsModuleHostInfo_HostDefined, specifier);
  282. }
  283. }
  284. }
  285. IfJsrtErrorFailLogAndRetErrorCode(errorCode);
  286. return JsNoError;
  287. }
  288. void WScriptJsrt::GetDir(LPCSTR fullPathNarrow, std::string *fullDirNarrow)
  289. {
  290. char fileDrive[_MAX_DRIVE];
  291. char fileDir[_MAX_DIR];
  292. std::string result;
  293. if (_splitpath_s(fullPathNarrow, fileDrive, _countof(fileDrive), fileDir, _countof(fileDir), nullptr, 0, nullptr, 0) == 0)
  294. {
  295. result += fileDrive;
  296. result += fileDir;
  297. }
  298. *fullDirNarrow = result;
  299. }
  300. JsErrorCode WScriptJsrt::LoadModuleFromString(LPCSTR fileName, LPCSTR fileContent, LPCSTR fullName, bool isFile)
  301. {
  302. DWORD_PTR dwSourceCookie = WScriptJsrt::GetNextSourceContext();
  303. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  304. LPCSTR moduleRecordKey = fullName ? fullName : fileName;
  305. auto moduleRecordEntry = moduleRecordMap.find(std::string(moduleRecordKey));
  306. JsErrorCode errorCode = JsNoError;
  307. // we need to create a new moduleRecord if the specifier (fileName) is not found;
  308. // otherwise we'll use the old one.
  309. if (moduleRecordEntry == moduleRecordMap.end())
  310. {
  311. JsValueRef specifier;
  312. errorCode = ChakraRTInterface::JsCreateString(
  313. fileName, strlen(fileName), &specifier);
  314. if (errorCode == JsNoError)
  315. {
  316. errorCode = ChakraRTInterface::JsInitializeModuleRecord(
  317. nullptr, specifier, &requestModule);
  318. }
  319. if (errorCode == JsNoError)
  320. {
  321. errorCode = InitializeModuleInfo(specifier, requestModule);
  322. }
  323. if (errorCode == JsNoError)
  324. {
  325. if (fullName)
  326. {
  327. GetDir(fullName, &moduleDirMap[requestModule]);
  328. }
  329. moduleRecordMap[std::string(moduleRecordKey)] = requestModule;
  330. }
  331. }
  332. else
  333. {
  334. requestModule = moduleRecordEntry->second;
  335. }
  336. IfJsrtErrorFailLogAndRetErrorCode(errorCode);
  337. JsValueRef errorObject = JS_INVALID_REFERENCE;
  338. // ParseModuleSource is sync, while additional fetch & evaluation are async.
  339. unsigned int fileContentLength = (fileContent == nullptr) ? 0 : (unsigned int)strlen(fileContent);
  340. if (isFile && fullName)
  341. {
  342. JsValueRef moduleUrl;
  343. ChakraRTInterface::JsCreateString(fullName, strlen(fullName), &moduleUrl);
  344. errorCode = ChakraRTInterface::JsSetModuleHostInfo(requestModule, JsModuleHostInfo_Url, moduleUrl);
  345. IfJsrtErrorFail(errorCode, errorCode);
  346. }
  347. errorCode = ChakraRTInterface::JsParseModuleSource(requestModule, dwSourceCookie, (LPBYTE)fileContent,
  348. fileContentLength, JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  349. if ((errorCode != JsNoError) && errorObject != JS_INVALID_REFERENCE && fileContent != nullptr && !HostConfigFlags::flags.IgnoreScriptErrorCode)
  350. {
  351. ChakraRTInterface::JsSetException(errorObject);
  352. return errorCode;
  353. }
  354. return JsNoError;
  355. }
  356. JsValueRef WScriptJsrt::LoadScript(JsValueRef callee, LPCSTR fileName,
  357. LPCSTR fileContent, LPCSTR scriptInjectType, bool isSourceModule, JsFinalizeCallback finalizeCallback, bool isFile)
  358. {
  359. HRESULT hr = E_FAIL;
  360. JsErrorCode errorCode = JsNoError;
  361. LPCWSTR errorMessage = _u("Internal error.");
  362. JsValueRef returnValue = JS_INVALID_REFERENCE;
  363. JsErrorCode innerErrorCode = JsNoError;
  364. JsContextRef currentContext = JS_INVALID_REFERENCE;
  365. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  366. void *callbackArg = (finalizeCallback != nullptr ? (void*)fileContent : nullptr);
  367. char fullPath[_MAX_PATH];
  368. IfJsrtErrorSetGo(ChakraRTInterface::JsGetCurrentContext(&currentContext));
  369. IfJsrtErrorSetGo(ChakraRTInterface::JsGetRuntime(currentContext, &runtime));
  370. if (fileName == nullptr)
  371. {
  372. fileName = "script.js";
  373. }
  374. if (_fullpath(fullPath, fileName, _MAX_PATH) == nullptr)
  375. {
  376. goto Error;
  377. }
  378. // this is called with LoadModuleCallback method as well where caller pass in a string that should be
  379. // treated as a module source text instead of opening a new file.
  380. if (isSourceModule || (strcmp(scriptInjectType, "module") == 0))
  381. {
  382. errorCode = LoadModuleFromString(fileName, fileContent, fullPath, isFile);
  383. }
  384. else if (strcmp(scriptInjectType, "self") == 0)
  385. {
  386. JsContextRef calleeContext;
  387. IfJsrtErrorSetGo(ChakraRTInterface::JsGetContextOfObject(callee, &calleeContext));
  388. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(calleeContext));
  389. JsValueRef scriptSource;
  390. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContent,
  391. (unsigned int)strlen(fileContent), finalizeCallback, callbackArg, &scriptSource));
  392. JsValueRef fname;
  393. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateString(fullPath,
  394. strlen(fullPath), &fname));
  395. JsSourceContext sourceContext = GetNextSourceContext();
  396. RegisterScriptDir(sourceContext, fullPath);
  397. errorCode = ChakraRTInterface::JsRun(scriptSource, sourceContext,
  398. fname, JsParseScriptAttributeNone, &returnValue);
  399. if(errorCode == JsNoError)
  400. {
  401. errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
  402. }
  403. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(currentContext));
  404. }
  405. else if (strcmp(scriptInjectType, "samethread") == 0)
  406. {
  407. JsValueRef newContext = JS_INVALID_REFERENCE;
  408. // Create a new context and set it as the current context
  409. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateContext(runtime, &newContext));
  410. #if ENABLE_TTD
  411. //We need this here since this context is created in record
  412. IfJsrtErrorSetGo(ChakraRTInterface::JsSetObjectBeforeCollectCallback(newContext, nullptr, WScriptJsrt::JsContextBeforeCollectCallback));
  413. #endif
  414. IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(newContext));
  415. IfJsErrorFailLog(ChakraRTInterface::JsSetPromiseContinuationCallback(PromiseContinuationCallback, (void*)messageQueue));
  416. // Initialize the host objects
  417. Initialize();
  418. JsValueRef scriptSource;
  419. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContent,
  420. (unsigned int)strlen(fileContent), finalizeCallback, callbackArg, &scriptSource));
  421. JsValueRef fname;
  422. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateString(fullPath,
  423. strlen(fullPath), &fname));
  424. JsSourceContext sourceContext = GetNextSourceContext();
  425. RegisterScriptDir(sourceContext, fullPath);
  426. errorCode = ChakraRTInterface::JsRun(scriptSource, sourceContext,
  427. fname, JsParseScriptAttributeNone, &returnValue);
  428. if (errorCode == JsNoError)
  429. {
  430. errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue);
  431. }
  432. // Set the context back to the old one
  433. ChakraRTInterface::JsSetCurrentContext(currentContext);
  434. }
  435. else if (strcmp(scriptInjectType, "crossthread") == 0)
  436. {
  437. auto& threadData = GetRuntimeThreadLocalData().threadData;
  438. if (threadData == nullptr)
  439. {
  440. threadData = new RuntimeThreadData();
  441. }
  442. RuntimeThreadData* child = new RuntimeThreadData();
  443. child->initialSource = fileContent;
  444. threadData->children.push_back(child);
  445. child->parent = threadData;
  446. // TODO: need to add a switch in case we don't need to wait for
  447. // child initial script completion
  448. ResetEvent(threadData->hevntInitialScriptCompleted);
  449. child->hThread = ::CreateThread(NULL, NULL, [](void* param) -> DWORD
  450. {
  451. return ((RuntimeThreadData*)param)->ThreadProc();
  452. }, (void*)child, NULL, NULL);
  453. WaitForSingleObject(threadData->hevntInitialScriptCompleted, INFINITE);
  454. }
  455. else
  456. {
  457. errorCode = JsErrorInvalidArgument;
  458. errorMessage = _u("Unsupported argument type inject type.");
  459. }
  460. Error:
  461. JsValueRef value = returnValue;
  462. if (errorCode != JsNoError)
  463. {
  464. if (innerErrorCode != JsNoError)
  465. {
  466. // Failed to retrieve the inner error message, so set a custom error string
  467. errorMessage = ConvertErrorCodeToMessage(errorCode);
  468. }
  469. JsValueRef error = JS_INVALID_REFERENCE;
  470. JsValueRef messageProperty = JS_INVALID_REFERENCE;
  471. ERROR_MESSAGE_TO_STRING(errCode, errorMessage, messageProperty);
  472. if (errCode == JsNoError)
  473. {
  474. errCode = ChakraRTInterface::JsCreateError(messageProperty, &error);
  475. if (errCode == JsNoError)
  476. {
  477. bool hasException = false;
  478. errorCode = ChakraRTInterface::JsHasException(&hasException);
  479. if (errorCode == JsNoError && !hasException)
  480. {
  481. errCode = ChakraRTInterface::JsSetException(error);
  482. }
  483. else if (errCode == JsNoError)
  484. {
  485. errCode = JsErrorInExceptionState;
  486. }
  487. }
  488. }
  489. ChakraRTInterface::JsDoubleToNumber(errorCode, &value);
  490. }
  491. _flushall();
  492. return value;
  493. }
  494. JsValueRef WScriptJsrt::SetTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  495. {
  496. LPCWSTR errorMessage = _u("invalid call to WScript.SetTimeout");
  497. JsValueRef function;
  498. JsValueRef timerId;
  499. unsigned int time;
  500. double tmp;
  501. CallbackMessage *msg = nullptr;
  502. if (argumentCount != 3)
  503. {
  504. goto Error;
  505. }
  506. function = arguments[1];
  507. IfJsrtError(ChakraRTInterface::JsNumberToDouble(arguments[2], &tmp));
  508. time = static_cast<int>(tmp);
  509. msg = new CallbackMessage(time, function);
  510. messageQueue->InsertSorted(msg);
  511. IfJsrtError(ChakraRTInterface::JsDoubleToNumber(static_cast<double>(msg->GetId()), &timerId));
  512. return timerId;
  513. Error:
  514. JsValueRef errorObject;
  515. JsValueRef errorMessageString;
  516. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  517. if (errorCode != JsNoError)
  518. {
  519. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  520. if (errorCode != JsNoError)
  521. {
  522. ChakraRTInterface::JsSetException(errorObject);
  523. }
  524. }
  525. return JS_INVALID_REFERENCE;
  526. }
  527. JsValueRef WScriptJsrt::ClearTimeoutCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  528. {
  529. LPCWSTR errorMessage = _u("invalid call to WScript.ClearTimeout");
  530. if (argumentCount != 2)
  531. {
  532. goto Error;
  533. }
  534. unsigned int timerId;
  535. double tmp;
  536. JsValueRef undef;
  537. JsValueRef global;
  538. IfJsrtError(ChakraRTInterface::JsNumberToDouble(arguments[1], &tmp));
  539. timerId = static_cast<int>(tmp);
  540. messageQueue->RemoveById(timerId);
  541. IfJsrtError(ChakraRTInterface::JsGetGlobalObject(&global));
  542. IfJsrtError(ChakraRTInterface::JsGetUndefinedValue(&undef));
  543. return undef;
  544. Error:
  545. JsValueRef errorObject;
  546. JsValueRef errorMessageString;
  547. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  548. if (errorCode != JsNoError)
  549. {
  550. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  551. if (errorCode != JsNoError)
  552. {
  553. ChakraRTInterface::JsSetException(errorObject);
  554. }
  555. }
  556. return JS_INVALID_REFERENCE;
  557. }
  558. template <class DebugOperationFunc>
  559. void QueueDebugOperation(JsValueRef function, const DebugOperationFunc& operation)
  560. {
  561. WScriptJsrt::PushMessage(WScriptJsrt::CallbackMessage::Create(function, operation));
  562. }
  563. JsValueRef WScriptJsrt::AttachCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  564. {
  565. LPCWSTR errorMessage = _u("WScript.Attach requires a function, like WScript.Attach(foo);");
  566. JsValueType argumentType = JsUndefined;
  567. if (argumentCount != 2)
  568. {
  569. goto Error;
  570. }
  571. IfJsrtError(ChakraRTInterface::JsGetValueType(arguments[1], &argumentType));
  572. if (argumentType != JsFunction)
  573. {
  574. goto Error;
  575. }
  576. QueueDebugOperation(arguments[1], [](WScriptJsrt::CallbackMessage& msg)
  577. {
  578. JsContextRef currentContext = JS_INVALID_REFERENCE;
  579. ChakraRTInterface::JsGetCurrentContext(&currentContext);
  580. JsRuntimeHandle currentRuntime = JS_INVALID_RUNTIME_HANDLE;
  581. ChakraRTInterface::JsGetRuntime(currentContext, &currentRuntime);
  582. Debugger* debugger = Debugger::GetDebugger(currentRuntime);
  583. debugger->StartDebugging(currentRuntime);
  584. debugger->SourceRunDown();
  585. return msg.CallFunction("");
  586. });
  587. Error:
  588. JsValueRef errorObject;
  589. JsValueRef errorMessageString;
  590. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  591. if (errorCode != JsNoError)
  592. {
  593. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  594. if (errorCode != JsNoError)
  595. {
  596. ChakraRTInterface::JsSetException(errorObject);
  597. }
  598. }
  599. return JS_INVALID_REFERENCE;
  600. }
  601. JsValueRef WScriptJsrt::DetachCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  602. {
  603. LPCWSTR errorMessage = _u("WScript.Detach requires a function, like WScript.Detach(foo);");
  604. JsValueType argumentType = JsUndefined;
  605. if (argumentCount != 2)
  606. {
  607. goto Error;
  608. }
  609. IfJsrtError(ChakraRTInterface::JsGetValueType(arguments[1], &argumentType));
  610. if (argumentType != JsFunction)
  611. {
  612. goto Error;
  613. }
  614. QueueDebugOperation(arguments[1], [](WScriptJsrt::CallbackMessage& msg)
  615. {
  616. JsContextRef currentContext = JS_INVALID_REFERENCE;
  617. ChakraRTInterface::JsGetCurrentContext(&currentContext);
  618. JsRuntimeHandle currentRuntime = JS_INVALID_RUNTIME_HANDLE;
  619. ChakraRTInterface::JsGetRuntime(currentContext, &currentRuntime);
  620. if (Debugger::debugger != nullptr)
  621. {
  622. Debugger* debugger = Debugger::GetDebugger(currentRuntime);
  623. debugger->StopDebugging(currentRuntime);
  624. }
  625. return msg.CallFunction("");
  626. });
  627. Error:
  628. JsValueRef errorObject;
  629. JsValueRef errorMessageString;
  630. ERROR_MESSAGE_TO_STRING(errorCode, errorMessage, errorMessageString);
  631. if (errorCode != JsNoError)
  632. {
  633. errorCode = ChakraRTInterface::JsCreateError(errorMessageString, &errorObject);
  634. if (errorCode != JsNoError)
  635. {
  636. ChakraRTInterface::JsSetException(errorObject);
  637. }
  638. }
  639. return JS_INVALID_REFERENCE;
  640. }
  641. JsValueRef WScriptJsrt::DumpFunctionPositionCallback(JsValueRef callee, bool isConstructCall, JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  642. {
  643. JsValueRef functionPosition = JS_INVALID_REFERENCE;
  644. if (argumentCount > 1)
  645. {
  646. if (ChakraRTInterface::JsDiagGetFunctionPosition(arguments[1], &functionPosition) != JsNoError)
  647. {
  648. // If we can't get the functionPosition pass undefined
  649. IfJsErrorFailLogAndRet(ChakraRTInterface::JsGetUndefinedValue(&functionPosition));
  650. }
  651. if (Debugger::debugger != nullptr)
  652. {
  653. Debugger::debugger->DumpFunctionPosition(functionPosition);
  654. }
  655. }
  656. return JS_INVALID_REFERENCE;
  657. }
  658. JsValueRef WScriptJsrt::RequestAsyncBreakCallback(JsValueRef callee, bool isConstructCall,
  659. JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  660. {
  661. if (Debugger::debugger != nullptr && !Debugger::debugger->IsDetached())
  662. {
  663. IfJsErrorFailLogAndRet(ChakraRTInterface::JsDiagRequestAsyncBreak(Debugger::GetRuntime()));
  664. }
  665. else
  666. {
  667. Helpers::LogError(_u("RequestAsyncBreak can only be called when debugger is attached"));
  668. }
  669. return JS_INVALID_REFERENCE;
  670. }
  671. JsValueRef WScriptJsrt::EmptyCallback(JsValueRef callee, bool isConstructCall,
  672. JsValueRef * arguments, unsigned short argumentCount, void * callbackState)
  673. {
  674. return JS_INVALID_REFERENCE;
  675. }
  676. bool WScriptJsrt::CreateNamedFunction(const char* nameString, JsNativeFunction callback,
  677. JsValueRef* functionVar)
  678. {
  679. JsValueRef nameVar;
  680. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  681. nameString, strlen(nameString), &nameVar), false);
  682. IfJsrtErrorFail(ChakraRTInterface::JsCreateNamedFunction(nameVar, callback,
  683. nullptr, functionVar), false);
  684. return true;
  685. }
  686. bool WScriptJsrt::InstallObjectsOnObject(JsValueRef object, const char* name,
  687. JsNativeFunction nativeFunction)
  688. {
  689. JsValueRef propertyValueRef;
  690. JsPropertyIdRef propertyId;
  691. IfJsrtErrorFail(CreatePropertyIdFromString(name, &propertyId), false);
  692. if (!CreateNamedFunction(name, nativeFunction, &propertyValueRef))
  693. {
  694. return false;
  695. }
  696. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(object, propertyId,
  697. propertyValueRef, true), false);
  698. return true;
  699. }
  700. bool WScriptJsrt::Initialize()
  701. {
  702. HRESULT hr = S_OK;
  703. char CH_BINARY_LOCATION[2048];
  704. #ifdef CHAKRA_STATIC_LIBRARY
  705. const char* LINK_TYPE = "static";
  706. #else
  707. const char* LINK_TYPE = "shared";
  708. #endif
  709. JsValueRef wscript;
  710. IfJsrtErrorFail(ChakraRTInterface::JsCreateObject(&wscript), false);
  711. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Echo", EchoCallback));
  712. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Quit", QuitCallback));
  713. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadScriptFile", LoadScriptFileCallback));
  714. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadScript", LoadScriptCallback));
  715. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadModule", LoadModuleCallback));
  716. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "SetTimeout", SetTimeoutCallback));
  717. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "ClearTimeout", ClearTimeoutCallback));
  718. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Attach", AttachCallback));
  719. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Detach", DetachCallback));
  720. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "DumpFunctionPosition", DumpFunctionPositionCallback));
  721. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "RequestAsyncBreak", RequestAsyncBreakCallback));
  722. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadBinaryFile", LoadBinaryFileCallback));
  723. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "LoadTextFile", LoadTextFileCallback));
  724. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Flag", FlagCallback));
  725. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "RegisterModuleSource", RegisterModuleSourceCallback));
  726. // ToDo Remove
  727. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Edit", EmptyCallback));
  728. // Platform
  729. JsValueRef platformObject;
  730. IfJsrtErrorFail(ChakraRTInterface::JsCreateObject(&platformObject), false);
  731. JsPropertyIdRef platformProperty;
  732. IfJsrtErrorFail(CreatePropertyIdFromString("Platform", &platformProperty), false);
  733. // Set CPU arch
  734. JsPropertyIdRef archProperty;
  735. IfJsrtErrorFail(CreatePropertyIdFromString("ARCH", &archProperty), false);
  736. JsValueRef archValue;
  737. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  738. CPU_ARCH_TEXT, strlen(CPU_ARCH_TEXT), &archValue), false);
  739. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, archProperty,
  740. archValue, true), false);
  741. // Set Build Type
  742. JsPropertyIdRef buildProperty;
  743. IfJsrtErrorFail(CreatePropertyIdFromString("BUILD_TYPE", &buildProperty), false);
  744. JsValueRef buildValue;
  745. #ifdef _DEBUG
  746. #define BUILD_TYPE_STRING_CH "Debug" // (O0)
  747. #elif defined(ENABLE_DEBUG_CONFIG_OPTIONS)
  748. #define BUILD_TYPE_STRING_CH "Test" // (O3 with debug config options)
  749. #else
  750. #define BUILD_TYPE_STRING_CH "Release" // (O3)
  751. #endif
  752. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  753. BUILD_TYPE_STRING_CH, strlen(BUILD_TYPE_STRING_CH), &buildValue), false);
  754. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, buildProperty,
  755. buildValue, true), false);
  756. #undef BUILD_TYPE_STRING_CH
  757. // Set Link Type [static / shared]
  758. JsPropertyIdRef linkProperty;
  759. IfJsrtErrorFail(CreatePropertyIdFromString("LINK_TYPE", &linkProperty), false);
  760. JsValueRef linkValue;
  761. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  762. LINK_TYPE, strlen(LINK_TYPE), &linkValue), false);
  763. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, linkProperty,
  764. linkValue, true), false);
  765. // Set Binary Location
  766. JsValueRef binaryPathValue;
  767. PlatformAgnostic::SystemInfo::GetBinaryLocation(CH_BINARY_LOCATION, sizeof(CH_BINARY_LOCATION));
  768. JsPropertyIdRef binaryPathProperty;
  769. IfJsrtErrorFail(CreatePropertyIdFromString("BINARY_PATH", &binaryPathProperty), false);
  770. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  771. CH_BINARY_LOCATION,
  772. strlen(CH_BINARY_LOCATION), &binaryPathValue), false);
  773. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(
  774. platformObject, binaryPathProperty, binaryPathValue, true), false);
  775. // Set destination OS
  776. JsPropertyIdRef osProperty;
  777. IfJsrtErrorFail(CreatePropertyIdFromString("OS", &osProperty), false);
  778. JsValueRef osValue;
  779. IfJsrtErrorFail(ChakraRTInterface::JsCreateString(
  780. DEST_PLATFORM_TEXT, strlen(DEST_PLATFORM_TEXT), &osValue), false);
  781. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(platformObject, osProperty,
  782. osValue, true), false);
  783. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(wscript, platformProperty,
  784. platformObject, true), false);
  785. JsValueRef argsObject;
  786. if (!CreateArgumentsObject(&argsObject))
  787. {
  788. return false;
  789. }
  790. JsPropertyIdRef argsName;
  791. IfJsrtErrorFail(CreatePropertyIdFromString("Arguments", &argsName), false);
  792. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(wscript, argsName, argsObject, true), false);
  793. JsPropertyIdRef wscriptName;
  794. IfJsrtErrorFail(CreatePropertyIdFromString("WScript", &wscriptName), false);
  795. JsValueRef global;
  796. IfJsrtErrorFail(ChakraRTInterface::JsGetGlobalObject(&global), false);
  797. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(global, wscriptName, wscript, true), false);
  798. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(global, "print", EchoCallback));
  799. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(global, "read", LoadTextFileCallback));
  800. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(global, "readbuffer", LoadBinaryFileCallback));
  801. JsValueRef console;
  802. IfJsrtErrorFail(ChakraRTInterface::JsCreateObject(&console), false);
  803. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(console, "log", EchoCallback));
  804. JsPropertyIdRef consoleName;
  805. IfJsrtErrorFail(CreatePropertyIdFromString("console", &consoleName), false);
  806. IfJsrtErrorFail(ChakraRTInterface::JsSetProperty(global, consoleName, console, true), false);
  807. IfJsrtErrorFail(InitializeModuleCallbacks(), false);
  808. // When the command-line argument `-Test262` is set,
  809. // WScript will have the extra support API below and $262 will be
  810. // added to global scope
  811. if (HostConfigFlags::flags.Test262)
  812. {
  813. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Broadcast", BroadcastCallback));
  814. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "ReceiveBroadcast", ReceiveBroadcastCallback));
  815. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Report", ReportCallback));
  816. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "GetReport", GetReportCallback));
  817. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Leaving", LeavingCallback));
  818. IfFalseGo(WScriptJsrt::InstallObjectsOnObject(wscript, "Sleep", SleepCallback));
  819. // $262
  820. const char Test262[] =
  821. #include "262.js"
  822. ;
  823. JsValueRef Test262ScriptRef;
  824. IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsCreateString(Test262, strlen(Test262), &Test262ScriptRef));
  825. JsValueRef fname;
  826. IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsCreateString("262", strlen("262"), &fname));
  827. IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsRun(Test262ScriptRef, WScriptJsrt::GetNextSourceContext(), fname, JsParseScriptAttributeNone, nullptr));
  828. }
  829. Error:
  830. return hr == S_OK;
  831. }
  832. JsErrorCode WScriptJsrt::InitializeModuleCallbacks()
  833. {
  834. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  835. JsErrorCode errorCode = ChakraRTInterface::JsInitializeModuleRecord(nullptr, nullptr, &moduleRecord);
  836. if (errorCode == JsNoError)
  837. {
  838. errorCode = InitializeModuleInfo(nullptr, moduleRecord);
  839. }
  840. return errorCode;
  841. }
  842. bool WScriptJsrt::Uninitialize()
  843. {
  844. // moduleRecordMap is a global std::map, its destructor may access overridden
  845. // "operator delete" / global HeapAllocator::Instance. Clear it manually here
  846. // to avoid worrying about global destructor order.
  847. moduleRecordMap.clear();
  848. moduleDirMap.clear();
  849. scriptDirMap.clear();
  850. auto& threadData = GetRuntimeThreadLocalData().threadData;
  851. if (threadData && !threadData->children.empty())
  852. {
  853. LONG count = (LONG)threadData->children.size();
  854. std::vector<HANDLE> childrenHandles;
  855. //Clang does not support "for each" yet
  856. for(auto i = threadData->children.begin(); i!= threadData->children.end(); i++)
  857. {
  858. auto child = *i;
  859. childrenHandles.push_back(child->hThread);
  860. SetEvent(child->hevntShutdown);
  861. }
  862. DWORD waitRet = WaitForMultipleObjects(count, &childrenHandles[0], TRUE, INFINITE);
  863. Assert(waitRet == WAIT_OBJECT_0);
  864. for (auto i = threadData->children.begin(); i != threadData->children.end(); i++)
  865. {
  866. delete *i;
  867. }
  868. threadData->children.clear();
  869. }
  870. return true;
  871. }
  872. #if ENABLE_TTD
  873. void CALLBACK WScriptJsrt::JsContextBeforeCollectCallback(JsRef contextRef, void *data)
  874. {
  875. ChakraRTInterface::JsTTDNotifyContextDestroy(contextRef);
  876. }
  877. #endif
  878. FileNode * SourceMap::root = nullptr;
  879. JsValueRef __stdcall WScriptJsrt::RegisterModuleSourceCallback(JsValueRef callee, bool isConstructCall,
  880. JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  881. {
  882. HRESULT hr = E_FAIL;
  883. JsValueRef returnValue = JS_INVALID_REFERENCE;
  884. JsErrorCode errorCode = JsNoError;
  885. if (argumentCount < 3)
  886. {
  887. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  888. }
  889. else
  890. {
  891. AutoString fileName;
  892. AutoString data;
  893. IfJsrtErrorSetGo(fileName.Initialize(arguments[1]));
  894. IfJsrtErrorSetGo(data.Initialize(arguments[2]));
  895. SourceMap::Add(fileName, data);
  896. }
  897. Error:
  898. return returnValue;
  899. }
  900. JsValueRef __stdcall WScriptJsrt::LoadTextFileCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  901. {
  902. HRESULT hr = E_FAIL;
  903. JsValueRef returnValue = JS_INVALID_REFERENCE;
  904. JsErrorCode errorCode = JsNoError;
  905. const char* fileContent = nullptr;
  906. if (argumentCount < 2)
  907. {
  908. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  909. }
  910. else
  911. {
  912. AutoString fileName;
  913. IfJsrtErrorSetGo(fileName.Initialize(arguments[1]));
  914. if (errorCode == JsNoError)
  915. {
  916. UINT lengthBytes = 0;
  917. hr = Helpers::LoadScriptFromFile(*fileName, fileContent, &lengthBytes);
  918. if (FAILED(hr))
  919. {
  920. // check if have it registered
  921. fprintf(stderr, "Couldn't load file '%s'\n", fileName.GetString());
  922. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  923. return returnValue;
  924. }
  925. IfJsrtErrorSetGo(ChakraRTInterface::JsCreateString(
  926. fileContent, lengthBytes, &returnValue));
  927. }
  928. }
  929. Error:
  930. if (fileContent)
  931. {
  932. free((void*)fileContent);
  933. }
  934. return returnValue;
  935. }
  936. JsValueRef __stdcall WScriptJsrt::LoadBinaryFileCallback(JsValueRef callee,
  937. bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  938. {
  939. HRESULT hr = E_FAIL;
  940. JsValueRef returnValue = JS_INVALID_REFERENCE;
  941. JsErrorCode errorCode = JsNoError;
  942. bool isHeapAlloc = true;
  943. if (argumentCount < 2)
  944. {
  945. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  946. }
  947. else
  948. {
  949. const char *fileContent;
  950. AutoString fileName;
  951. IfJsrtErrorSetGo(fileName.Initialize(arguments[1]));
  952. if (errorCode == JsNoError)
  953. {
  954. UINT lengthBytes = 0;
  955. hr = Helpers::LoadBinaryFile(*fileName, fileContent, lengthBytes);
  956. if (FAILED(hr))
  957. {
  958. // check if have it registered
  959. fprintf(stderr, "Couldn't load file '%s'\n", fileName.GetString());
  960. IfJsrtErrorSetGoLabel(ChakraRTInterface::JsGetUndefinedValue(&returnValue), Error);
  961. return returnValue;
  962. }
  963. JsValueRef arrayBuffer;
  964. IfJsrtErrorSetGoLabel(ChakraRTInterface::JsCreateArrayBuffer(lengthBytes, &arrayBuffer), ErrorStillFree);
  965. BYTE* buffer;
  966. unsigned int bufferLength;
  967. IfJsrtErrorSetGoLabel(ChakraRTInterface::JsGetArrayBufferStorage(arrayBuffer, &buffer, &bufferLength), ErrorStillFree);
  968. if (bufferLength < lengthBytes)
  969. {
  970. fwprintf(stderr, _u("Array buffer size is insufficient to store the binary file.\n"));
  971. }
  972. else
  973. {
  974. if (memcpy_s(buffer, bufferLength, (BYTE*)fileContent, lengthBytes) == 0)
  975. {
  976. returnValue = arrayBuffer;
  977. }
  978. }
  979. ErrorStillFree:
  980. if (isHeapAlloc)
  981. {
  982. HeapFree(GetProcessHeap(), 0, (void*)fileContent);
  983. }
  984. }
  985. }
  986. Error:
  987. return returnValue;
  988. }
  989. JsValueRef __stdcall WScriptJsrt::FlagCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  990. {
  991. HRESULT hr = E_FAIL;
  992. JsValueRef returnValue = JS_INVALID_REFERENCE;
  993. JsErrorCode errorCode = JsNoError;
  994. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  995. #if ENABLE_DEBUG_CONFIG_OPTIONS
  996. if (argumentCount > 1)
  997. {
  998. AutoString cmd;
  999. IfJsrtErrorSetGo(cmd.Initialize(arguments[1]));
  1000. char16* argv[] = { nullptr, cmd.GetWideString() };
  1001. ChakraRTInterface::SetConfigFlags(2, argv, nullptr);
  1002. }
  1003. #endif
  1004. Error:
  1005. return returnValue;
  1006. }
  1007. JsValueRef __stdcall WScriptJsrt::BroadcastCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  1008. {
  1009. HRESULT hr = E_FAIL;
  1010. JsValueRef returnValue = JS_INVALID_REFERENCE;
  1011. JsErrorCode errorCode = JsNoError;
  1012. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  1013. if (argumentCount > 1)
  1014. {
  1015. auto& threadData = GetRuntimeThreadLocalData().threadData;
  1016. if (threadData)
  1017. {
  1018. ChakraRTInterface::JsGetSharedArrayBufferContent(arguments[1], &threadData->sharedContent);
  1019. LONG count = (LONG)threadData->children.size();
  1020. threadData->hSemaphore = CreateSemaphore(NULL, 0, count, NULL);
  1021. if (threadData->hSemaphore)
  1022. {
  1023. //Clang does not support "for each" yet
  1024. for (auto i = threadData->children.begin(); i != threadData->children.end(); i++)
  1025. {
  1026. auto child = *i;
  1027. SetEvent(child->hevntReceivedBroadcast);
  1028. }
  1029. WaitForSingleObject(threadData->hSemaphore, INFINITE);
  1030. CloseHandle(threadData->hSemaphore);
  1031. threadData->hSemaphore = INVALID_HANDLE_VALUE;
  1032. }
  1033. else
  1034. {
  1035. fwprintf(stderr, _u("Couldn't create semaphore.\n"));
  1036. fflush(stderr);
  1037. }
  1038. ChakraRTInterface::JsReleaseSharedArrayBufferContentHandle(threadData->sharedContent);
  1039. }
  1040. }
  1041. Error:
  1042. return returnValue;
  1043. }
  1044. JsValueRef __stdcall WScriptJsrt::ReceiveBroadcastCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  1045. {
  1046. HRESULT hr = E_FAIL;
  1047. JsValueRef returnValue = JS_INVALID_REFERENCE;
  1048. JsErrorCode errorCode = JsNoError;
  1049. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  1050. if (argumentCount > 1)
  1051. {
  1052. auto& threadData = GetRuntimeThreadLocalData().threadData;
  1053. if (threadData)
  1054. {
  1055. if (threadData->receiveBroadcastCallbackFunc)
  1056. {
  1057. ChakraRTInterface::JsRelease(threadData->receiveBroadcastCallbackFunc, nullptr);
  1058. }
  1059. threadData->receiveBroadcastCallbackFunc = arguments[1];
  1060. ChakraRTInterface::JsAddRef(threadData->receiveBroadcastCallbackFunc, nullptr);
  1061. }
  1062. }
  1063. Error:
  1064. return returnValue;
  1065. }
  1066. JsValueRef __stdcall WScriptJsrt::ReportCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  1067. {
  1068. HRESULT hr = E_FAIL;
  1069. JsValueRef returnValue = JS_INVALID_REFERENCE;
  1070. JsErrorCode errorCode = JsNoError;
  1071. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  1072. if (argumentCount > 1)
  1073. {
  1074. JsValueRef stringRef;
  1075. ChakraRTInterface::JsConvertValueToString(arguments[1], &stringRef);
  1076. AutoString autoStr(stringRef);
  1077. if (autoStr.GetError() == JsNoError)
  1078. {
  1079. std::string str(autoStr.GetString());
  1080. auto& threadData = GetRuntimeThreadLocalData().threadData;
  1081. if (threadData && threadData->parent)
  1082. {
  1083. EnterCriticalSection(&threadData->parent->csReportQ);
  1084. threadData->parent->reportQ.push_back(str);
  1085. LeaveCriticalSection(&threadData->parent->csReportQ);
  1086. }
  1087. }
  1088. }
  1089. Error:
  1090. return returnValue;
  1091. }
  1092. JsValueRef __stdcall WScriptJsrt::GetReportCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  1093. {
  1094. HRESULT hr = E_FAIL;
  1095. JsValueRef returnValue = JS_INVALID_REFERENCE;
  1096. JsErrorCode errorCode = JsNoError;
  1097. IfJsrtErrorSetGo(ChakraRTInterface::JsGetNullValue(&returnValue));
  1098. if (argumentCount > 0)
  1099. {
  1100. auto& threadData = GetRuntimeThreadLocalData().threadData;
  1101. if (threadData)
  1102. {
  1103. EnterCriticalSection(&threadData->csReportQ);
  1104. if (threadData->reportQ.size() > 0)
  1105. {
  1106. auto str = threadData->reportQ.front();
  1107. threadData->reportQ.pop_front();
  1108. ChakraRTInterface::JsCreateString(str.c_str(), str.size(), &returnValue);
  1109. }
  1110. LeaveCriticalSection(&threadData->csReportQ);
  1111. }
  1112. }
  1113. Error:
  1114. return returnValue;
  1115. }
  1116. JsValueRef __stdcall WScriptJsrt::LeavingCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  1117. {
  1118. HRESULT hr = E_FAIL;
  1119. JsValueRef returnValue = JS_INVALID_REFERENCE;
  1120. JsErrorCode errorCode = JsNoError;
  1121. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  1122. if (argumentCount > 0)
  1123. {
  1124. auto& threadData = GetRuntimeThreadLocalData().threadData;
  1125. if (threadData)
  1126. {
  1127. threadData->leaving = true;
  1128. }
  1129. }
  1130. Error:
  1131. return returnValue;
  1132. }
  1133. JsValueRef __stdcall WScriptJsrt::SleepCallback(JsValueRef callee, bool isConstructCall, JsValueRef *arguments, unsigned short argumentCount, void *callbackState)
  1134. {
  1135. HRESULT hr = E_FAIL;
  1136. JsValueRef returnValue = JS_INVALID_REFERENCE;
  1137. JsErrorCode errorCode = JsNoError;
  1138. IfJsrtErrorSetGo(ChakraRTInterface::JsGetUndefinedValue(&returnValue));
  1139. if (argumentCount > 1)
  1140. {
  1141. double timeout = 0.0;
  1142. ChakraRTInterface::JsNumberToDouble(arguments[1], &timeout);
  1143. Sleep((DWORD)timeout);
  1144. }
  1145. Error:
  1146. return returnValue;
  1147. }
  1148. bool WScriptJsrt::PrintException(LPCSTR fileName, JsErrorCode jsErrorCode)
  1149. {
  1150. LPCWSTR errorTypeString = ConvertErrorCodeToMessage(jsErrorCode);
  1151. JsValueRef exception;
  1152. ChakraRTInterface::JsGetAndClearException(&exception);
  1153. if (HostConfigFlags::flags.MuteHostErrorMsgIsEnabled)
  1154. {
  1155. return false;
  1156. }
  1157. if (exception != nullptr)
  1158. {
  1159. if (jsErrorCode == JsErrorCode::JsErrorScriptCompile || jsErrorCode == JsErrorCode::JsErrorScriptException)
  1160. {
  1161. AutoString errorMessage;
  1162. IfJsrtErrorFail(errorMessage.Initialize(exception), false);
  1163. if (jsErrorCode == JsErrorCode::JsErrorScriptCompile)
  1164. {
  1165. JsPropertyIdRef linePropertyId = JS_INVALID_REFERENCE;
  1166. JsValueRef lineProperty = JS_INVALID_REFERENCE;
  1167. JsPropertyIdRef columnPropertyId = JS_INVALID_REFERENCE;
  1168. JsValueRef columnProperty = JS_INVALID_REFERENCE;
  1169. int line;
  1170. int column;
  1171. IfJsrtErrorFail(CreatePropertyIdFromString("line", &linePropertyId), false);
  1172. IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, linePropertyId, &lineProperty), false);
  1173. IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(lineProperty, &line), false);
  1174. IfJsrtErrorFail(CreatePropertyIdFromString("column", &columnPropertyId), false);
  1175. IfJsrtErrorFail(ChakraRTInterface::JsGetProperty(exception, columnPropertyId, &columnProperty), false);
  1176. IfJsrtErrorFail(ChakraRTInterface::JsNumberToInt(columnProperty, &column), false);
  1177. CHAR shortFileName[_MAX_PATH];
  1178. CHAR ext[_MAX_EXT];
  1179. _splitpath_s(fileName, nullptr, 0, nullptr, 0, shortFileName, _countof(shortFileName), ext, _countof(ext));
  1180. fwprintf(stderr, _u("%ls\n\tat code (%S%S:%d:%d)\n"),
  1181. errorMessage.GetWideString(), shortFileName, ext, (int)line + 1,
  1182. (int)column + 1);
  1183. }
  1184. else
  1185. {
  1186. JsValueType propertyType = JsUndefined;
  1187. JsPropertyIdRef stackPropertyId = JS_INVALID_REFERENCE;
  1188. JsValueRef stackProperty = JS_INVALID_REFERENCE;
  1189. AutoString errorStack;
  1190. JsErrorCode errorCode = CreatePropertyIdFromString("stack", &stackPropertyId);
  1191. if (errorCode == JsErrorCode::JsNoError)
  1192. {
  1193. errorCode = ChakraRTInterface::JsGetProperty(exception, stackPropertyId, &stackProperty);
  1194. if (errorCode == JsErrorCode::JsNoError)
  1195. {
  1196. errorCode = ChakraRTInterface::JsGetValueType(stackProperty, &propertyType);
  1197. }
  1198. }
  1199. if (errorCode != JsErrorCode::JsNoError || propertyType == JsUndefined)
  1200. {
  1201. const char *fName = fileName != nullptr ? fileName : "(unknown)";
  1202. CHAR shortFileName[_MAX_PATH];
  1203. CHAR ext[_MAX_EXT];
  1204. _splitpath_s(fName, nullptr, 0, nullptr, 0, shortFileName, _countof(shortFileName), ext, _countof(ext));
  1205. // do not mix char/wchar. print them separately
  1206. fprintf(stderr, "thrown at %s%s:\n^\n", shortFileName, ext);
  1207. fwprintf(stderr, _u("%ls\n"), errorMessage.GetWideString());
  1208. }
  1209. else
  1210. {
  1211. IfJsrtErrorFail(errorStack.Initialize(stackProperty), false);
  1212. fwprintf(stderr, _u("%ls\n"), errorStack.GetWideString());
  1213. }
  1214. }
  1215. }
  1216. else
  1217. {
  1218. fwprintf(stderr, _u("Error : %ls\n"), errorTypeString);
  1219. }
  1220. return true;
  1221. }
  1222. else
  1223. {
  1224. fwprintf(stderr, _u("Error : %ls\n"), errorTypeString);
  1225. }
  1226. return false;
  1227. }
  1228. void WScriptJsrt::AddMessageQueue(MessageQueue *_messageQueue)
  1229. {
  1230. Assert(messageQueue == nullptr);
  1231. messageQueue = _messageQueue;
  1232. }
  1233. WScriptJsrt::CallbackMessage::CallbackMessage(unsigned int time, JsValueRef function) : MessageBase(time), m_function(function)
  1234. {
  1235. JsErrorCode error = ChakraRTInterface::JsAddRef(m_function, nullptr);
  1236. if (error != JsNoError)
  1237. {
  1238. // Simply report a fatal error and exit because continuing from this point would result in inconsistent state
  1239. // and FailFast telemetry would not be useful.
  1240. wprintf(_u("FATAL ERROR: ChakraRTInterface::JsAddRef failed in WScriptJsrt::CallbackMessage::`ctor`. error=0x%x\n"), error);
  1241. exit(1);
  1242. }
  1243. }
  1244. WScriptJsrt::CallbackMessage::~CallbackMessage()
  1245. {
  1246. bool hasException = false;
  1247. ChakraRTInterface::JsHasException(&hasException);
  1248. if (hasException)
  1249. {
  1250. WScriptJsrt::PrintException("", JsErrorScriptException);
  1251. }
  1252. JsErrorCode errorCode = ChakraRTInterface::JsRelease(m_function, nullptr);
  1253. Assert(errorCode == JsNoError);
  1254. m_function = JS_INVALID_REFERENCE;
  1255. }
  1256. HRESULT WScriptJsrt::CallbackMessage::Call(LPCSTR fileName)
  1257. {
  1258. return CallFunction(fileName);
  1259. }
  1260. HRESULT WScriptJsrt::CallbackMessage::CallFunction(LPCSTR fileName)
  1261. {
  1262. HRESULT hr = S_OK;
  1263. JsValueRef global;
  1264. JsValueRef result;
  1265. JsValueRef stringValue;
  1266. JsValueType type;
  1267. JsErrorCode errorCode = JsNoError;
  1268. IfJsrtErrorHR(ChakraRTInterface::JsGetGlobalObject(&global));
  1269. IfJsrtErrorHR(ChakraRTInterface::JsGetValueType(m_function, &type));
  1270. if (type == JsString)
  1271. {
  1272. IfJsrtErrorHR(ChakraRTInterface::JsConvertValueToString(m_function, &stringValue));
  1273. JsValueRef fname;
  1274. ChakraRTInterface::JsCreateString("", strlen(""), &fname);
  1275. // Run the code
  1276. errorCode = ChakraRTInterface::JsRun(stringValue, JS_SOURCE_CONTEXT_NONE,
  1277. fname, JsParseScriptAttributeArrayBufferIsUtf16Encoded,
  1278. nullptr /*no result needed*/);
  1279. }
  1280. else
  1281. {
  1282. errorCode = ChakraRTInterface::JsCallFunction(m_function, &global, 1, &result);
  1283. }
  1284. if (errorCode != JsNoError)
  1285. {
  1286. hr = E_FAIL;
  1287. PrintException(fileName, errorCode);
  1288. }
  1289. Error:
  1290. return hr;
  1291. }
  1292. WScriptJsrt::ModuleMessage::ModuleMessage(JsModuleRecord module, JsValueRef specifier)
  1293. : MessageBase(0), moduleRecord(module), specifier(specifier)
  1294. {
  1295. ChakraRTInterface::JsAddRef(module, nullptr);
  1296. if (specifier != nullptr)
  1297. {
  1298. // nullptr specifier means a Promise to execute; non-nullptr means a "fetch" operation.
  1299. ChakraRTInterface::JsAddRef(specifier, nullptr);
  1300. }
  1301. }
  1302. WScriptJsrt::ModuleMessage::~ModuleMessage()
  1303. {
  1304. ChakraRTInterface::JsRelease(moduleRecord, nullptr);
  1305. if (specifier != nullptr)
  1306. {
  1307. ChakraRTInterface::JsRelease(specifier, nullptr);
  1308. }
  1309. }
  1310. HRESULT WScriptJsrt::ModuleMessage::Call(LPCSTR fileName)
  1311. {
  1312. JsErrorCode errorCode;
  1313. JsValueRef result = JS_INVALID_REFERENCE;
  1314. HRESULT hr;
  1315. if (specifier == nullptr)
  1316. {
  1317. errorCode = ChakraRTInterface::JsModuleEvaluation(moduleRecord, &result);
  1318. if (errorCode != JsNoError)
  1319. {
  1320. PrintException(fileName, errorCode);
  1321. }
  1322. }
  1323. else
  1324. {
  1325. LPCSTR fileContent = nullptr;
  1326. AutoString specifierStr(specifier);
  1327. errorCode = specifierStr.GetError();
  1328. if (errorCode == JsNoError)
  1329. {
  1330. hr = Helpers::LoadScriptFromFile(*specifierStr, fileContent);
  1331. if (FAILED(hr))
  1332. {
  1333. // check if have it registered
  1334. if (!HostConfigFlags::flags.MuteHostErrorMsgIsEnabled)
  1335. {
  1336. fprintf(stderr, "Couldn't load file '%s'\n", specifierStr.GetString());
  1337. }
  1338. LoadScript(nullptr, *specifierStr, nullptr, "module", true, WScriptJsrt::FinalizeFree, false);
  1339. goto Error;
  1340. }
  1341. LoadScript(nullptr, *specifierStr, fileContent, "module", true, WScriptJsrt::FinalizeFree, true);
  1342. }
  1343. }
  1344. Error:
  1345. return errorCode;
  1346. }
  1347. JsErrorCode WScriptJsrt::FetchImportedModuleHelper(JsModuleRecord referencingModule,
  1348. JsValueRef specifier, __out JsModuleRecord* dependentModuleRecord, LPCSTR refdir)
  1349. {
  1350. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1351. AutoString specifierStr;
  1352. *dependentModuleRecord = nullptr;
  1353. if (specifierStr.Initialize(specifier) != JsNoError)
  1354. {
  1355. return specifierStr.GetError();
  1356. }
  1357. char fullPath[_MAX_PATH];
  1358. std::string specifierFullPath = refdir ? refdir : "";
  1359. specifierFullPath += *specifierStr;
  1360. if (_fullpath(fullPath, specifierFullPath.c_str(), _MAX_PATH) == nullptr)
  1361. {
  1362. return JsErrorInvalidArgument;
  1363. }
  1364. auto moduleEntry = moduleRecordMap.find(std::string(fullPath));
  1365. if (moduleEntry != moduleRecordMap.end())
  1366. {
  1367. *dependentModuleRecord = moduleEntry->second;
  1368. return JsNoError;
  1369. }
  1370. JsErrorCode errorCode = ChakraRTInterface::JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1371. if (errorCode == JsNoError)
  1372. {
  1373. GetDir(fullPath, &moduleDirMap[moduleRecord]);
  1374. InitializeModuleInfo(specifier, moduleRecord);
  1375. moduleRecordMap[std::string(fullPath)] = moduleRecord;
  1376. ModuleMessage* moduleMessage =
  1377. WScriptJsrt::ModuleMessage::Create(referencingModule, specifier);
  1378. if (moduleMessage == nullptr)
  1379. {
  1380. return JsErrorOutOfMemory;
  1381. }
  1382. WScriptJsrt::PushMessage(moduleMessage);
  1383. *dependentModuleRecord = moduleRecord;
  1384. }
  1385. return errorCode;
  1386. }
  1387. // Callback from chakracore to fetch dependent module. In the test harness,
  1388. // we are not doing any translation, just treat the specifier as fileName.
  1389. // While this call will come back directly from ParseModuleSource, the additional
  1390. // task are treated as Promise that will be executed later.
  1391. JsErrorCode WScriptJsrt::FetchImportedModule(_In_ JsModuleRecord referencingModule,
  1392. _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1393. {
  1394. auto moduleDirEntry = moduleDirMap.find(referencingModule);
  1395. if (moduleDirEntry != moduleDirMap.end())
  1396. {
  1397. std::string dir = moduleDirEntry->second;
  1398. return FetchImportedModuleHelper(referencingModule, specifier, dependentModuleRecord, dir.c_str());
  1399. }
  1400. return FetchImportedModuleHelper(referencingModule, specifier, dependentModuleRecord);
  1401. }
  1402. // Callback from chakracore to fetch module dynamically during runtime. In the test harness,
  1403. // we are not doing any translation, just treat the specifier as fileName.
  1404. // While this call will come back directly from runtime script or module code, the additional
  1405. // task can be scheduled asynchronously that executed later.
  1406. JsErrorCode WScriptJsrt::FetchImportedModuleFromScript(_In_ JsSourceContext dwReferencingSourceContext,
  1407. _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1408. {
  1409. // ch.exe assumes all imported source files are located at .
  1410. auto scriptDirEntry = scriptDirMap.find(dwReferencingSourceContext);
  1411. if (scriptDirEntry != scriptDirMap.end())
  1412. {
  1413. std::string dir = scriptDirEntry->second;
  1414. return FetchImportedModuleHelper(nullptr, specifier, dependentModuleRecord, dir.c_str());
  1415. }
  1416. return FetchImportedModuleHelper(nullptr, specifier, dependentModuleRecord);
  1417. }
  1418. // Callback from chakraCore when the module resolution is finished, either successfuly or unsuccessfully.
  1419. JsErrorCode WScriptJsrt::NotifyModuleReadyCallback(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  1420. {
  1421. if (exceptionVar != nullptr)
  1422. {
  1423. ChakraRTInterface::JsSetException(exceptionVar);
  1424. JsValueRef specifier = JS_INVALID_REFERENCE;
  1425. ChakraRTInterface::JsGetModuleHostInfo(referencingModule, JsModuleHostInfo_HostDefined, &specifier);
  1426. AutoString fileName;
  1427. if (specifier != JS_INVALID_REFERENCE)
  1428. {
  1429. fileName.Initialize(specifier);
  1430. }
  1431. if (HostConfigFlags::flags.TraceHostCallbackIsEnabled)
  1432. {
  1433. wprintf(_u("NotifyModuleReadyCallback(exception) %S\n"), fileName.GetString());
  1434. }
  1435. // No need to print - just consume the exception
  1436. JsValueRef exception;
  1437. ChakraRTInterface::JsGetAndClearException(&exception);
  1438. exception; // unused
  1439. }
  1440. else
  1441. {
  1442. WScriptJsrt::ModuleMessage* moduleMessage =
  1443. WScriptJsrt::ModuleMessage::Create(referencingModule, nullptr);
  1444. if (moduleMessage == nullptr)
  1445. {
  1446. return JsErrorOutOfMemory;
  1447. }
  1448. WScriptJsrt::PushMessage(moduleMessage);
  1449. }
  1450. return JsNoError;
  1451. }
  1452. void WScriptJsrt::PromiseContinuationCallback(JsValueRef task, void *callbackState)
  1453. {
  1454. Assert(task != JS_INVALID_REFERENCE);
  1455. Assert(callbackState != JS_INVALID_REFERENCE);
  1456. MessageQueue * messageQueue = (MessageQueue *)callbackState;
  1457. WScriptJsrt::CallbackMessage *msg = new WScriptJsrt::CallbackMessage(0, task);
  1458. messageQueue->InsertSorted(msg);
  1459. }
  1460. void WScriptJsrt::PromiseRejectionTrackerCallback(JsValueRef promise, JsValueRef reason, bool handled, void *callbackState)
  1461. {
  1462. Assert(promise != JS_INVALID_REFERENCE);
  1463. Assert(reason != JS_INVALID_REFERENCE);
  1464. JsValueRef strValue;
  1465. JsErrorCode error = ChakraRTInterface::JsConvertValueToString(reason, &strValue);
  1466. if (!handled)
  1467. {
  1468. wprintf(_u("Uncaught promise rejection\n"));
  1469. }
  1470. else
  1471. {
  1472. wprintf(_u("Promise rejection handled\n"));
  1473. }
  1474. if (error == JsNoError)
  1475. {
  1476. AutoString str(strValue);
  1477. if (str.GetError() == JsNoError)
  1478. {
  1479. wprintf(_u("%ls\n"), str.GetWideString());
  1480. }
  1481. }
  1482. fflush(stdout);
  1483. }