GlobalObject.cpp 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLibraryPch.h"
  6. #ifndef USING_PAL_STDLIB
  7. #include <strsafe.h>
  8. #endif
  9. #include "ByteCode/ByteCodeApi.h"
  10. #include "Exceptions/EvalDisabledException.h"
  11. #include "Types/PropertyIndexRanges.h"
  12. #include "Types/SimpleDictionaryPropertyDescriptor.h"
  13. #include "Types/SimpleDictionaryTypeHandler.h"
  14. using namespace Js;
  15. GlobalObject * GlobalObject::New(ScriptContext * scriptContext)
  16. {
  17. SimpleDictionaryTypeHandler* globalTypeHandler = SimpleDictionaryTypeHandler::New(
  18. scriptContext->GetRecycler(), InitialCapacity, InlineSlotCapacity, sizeof(Js::GlobalObject));
  19. DynamicType* globalType = DynamicType::New(
  20. scriptContext, TypeIds_GlobalObject, nullptr, nullptr, globalTypeHandler);
  21. GlobalObject* globalObject = RecyclerNewPlus(scriptContext->GetRecycler(),
  22. sizeof(Var) * InlineSlotCapacity, GlobalObject, globalType, scriptContext);
  23. #if ENABLE_FIXED_FIELDS
  24. globalTypeHandler->SetSingletonInstanceIfNeeded(scriptContext->GetRecycler()->CreateWeakReferenceHandle<DynamicObject>(globalObject));
  25. #endif
  26. return globalObject;
  27. }
  28. GlobalObject::GlobalObject(DynamicType * type, ScriptContext* scriptContext) :
  29. RootObjectBase(type, scriptContext),
  30. directHostObject(nullptr),
  31. secureDirectHostObject(nullptr),
  32. EvalHelper(&GlobalObject::DefaultEvalHelper),
  33. reservedProperties(nullptr)
  34. {
  35. }
  36. void GlobalObject::Initialize(ScriptContext * scriptContext)
  37. {
  38. Assert(type->javascriptLibrary == nullptr);
  39. Recycler * recycler = scriptContext->GetRecycler();
  40. JavascriptLibrary* localLibrary = RecyclerNewFinalized(recycler, JavascriptLibrary, this, recycler);
  41. scriptContext->SetLibrary(localLibrary);
  42. type->javascriptLibrary = localLibrary;
  43. scriptContext->InitializeCache();
  44. localLibrary->Initialize(scriptContext, this);
  45. library = localLibrary;
  46. }
  47. HRESULT GlobalObject::SetDirectHostObject(RecyclableObject* hostObject, RecyclableObject* secureDirectHostObject)
  48. {
  49. HRESULT hr = S_OK;
  50. this->directHostObject = hostObject;
  51. this->secureDirectHostObject = secureDirectHostObject;
  52. BEGIN_TRANSLATE_OOM_TO_HRESULT_NESTED
  53. {
  54. // In fastDOM scenario, we should use the host object to lookup the prototype.
  55. this->SetPrototype(library->GetNull());
  56. // Host can call to set the direct host object after the GlobalObject has been initialized but
  57. // before user script has run. (This happens even before the previous call to SetPrototype)
  58. // If that happens, we'll need to update the 'globalThis' property to point to the secure
  59. // host object so that we don't hand a reference to the bare GlobalObject out to user script.
  60. if (this->GetScriptContext()->GetConfig()->IsESGlobalThisEnabled())
  61. {
  62. this->SetProperty(PropertyIds::globalThis, this->ToThis(), PropertyOperation_None, nullptr);
  63. }
  64. }
  65. END_TRANSLATE_OOM_TO_HRESULT(hr)
  66. return hr;
  67. }
  68. RecyclableObject* GlobalObject::GetDirectHostObject()
  69. {
  70. return this->directHostObject;
  71. }
  72. RecyclableObject* GlobalObject::GetSecureDirectHostObject()
  73. {
  74. return this->secureDirectHostObject;
  75. }
  76. // Converts the global object into the object that should be used as the 'this' parameter.
  77. // In a non-hosted environment, the global object (this) is returned.
  78. // In a hosted environment, the host object is returned.
  79. Var GlobalObject::ToThis()
  80. {
  81. Var ret;
  82. // In fast DOM, we need to give user the secure version of host object
  83. if (secureDirectHostObject)
  84. {
  85. ret = secureDirectHostObject;
  86. }
  87. else if (hostObject)
  88. {
  89. // If the global object has the host object, use that as "this"
  90. ret = hostObject->GetHostDispatchVar();
  91. Assert(ret);
  92. }
  93. else
  94. {
  95. // Otherwise just use the global object
  96. ret = this;
  97. }
  98. return ret;
  99. }
  100. BOOL GlobalObject::ReserveGlobalProperty(PropertyId propertyId)
  101. {
  102. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, nullptr /*info*/)))
  103. {
  104. return false;
  105. }
  106. if (reservedProperties == nullptr)
  107. {
  108. Recycler* recycler = this->GetScriptContext()->GetRecycler();
  109. reservedProperties = RecyclerNew(recycler, ReservedPropertiesHashSet, recycler, 3);
  110. }
  111. reservedProperties->AddNew(propertyId);
  112. return true;
  113. }
  114. BOOL GlobalObject::IsReservedGlobalProperty(PropertyId propertyId)
  115. {
  116. return reservedProperties != nullptr && reservedProperties->Contains(propertyId);
  117. }
  118. #ifdef IR_VIEWER
  119. Var GlobalObject::EntryParseIR(RecyclableObject *function, CallInfo callInfo, ...)
  120. {
  121. //
  122. // retrieve arguments
  123. //
  124. RUNTIME_ARGUMENTS(args, callInfo);
  125. Js::Var codeVar = args[1]; // args[0] is (this)
  126. Js::JavascriptString *codeStringVar = nullptr;
  127. const char16 *source = nullptr;
  128. size_t sourceLength = 0;
  129. if (Js::VarIs<Js::JavascriptString>(codeVar))
  130. {
  131. codeStringVar = (Js::JavascriptString *)codeVar;
  132. source = codeStringVar->GetString();
  133. sourceLength = codeStringVar->GetLength();
  134. }
  135. else
  136. {
  137. AssertMsg(false, "The input to parseIR was not a string.");
  138. }
  139. //
  140. // collect arguments for eval
  141. //
  142. /* @see NativeCodeGenerator::CodeGen */
  143. ScriptContext *scriptContext = function->GetScriptContext();
  144. // used arbitrary defaults for these, but it seems to work
  145. ModuleID moduleID = 0;
  146. uint32 grfscr = 0;
  147. LPCOLESTR pszTitle = _u("");
  148. BOOL registerDocument = false;
  149. BOOL strictMode = true;
  150. return IRDumpEvalHelper(scriptContext, source, sourceLength, moduleID, grfscr,
  151. pszTitle, registerDocument, FALSE, strictMode);
  152. }
  153. // TODO remove when refactor
  154. Js::PropertyId GlobalObject::CreateProperty(Js::ScriptContext *scriptContext, const char16 *propertyName)
  155. {
  156. Js::PropertyRecord const *propertyRecord;
  157. scriptContext->GetOrAddPropertyRecord(propertyName, (int) wcslen(propertyName), &propertyRecord);
  158. Js::PropertyId propertyId = propertyRecord->GetPropertyId();
  159. return propertyId;
  160. }
  161. // TODO remove when refactor
  162. void GlobalObject::SetProperty(Js::DynamicObject *obj, const char16 *propertyName, Js::Var value)
  163. {
  164. const size_t len = wcslen(propertyName);
  165. if (!(len > 0))
  166. {
  167. return;
  168. }
  169. Js::PropertyId id = CreateProperty(obj->GetScriptContext(), propertyName);
  170. SetProperty(obj, id, value);
  171. }
  172. // TODO remove when refactor
  173. void GlobalObject::SetProperty(Js::DynamicObject *obj, Js::PropertyId id, Js::Var value)
  174. {
  175. if (value == NULL)
  176. {
  177. return;
  178. }
  179. Js::JavascriptOperators::SetProperty(obj, obj, id, value, obj->GetScriptContext());
  180. }
  181. Var GlobalObject::FunctionInfoObjectBuilder(ScriptContext *scriptContext, const char16 *file,
  182. const char16 *function, ULONG lineNum, ULONG colNum,
  183. uint functionId, Js::Utf8SourceInfo *utf8SrcInfo, Js::Var source)
  184. {
  185. Js::DynamicObject *fnInfoObj = scriptContext->GetLibrary()->CreateObject();
  186. // create javascript objects for properties
  187. Js::Var filenameString = Js::JavascriptString::NewCopyBuffer(file, wcslen(file), scriptContext);
  188. Js::Var funcnameString = Js::JavascriptString::NewCopyBuffer(function, wcslen(function), scriptContext);
  189. Js::Var lineNumber = Js::JavascriptNumber::ToVar((int64) lineNum, scriptContext);
  190. Js::Var colNumber = Js::JavascriptNumber::ToVar((int64) colNum, scriptContext);
  191. Js::Var functionIdNumberVar = Js::JavascriptNumber::ToVar(functionId, scriptContext);
  192. Js::Var utf8SourceInfoVar = Js::JavascriptNumber::ToVar((int32) utf8SrcInfo, scriptContext);
  193. // assign properties to function info object
  194. SetProperty(fnInfoObj, _u("filename"), filenameString);
  195. SetProperty(fnInfoObj, _u("function"), funcnameString);
  196. SetProperty(fnInfoObj, _u("line"), lineNumber);
  197. SetProperty(fnInfoObj, _u("col"), colNumber);
  198. SetProperty(fnInfoObj, _u("funcId"), functionIdNumberVar);
  199. SetProperty(fnInfoObj, _u("utf8SrcInfoPtr"), utf8SourceInfoVar);
  200. SetProperty(fnInfoObj, _u("source"), source);
  201. return fnInfoObj;
  202. }
  203. /**
  204. * Return a list of functions visible in the current ScriptContext.
  205. */
  206. Var GlobalObject::EntryFunctionList(RecyclableObject *function, CallInfo callInfo, ...)
  207. {
  208. // Note: the typedefs below help make the following code more readable
  209. // See: Js::ScriptContext::SourceList (declaration not visible from this file)
  210. typedef JsUtil::List<RecyclerWeakReference<Utf8SourceInfo>*, Recycler, false, Js::FreeListedRemovePolicy> SourceList;
  211. typedef RecyclerWeakReference<Js::Utf8SourceInfo> Utf8SourceInfoRef;
  212. ScriptContext *originalScriptContext = function->GetScriptContext();
  213. ThreadContext *threadContext = originalScriptContext->GetThreadContext();
  214. ScriptContext *scriptContext;
  215. int fnCount = 0;
  216. for (scriptContext = threadContext->GetScriptContextList();
  217. scriptContext;
  218. scriptContext = scriptContext->next)
  219. {
  220. if (scriptContext->IsClosed()) continue;
  221. //
  222. // get count of functions in all files in script context
  223. //
  224. SourceList *sourceList = scriptContext->GetSourceList();
  225. sourceList->Map([&fnCount](uint i, Utf8SourceInfoRef *sourceInfoWeakRef)
  226. {
  227. Js::Utf8SourceInfo *sourceInfo = sourceInfoWeakRef->Get();
  228. if (sourceInfo == nullptr || sourceInfo->GetIsLibraryCode()) // library code has no source, skip
  229. {
  230. return;
  231. }
  232. fnCount += sourceInfo->GetFunctionBodyCount();
  233. });
  234. }
  235. #ifdef ENABLE_IR_VIEWER_DBG_DUMP
  236. if (Js::Configuration::Global.flags.Verbose)
  237. {
  238. Output::Print(_u(">> There are %d total functions\n"), fnCount);
  239. Output::Flush();
  240. }
  241. #endif
  242. //
  243. // create a javascript array to hold info for all of the functions
  244. //
  245. Js::JavascriptArray *functionList = originalScriptContext->GetLibrary()->CreateArray(fnCount);
  246. int count = 0;
  247. for (scriptContext = threadContext->GetScriptContextList();
  248. scriptContext;
  249. scriptContext = scriptContext->next)
  250. {
  251. if (scriptContext->IsClosed()) continue;
  252. // if (scriptContext == originalScriptContext) continue; // uncomment to ignore the originalScriptContext
  253. SourceList *sourceList = scriptContext->GetSourceList();
  254. sourceList->Map([&fnCount, &count, functionList, scriptContext](uint i, Utf8SourceInfoRef *sourceInfoWeakRef)
  255. {
  256. Js::Utf8SourceInfo *sourceInfo = sourceInfoWeakRef->Get();
  257. if (sourceInfo == nullptr || sourceInfo->GetIsLibraryCode()) // library code has no source, skip
  258. {
  259. return;
  260. }
  261. const SRCINFO *srcInfo = sourceInfo->GetSrcInfo();
  262. SourceContextInfo *srcContextInfo = srcInfo->sourceContextInfo;
  263. //
  264. // get URL of source file
  265. //
  266. char16 filenameBuffer[128]; // hold dynamically built filename
  267. char16 const *srcFileUrl = NULL;
  268. if (!srcContextInfo->IsDynamic())
  269. {
  270. Assert(srcContextInfo->url != NULL);
  271. srcFileUrl = srcContextInfo->url;
  272. }
  273. else
  274. {
  275. StringCchPrintf(filenameBuffer, 128, _u("[dynamic(hash:%u)]"), srcContextInfo->hash);
  276. srcFileUrl = filenameBuffer;
  277. }
  278. sourceInfo->MapFunction([scriptContext, &count, functionList, srcFileUrl](Js::FunctionBody *functionBody)
  279. {
  280. char16 const *functionName = functionBody->GetExternalDisplayName();
  281. ULONG lineNum = functionBody->GetLineNumber();
  282. ULONG colNum = functionBody->GetColumnNumber();
  283. uint funcId = functionBody->GetLocalFunctionId();
  284. Js::Utf8SourceInfo *utf8SrcInfo = functionBody->GetUtf8SourceInfo();
  285. if (utf8SrcInfo == nullptr)
  286. {
  287. return;
  288. }
  289. Assert(utf8SrcInfo->FindFunction(funcId) == functionBody);
  290. BufferStringBuilder builder(functionBody->LengthInChars(), scriptContext);
  291. utf8::DecodeOptions options = utf8SrcInfo->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
  292. utf8::DecodeInto(builder.DangerousGetWritableBuffer(), functionBody->GetSource(), functionBody->LengthInChars(), options);
  293. Var cachedSourceString = builder.ToString();
  294. Js::Var obj = FunctionInfoObjectBuilder(scriptContext, srcFileUrl,
  295. functionName, lineNum, colNum, funcId, utf8SrcInfo, cachedSourceString);
  296. functionList->SetItem(count, obj, Js::PropertyOperationFlags::PropertyOperation_None);
  297. ++count;
  298. });
  299. });
  300. }
  301. #ifdef ENABLE_IR_VIEWER_DBG_DUMP
  302. if (Js::Configuration::Global.flags.Verbose)
  303. {
  304. Output::Print(_u(">> Returning from functionList()\n"));
  305. Output::Flush();
  306. }
  307. #endif
  308. return functionList;
  309. }
  310. /**
  311. * Return the parsed IR for the given function.
  312. */
  313. Var GlobalObject::EntryRejitFunction(RecyclableObject *function, CallInfo callInfo, ...)
  314. {
  315. #ifdef ENABLE_IR_VIEWER_DBG_DUMP
  316. if (Js::Configuration::Global.flags.Verbose)
  317. {
  318. Output::Print(_u(">> Entering rejitFunction()\n"));
  319. Output::Flush();
  320. }
  321. #endif
  322. //
  323. // retrieve and coerce arguments
  324. //
  325. RUNTIME_ARGUMENTS(args, callInfo); // args[0] is (callInfo)
  326. Js::Var jsVarUtf8SourceInfo = args[1];
  327. Js::Var jsVarFunctionId = args[2];
  328. #ifdef ENABLE_IR_VIEWER_DBG_DUMP
  329. if (Js::Configuration::Global.flags.Verbose)
  330. {
  331. Output::Print(_u("jsVarUtf8SourceInfo: %d (0x%08X)\n"), jsVarUtf8SourceInfo, jsVarUtf8SourceInfo);
  332. Output::Print(_u("jsVarFunctionId: %d (0x%08X)\n"), jsVarFunctionId, jsVarFunctionId);
  333. }
  334. #endif
  335. Js::JavascriptNumber *jsUtf8SourceInfoNumber = NULL;
  336. Js::JavascriptNumber *jsFunctionIdNumber = NULL;
  337. int32 utf8SourceInfoNumber = 0; // null
  338. int32 functionIdNumber = -1; // start with invalid function id
  339. // extract value of jsVarUtf8SourceInfo
  340. if (Js::TaggedInt::Is(jsVarUtf8SourceInfo))
  341. {
  342. utf8SourceInfoNumber = (int32)TaggedInt::ToInt64(jsVarUtf8SourceInfo); // REVIEW: just truncate?
  343. }
  344. else if (Js::JavascriptNumber::Is(jsVarUtf8SourceInfo))
  345. {
  346. jsUtf8SourceInfoNumber = (Js::JavascriptNumber *)jsVarUtf8SourceInfo;
  347. utf8SourceInfoNumber = (int32)JavascriptNumber::GetValue(jsUtf8SourceInfoNumber); // REVIEW: just truncate?
  348. }
  349. else
  350. {
  351. // should not reach here
  352. AssertMsg(false, "Failed to extract value for jsVarUtf8SourceInfo as either TaggedInt or JavascriptNumber.\n");
  353. }
  354. // extract value of jsVarFunctionId
  355. if (Js::TaggedInt::Is(jsVarFunctionId))
  356. {
  357. functionIdNumber = (int32)TaggedInt::ToInt64(jsVarFunctionId); // REVIEW: just truncate?
  358. }
  359. else if (Js::JavascriptNumber::Is(jsVarFunctionId))
  360. {
  361. jsFunctionIdNumber = (Js::JavascriptNumber *)jsVarFunctionId;
  362. functionIdNumber = (int32)JavascriptNumber::GetValue(jsFunctionIdNumber); // REVIEW: just truncate?
  363. }
  364. else
  365. {
  366. // should not reach here
  367. AssertMsg(false, "Failed to extract value for jsVarFunctionId as either TaggedInt or JavascriptNumber.\n");
  368. }
  369. #ifdef ENABLE_IR_VIEWER_DBG_DUMP
  370. if (Js::Configuration::Global.flags.Verbose)
  371. {
  372. Output::Print(_u("utf8SourceInfoNumber (value): %d (0x%08X)\n"), utf8SourceInfoNumber, utf8SourceInfoNumber);
  373. Output::Print(_u("jsVarFunctionId (value): %d (0x%08X)\n"), functionIdNumber, functionIdNumber);
  374. Output::Print(_u(">> Executing rejitFunction(%d, %d)\n"), utf8SourceInfoNumber, functionIdNumber);
  375. Output::Flush();
  376. }
  377. #endif
  378. //
  379. // recover functionBody
  380. //
  381. Js::Utf8SourceInfo *sourceInfo = (Js::Utf8SourceInfo *)(utf8SourceInfoNumber);
  382. if (sourceInfo == NULL)
  383. {
  384. return NULL;
  385. }
  386. Js::FunctionBody *functionBody = sourceInfo->FindFunction((Js::LocalFunctionId)functionIdNumber);
  387. //
  388. // rejit the function body
  389. //
  390. Js::ScriptContext *scriptContext = function->GetScriptContext();
  391. NativeCodeGenerator *nativeCodeGenerator = scriptContext->GetNativeCodeGenerator();
  392. if (!functionBody || !functionBody->GetByteCode())
  393. {
  394. return scriptContext->GetLibrary()->GetUndefined();
  395. }
  396. Js::Var retVal = RejitIRViewerFunction(nativeCodeGenerator, functionBody, scriptContext);
  397. //
  398. // return the parsed IR object
  399. //
  400. #ifdef ENABLE_IR_VIEWER_DBG_DUMP
  401. if (Js::Configuration::Global.flags.Verbose)
  402. {
  403. Output::Print(_u("rejitFunction - retVal: 0x%08X\n"), retVal);
  404. Output::Flush();
  405. }
  406. #endif
  407. return retVal;
  408. }
  409. #endif /* IR_VIEWER */
  410. Var GlobalObject::EntryEvalHelper(ScriptContext* scriptContext, RecyclableObject* function, Js::Arguments& args)
  411. {
  412. FrameDisplay* environment = (FrameDisplay*)&NullFrameDisplay;
  413. ModuleID moduleID = kmodGlobal;
  414. BOOL strictMode = FALSE;
  415. // TODO: Handle call from global scope, strict mode
  416. BOOL isIndirect = FALSE;
  417. if (args.IsDirectEvalCall())
  418. {
  419. // This was recognized as an eval call at compile time. The last one or two args are internal to us.
  420. // Argcount will be one of the following when called from global code
  421. // - eval("...") : argcount 3 : this, evalString, frameDisplay
  422. // - eval.call("..."): argcount 2 : this(which is string) , frameDisplay
  423. if (args.Info.Count >= 1)
  424. {
  425. environment = args.GetFrameDisplay();
  426. strictMode = environment->GetStrictMode();
  427. }
  428. }
  429. else
  430. {
  431. // This must be an indirect "eval" call that we didn't detect at compile time.
  432. // Pass null as the environment, which will force all lookups in the eval code
  433. // to use the root for the current module.
  434. // Also pass "null" for "this", which will force the callee to use the current module root.
  435. isIndirect = !PHASE_OFF1(Js::FastIndirectEvalPhase);
  436. }
  437. return GlobalObject::VEval(function->GetLibrary(), environment, moduleID, !!strictMode, !!isIndirect, args,
  438. /* isLibraryCode = */ false, /* registerDocument */ true, /*additionalGrfscr */ 0);
  439. }
  440. Var GlobalObject::EntryEvalRestrictedMode(RecyclableObject* function, CallInfo callInfo, ...)
  441. {
  442. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  443. RUNTIME_ARGUMENTS(args, callInfo);
  444. Assert(!(callInfo.Flags & CallFlags_New));
  445. JavascriptLibrary* library = function->GetLibrary();
  446. ScriptContext* scriptContext = library->GetScriptContext();
  447. scriptContext->CheckEvalRestriction();
  448. return EntryEvalHelper(scriptContext, function, args);
  449. }
  450. // This function is used to decipher eval function parameters and we don't want the stack arguments optimization by C++ compiler so turning off the optimization
  451. Var GlobalObject::EntryEval(RecyclableObject* function, CallInfo callInfo, ...)
  452. {
  453. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  454. RUNTIME_ARGUMENTS(args, callInfo);
  455. Assert(!(callInfo.Flags & CallFlags_New));
  456. JavascriptLibrary* library = function->GetLibrary();
  457. ScriptContext* scriptContext = library->GetScriptContext();
  458. return EntryEvalHelper(scriptContext, function, args);
  459. }
  460. Var GlobalObject::VEval(JavascriptLibrary* library, FrameDisplay* environment, ModuleID moduleID, bool strictMode, bool isIndirect,
  461. Arguments& args, bool isLibraryCode, bool registerDocument, uint32 additionalGrfscr, ScriptContext* debugEvalScriptContext)
  462. {
  463. Assert(library);
  464. ScriptContext* scriptContext = library->GetScriptContext();
  465. unsigned argCount = args.Info.Count;
  466. AssertMsg(argCount > 0, "Should always have implicit 'this'");
  467. bool doRegisterDocument = registerDocument & !isLibraryCode;
  468. Var varThis = library->GetUndefined();
  469. if (argCount < 2)
  470. {
  471. return library->GetUndefined();
  472. }
  473. Var evalArg = args[1];
  474. if (!VarIs<JavascriptString>(evalArg))
  475. {
  476. // "If x is not a string value, return x."
  477. return evalArg;
  478. }
  479. #ifdef ENABLE_SCRIPT_DEBUGGING
  480. // It might happen that no script parsed on this context (scriptContext) till now,
  481. // so this Eval acts as the first source compile for scriptContext, transition to debugMode as needed
  482. scriptContext->TransitionToDebugModeIfFirstSource(/* utf8SourceInfo = */ nullptr);
  483. #endif
  484. ScriptFunction *pfuncScript = nullptr;
  485. JavascriptString *argString = VarTo<JavascriptString>(evalArg);
  486. char16 const * sourceString = argString->GetSz();
  487. charcount_t sourceLen = argString->GetLength();
  488. FastEvalMapString key(argString, sourceString, sourceLen, moduleID, strictMode, isLibraryCode);
  489. // PropertyString's buffer references to PropertyRecord's inline buffer, if both PropertyString and PropertyRecord are collected
  490. // we'll leave the PropertyRecord's interior buffer pointer in the EvalMap. So do not use evalmap if we are evaluating PropertyString
  491. bool useEvalMap = !VirtualTableInfo<PropertyString>::HasVirtualTable(argString) && debugEvalScriptContext == nullptr; // Don't use the cache in case of debugEval
  492. bool found = useEvalMap && scriptContext->IsInEvalMap(key, isIndirect, &pfuncScript);
  493. if (!found || (!isIndirect && pfuncScript->GetEnvironment() != &NullFrameDisplay))
  494. {
  495. uint32 grfscr = additionalGrfscr | fscrReturnExpression | fscrEval | fscrEvalCode | fscrGlobalCode;
  496. if (isLibraryCode)
  497. {
  498. grfscr |= fscrIsLibraryCode;
  499. }
  500. if (!(grfscr & fscrConsoleScopeEval))
  501. {
  502. grfscr |= fscrCanDeferFncParse;
  503. }
  504. pfuncScript = library->GetGlobalObject()->EvalHelper(scriptContext, argString->GetSz(), argString->GetLength(), moduleID,
  505. grfscr, Constants::EvalCode, doRegisterDocument, isIndirect, strictMode);
  506. if (debugEvalScriptContext != nullptr && CrossSite::NeedMarshalVar(pfuncScript, debugEvalScriptContext))
  507. {
  508. // This is console scope scenario. DebugEval script context is on the top of the stack. But we are going
  509. // to execute the user script from target script context. In order to fix the script context stack we
  510. // need to marshall the function object.
  511. pfuncScript = VarTo<ScriptFunction>(CrossSite::MarshalVar(debugEvalScriptContext, pfuncScript));
  512. }
  513. if (useEvalMap && !found)
  514. {
  515. scriptContext->AddToEvalMap(key, isIndirect, pfuncScript);
  516. }
  517. }
  518. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  519. else
  520. {
  521. Js::Utf8SourceInfo* utf8SourceInfo = pfuncScript->GetFunctionBody()->GetUtf8SourceInfo();
  522. if (scriptContext->IsScriptContextInDebugMode() && !utf8SourceInfo->GetIsLibraryCode() && !utf8SourceInfo->IsInDebugMode())
  523. {
  524. // Identifying if any non library function escaped for not being in debug mode.
  525. Throw::FatalInternalError();
  526. }
  527. }
  528. #endif
  529. #if ENABLE_TTD
  530. //
  531. //TODO: We may (probably?) want to use the debugger source rundown functionality here instead
  532. //
  533. if(!isLibraryCode && pfuncScript != nullptr && (scriptContext->IsTTDRecordModeEnabled() || scriptContext->ShouldPerformReplayAction()))
  534. {
  535. //Make sure we have the body and text information available
  536. FunctionBody* globalBody = TTD::JsSupport::ForceAndGetFunctionBody(pfuncScript->GetParseableFunctionInfo());
  537. if(!scriptContext->TTDContextInfo->IsBodyAlreadyLoadedAtTopLevel(globalBody))
  538. {
  539. uint32 bodyIdCtr = 0;
  540. if(scriptContext->IsTTDRecordModeEnabled())
  541. {
  542. const TTD::NSSnapValues::TopLevelEvalFunctionBodyResolveInfo* tbfi = scriptContext->GetThreadContext()->TTDLog->AddEvalFunction(globalBody, moduleID, sourceString, sourceLen, additionalGrfscr, registerDocument, isIndirect, strictMode);
  543. //We always want to register the top-level load but we don't always need to log the event
  544. if(scriptContext->ShouldPerformRecordAction())
  545. {
  546. scriptContext->GetThreadContext()->TTDLog->RecordTopLevelCodeAction(tbfi->TopLevelBase.TopLevelBodyCtr);
  547. }
  548. bodyIdCtr = tbfi->TopLevelBase.TopLevelBodyCtr;
  549. }
  550. if(scriptContext->ShouldPerformReplayAction())
  551. {
  552. bodyIdCtr = scriptContext->GetThreadContext()->TTDLog->ReplayTopLevelCodeAction();
  553. }
  554. //walk global body to (1) add functions to pin set (2) build parent map
  555. scriptContext->TTDContextInfo->ProcessFunctionBodyOnLoad(globalBody, nullptr);
  556. scriptContext->TTDContextInfo->RegisterEvalScript(globalBody, bodyIdCtr);
  557. if(scriptContext->ShouldPerformRecordOrReplayAction())
  558. {
  559. globalBody->GetUtf8SourceInfo()->SetSourceInfoForDebugReplay_TTD(bodyIdCtr);
  560. }
  561. if(scriptContext->ShouldPerformReplayDebuggerAction())
  562. {
  563. scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessScriptLoad(scriptContext, bodyIdCtr, globalBody, globalBody->GetUtf8SourceInfo(), nullptr);
  564. }
  565. }
  566. }
  567. #endif
  568. //We shouldn't be serializing eval functions; unless with -ForceSerialized flag
  569. if (CONFIG_FLAG(ForceSerialized)) {
  570. pfuncScript->GetFunctionProxy()->EnsureDeserialized();
  571. }
  572. if (pfuncScript->HasSuperReference())
  573. {
  574. // Indirect evals cannot have a super reference.
  575. if (!(args.Info.Flags & CallFlags_ExtraArg))
  576. {
  577. JavascriptError::ThrowSyntaxError(scriptContext, ERRSuperInIndirectEval, _u("super"));
  578. }
  579. }
  580. return library->GetGlobalObject()->ExecuteEvalParsedFunction(pfuncScript, environment, varThis, scriptContext);
  581. }
  582. void GlobalObject::UpdateThisForEval(Var &varThis, ModuleID moduleID, ScriptContext *scriptContext)
  583. {
  584. varThis = JavascriptOperators::OP_GetThisNoFastPath(varThis, moduleID, scriptContext);
  585. }
  586. Var GlobalObject::ExecuteEvalParsedFunction(ScriptFunction *pfuncScript, FrameDisplay* environment, Var &varThis, ScriptContext *scriptContext)
  587. {
  588. Assert(pfuncScript != nullptr);
  589. pfuncScript->SetEnvironment(environment);
  590. //This function is supposed to be deserialized
  591. Assert(pfuncScript->GetFunctionBody());
  592. if (pfuncScript->GetFunctionBody()->GetFuncEscapes())
  593. {
  594. // Executing the eval causes the scope chain to escape.
  595. pfuncScript->InvalidateCachedScopeChain();
  596. }
  597. Var varResult = nullptr;
  598. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  599. {
  600. varResult = CALL_FUNCTION(scriptContext->GetThreadContext(), pfuncScript, CallInfo(CallFlags_Eval, 1), varThis);
  601. }
  602. END_SAFE_REENTRANT_CALL
  603. pfuncScript->SetEnvironment((FrameDisplay*)&NullFrameDisplay);
  604. return varResult;
  605. }
  606. #ifdef ENABLE_SCRIPT_PROFILING
  607. ScriptFunction* GlobalObject::ProfileModeEvalHelper(ScriptContext* scriptContext, const char16 *source, int sourceLength, ModuleID moduleID, uint32 grfscr, LPCOLESTR pszTitle, BOOL registerDocument, BOOL isIndirect, BOOL strictMode)
  608. {
  609. #if ENABLE_DEBUG_CONFIG_OPTIONS
  610. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  611. #endif
  612. ScriptFunction *pEvalFunction = DefaultEvalHelper(scriptContext, source, sourceLength, moduleID, grfscr, pszTitle, registerDocument, isIndirect, strictMode);
  613. Assert(pEvalFunction);
  614. Js::FunctionProxy *proxy = pEvalFunction->GetFunctionProxy();
  615. Assert(proxy);
  616. OUTPUT_TRACE(Js::ScriptProfilerPhase, _u("GlobalObject::ProfileModeEvalHelper FunctionNumber : %s, Entrypoint : 0x%08X IsFunctionDefer : %d\n"),
  617. proxy->GetDebugNumberSet(debugStringBuffer), pEvalFunction->GetEntryPoint(), proxy->IsDeferred());
  618. if (proxy->IsDeferred())
  619. {
  620. // This could happen if the top level function is marked as deferred, we need to parse this to generate the script compile information (RegisterScript depends on that)
  621. Js::JavascriptFunction::DeferredParse(&pEvalFunction);
  622. proxy = pEvalFunction->GetFunctionProxy();
  623. }
  624. scriptContext->RegisterScript(proxy);
  625. return pEvalFunction;
  626. }
  627. #endif
  628. void GlobalObject::ValidateSyntax(ScriptContext* scriptContext, const char16 *source, int sourceLength, bool isGenerator, bool isAsync, void (Parser::*validateSyntax)())
  629. {
  630. Assert(sourceLength >= 0);
  631. HRESULT hr = S_OK;
  632. HRESULT hrParser = E_FAIL;
  633. CompileScriptException se;
  634. BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext);
  635. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
  636. {
  637. ArenaAllocator tempAlloc(_u("ValidateSyntaxArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Throw::OutOfMemory);
  638. size_t cchSource = sourceLength;
  639. size_t cbUtf8Buffer = UInt32Math::MulAdd<3, 1>(sourceLength);
  640. LPUTF8 utf8Source = AnewArray(&tempAlloc, utf8char_t, cbUtf8Buffer);
  641. Assert(cchSource < MAXLONG);
  642. size_t cbSource = utf8::EncodeIntoAndNullTerminate<utf8::Utf8EncodingKind::Cesu8>(utf8Source, cbUtf8Buffer, source, static_cast<charcount_t>(cchSource));
  643. utf8Source = reinterpret_cast< LPUTF8 >( tempAlloc.Realloc(utf8Source, cbUtf8Buffer, cbSource + 1) );
  644. Parser parser(scriptContext);
  645. hrParser = parser.ValidateSyntax(utf8Source, cbSource, isGenerator, isAsync, &se, validateSyntax);
  646. }
  647. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  648. END_LEAVE_SCRIPT_INTERNAL(scriptContext);
  649. if (FAILED(hr))
  650. {
  651. if (hr == E_OUTOFMEMORY)
  652. {
  653. JavascriptError::ThrowOutOfMemoryError(scriptContext);
  654. }
  655. if (hr == VBSERR_OutOfStack)
  656. {
  657. JavascriptError::ThrowStackOverflowError(scriptContext);
  658. }
  659. }
  660. if (!SUCCEEDED(hrParser))
  661. {
  662. hrParser = SCRIPT_E_RECORDED;
  663. EXCEPINFO ei;
  664. se.GetError(&hrParser, &ei);
  665. ErrorTypeEnum errorType;
  666. switch ((HRESULT)ei.scode)
  667. {
  668. #define RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) \
  669. case name: \
  670. errorType = jst; \
  671. break;
  672. #define RT_PUBLICERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource)
  673. #include "rterrors.h"
  674. #undef RT_PUBLICERROR_MSG
  675. #undef RT_ERROR_MSG
  676. default:
  677. errorType = kjstSyntaxError;
  678. }
  679. JavascriptError::MapAndThrowError(scriptContext, ei.scode, errorType, &ei);
  680. }
  681. }
  682. ScriptFunction* GlobalObject::DefaultEvalHelper(ScriptContext* scriptContext, const char16 *source, int sourceLength, ModuleID moduleID, uint32 grfscr, LPCOLESTR pszTitle, BOOL registerDocument, BOOL isIndirect, BOOL strictMode)
  683. {
  684. Assert(sourceLength >= 0);
  685. AnalysisAssert(scriptContext);
  686. if (scriptContext->GetThreadContext()->EvalDisabled())
  687. {
  688. throw Js::EvalDisabledException();
  689. }
  690. #ifdef PROFILE_EXEC
  691. scriptContext->ProfileBegin(Js::EvalCompilePhase);
  692. #endif
  693. void * frameAddr = nullptr;
  694. GET_CURRENT_FRAME_ID(frameAddr);
  695. HRESULT hr = S_OK;
  696. HRESULT hrParser = S_OK;
  697. HRESULT hrCodeGen = S_OK;
  698. CompileScriptException se;
  699. Js::ParseableFunctionInfo * funcBody = NULL;
  700. uint sourceIndex = Constants::InvalidSourceIndex;
  701. BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext);
  702. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
  703. {
  704. uint cchSource = sourceLength;
  705. size_t cbUtf8Buffer = UInt32Math::MulAdd<3, 1>(cchSource);
  706. ArenaAllocator tempArena(_u("EvalHelperArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory);
  707. LPUTF8 utf8Source = AnewArray(&tempArena, utf8char_t, cbUtf8Buffer);
  708. Assert(cchSource < MAXLONG);
  709. size_t cbSource = utf8::EncodeIntoAndNullTerminate<utf8::Utf8EncodingKind::Cesu8>(utf8Source, cbUtf8Buffer, source, static_cast<charcount_t>(cchSource));
  710. Assert(cbSource + 1 <= cbUtf8Buffer);
  711. SRCINFO const * pSrcInfo = scriptContext->GetModuleSrcInfo(moduleID);
  712. // Source Info objects are kept alive by the function bodies that are referencing it
  713. // The function body is created in GenerateByteCode but the source info isn't passed in, only the index
  714. // So we need to pin it here (TODO: Change GenerateByteCode to take in the sourceInfo itself)
  715. ENTER_PINNED_SCOPE(Utf8SourceInfo, sourceInfo);
  716. sourceInfo = Utf8SourceInfo::New(scriptContext, utf8Source, cchSource,
  717. cbSource, pSrcInfo, ((grfscr & fscrIsLibraryCode) != 0));
  718. Parser parser(scriptContext, strictMode);
  719. bool forceNoNative = false;
  720. ParseNodeProg * parseTree = nullptr;
  721. SourceContextInfo * sourceContextInfo = pSrcInfo->sourceContextInfo;
  722. ULONG deferParseThreshold = Parser::GetDeferralThreshold(sourceContextInfo->IsSourceProfileLoaded());
  723. if ((ULONG)sourceLength > deferParseThreshold && !PHASE_OFF1(Phase::DeferParsePhase))
  724. {
  725. // Defer function bodies declared inside large dynamic blocks.
  726. grfscr |= fscrWillDeferFncParse;
  727. }
  728. grfscr = grfscr | fscrDynamicCode;
  729. // fscrEval signifies direct eval in parser
  730. hrParser = parser.ParseCesu8Source(&parseTree, utf8Source, cbSource, isIndirect ? grfscr & ~fscrEval : grfscr, &se, &sourceContextInfo->nextLocalFunctionId,
  731. sourceContextInfo);
  732. sourceInfo->SetParseFlags(grfscr);
  733. if (SUCCEEDED(hrParser) && parseTree)
  734. {
  735. // This keeps function bodies generated by the byte code alive till we return
  736. Js::AutoDynamicCodeReference dynamicFunctionReference(scriptContext);
  737. Assert(cchSource < MAXLONG);
  738. sourceIndex = scriptContext->SaveSourceNoCopy(sourceInfo, cchSource, true);
  739. // Tell byte code gen not to attempt to interact with the caller's context if this is indirect eval.
  740. // TODO: Handle strict mode.
  741. if (isIndirect &&
  742. !strictMode &&
  743. !parseTree->GetStrictMode())
  744. {
  745. grfscr &= ~fscrEval;
  746. }
  747. hrCodeGen = GenerateByteCode(parseTree, grfscr, scriptContext, &funcBody, sourceIndex, forceNoNative, &parser, &se);
  748. sourceInfo->SetByteCodeGenerationFlags(grfscr);
  749. }
  750. LEAVE_PINNED_SCOPE();
  751. }
  752. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  753. END_LEAVE_SCRIPT_INTERNAL(scriptContext);
  754. #ifdef PROFILE_EXEC
  755. scriptContext->ProfileEnd(Js::EvalCompilePhase);
  756. #endif
  757. THROW_KNOWN_HRESULT_EXCEPTIONS(hr, scriptContext);
  758. if (!SUCCEEDED(hrParser))
  759. {
  760. JavascriptError::ThrowParserError(scriptContext, hrParser, &se);
  761. }
  762. else if (!SUCCEEDED(hrCodeGen))
  763. {
  764. Assert(hrCodeGen == SCRIPT_E_RECORDED);
  765. hrCodeGen = se.ei.scode;
  766. /*
  767. * VBSERR_OutOfStack is of type kjstError but we throw a (more specific) StackOverflowError when a hard stack
  768. * overflow occurs. To keep the behavior consistent I'm special casing it here.
  769. */
  770. se.Free();
  771. if (hrCodeGen == VBSERR_OutOfStack)
  772. {
  773. JavascriptError::ThrowStackOverflowError(scriptContext);
  774. }
  775. else if (hrCodeGen == JSERR_AsmJsCompileError)
  776. {
  777. // if asm.js compilation failed, retry with asm.js disabled
  778. grfscr |= fscrNoAsmJs;
  779. if (sourceIndex != Constants::InvalidSourceIndex)
  780. {
  781. // If we registered source, we should remove it or we will register another source info
  782. scriptContext->RemoveSource(sourceIndex);
  783. }
  784. return DefaultEvalHelper(scriptContext, source, sourceLength, moduleID, grfscr, pszTitle, registerDocument, isIndirect, strictMode);
  785. }
  786. JavascriptError::MapAndThrowError(scriptContext, hrCodeGen);
  787. }
  788. else
  789. {
  790. Assert(funcBody != nullptr);
  791. funcBody->SetDisplayName(pszTitle);
  792. // Set the functionbody information to dynamic content PROFILER_SCRIPT_TYPE_DYNAMIC
  793. funcBody->SetIsTopLevel(true);
  794. // If not library code then let's find the parent, we may need to register this source if any exception happens later
  795. if ((grfscr & fscrIsLibraryCode) == 0)
  796. {
  797. // For parented eval get the caller's utf8SourceInfo
  798. JavascriptFunction* pfuncCaller = nullptr;
  799. if (JavascriptStackWalker::GetCaller(&pfuncCaller, scriptContext) && pfuncCaller && pfuncCaller->IsScriptFunction())
  800. {
  801. FunctionBody* parentFuncBody = pfuncCaller->GetFunctionBody();
  802. Utf8SourceInfo* parentUtf8SourceInfo = parentFuncBody->GetUtf8SourceInfo();
  803. Utf8SourceInfo* utf8SourceInfo = funcBody->GetUtf8SourceInfo();
  804. utf8SourceInfo->SetCallerUtf8SourceInfo(parentUtf8SourceInfo);
  805. }
  806. }
  807. if (registerDocument)
  808. {
  809. funcBody->RegisterFuncToDiag(scriptContext, pszTitle);
  810. funcBody = funcBody->GetParseableFunctionInfo(); // RegisterFunction may parse and update function body
  811. }
  812. ScriptFunction* pfuncScript = funcBody->IsCoroutine() ?
  813. scriptContext->GetLibrary()->CreateGeneratorVirtualScriptFunction(funcBody) :
  814. scriptContext->GetLibrary()->CreateScriptFunction(funcBody);
  815. return pfuncScript;
  816. }
  817. }
  818. #ifdef IR_VIEWER
  819. Var GlobalObject::IRDumpEvalHelper(ScriptContext* scriptContext, const char16 *source,
  820. int sourceLength, ModuleID moduleID, uint32 grfscr, LPCOLESTR pszTitle,
  821. BOOL registerDocument, BOOL isIndirect, BOOL strictMode)
  822. {
  823. // TODO (t-doilij) clean up this function, specifically used for IR dump (don't execute bytecode; potentially dangerous)
  824. Assert(sourceLength >= 0);
  825. if (scriptContext->GetThreadContext()->EvalDisabled())
  826. {
  827. throw Js::EvalDisabledException();
  828. }
  829. #ifdef PROFILE_EXEC
  830. scriptContext->ProfileBegin(Js::EvalCompilePhase);
  831. #endif
  832. void * frameAddr = nullptr;
  833. GET_CURRENT_FRAME_ID(frameAddr);
  834. HRESULT hr = S_OK;
  835. HRESULT hrParser = S_OK;
  836. HRESULT hrCodeGen = S_OK;
  837. CompileScriptException se;
  838. Js::ParseableFunctionInfo * funcBody = NULL;
  839. BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext);
  840. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
  841. {
  842. size_t cchSource = sourceLength;
  843. size_t cbUtf8Buffer = UInt32Math::AddMul<1, 3>(sourceLength);
  844. ArenaAllocator tempArena(_u("EvalHelperArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory);
  845. LPUTF8 utf8Source = AnewArray(&tempArena, utf8char_t, cbUtf8Buffer);
  846. Assert(cchSource < MAXLONG);
  847. size_t cbSource = utf8::EncodeIntoAndNullTerminate(utf8Source, source, static_cast< charcount_t >(cchSource));
  848. Assert(cbSource + 1 <= cbUtf8Buffer);
  849. SRCINFO const * pSrcInfo = scriptContext->GetModuleSrcInfo(moduleID);
  850. // Source Info objects are kept alive by the function bodies that are referencing it
  851. // The function body is created in GenerateByteCode but the source info isn't passed in, only the index
  852. // So we need to pin it here (TODO: Change GenerateByteCode to take in the sourceInfo itself)
  853. ENTER_PINNED_SCOPE(Utf8SourceInfo, sourceInfo);
  854. sourceInfo = Utf8SourceInfo::New(scriptContext, utf8Source, cchSource, cbSource, pSrcInfo, ((grfscr & fscrIsLibraryCode) != 0));
  855. Parser parser(scriptContext, strictMode);
  856. bool forceNoNative = false;
  857. ParseNodePtr parseTree = nullptr;
  858. SourceContextInfo * sourceContextInfo = pSrcInfo->sourceContextInfo;
  859. grfscr = grfscr | fscrDynamicCode;
  860. hrParser = parser.ParseCesu8Source(&parseTree, utf8Source, cbSource, grfscr, &se, &sourceContextInfo->nextLocalFunctionId,
  861. sourceContextInfo);
  862. sourceInfo->SetParseFlags(grfscr);
  863. if (SUCCEEDED(hrParser) && parseTree)
  864. {
  865. // This keeps function bodies generated by the byte code alive till we return
  866. Js::AutoDynamicCodeReference dynamicFunctionReference(scriptContext);
  867. Assert(cchSource < MAXLONG);
  868. uint sourceIndex = scriptContext->SaveSourceNoCopy(sourceInfo, cchSource, true);
  869. grfscr = grfscr | fscrIrDumpEnable;
  870. hrCodeGen = GenerateByteCode(parseTree, grfscr, scriptContext, &funcBody, sourceIndex, forceNoNative, &parser, &se);
  871. sourceInfo->SetByteCodeGenerationFlags(grfscr);
  872. }
  873. LEAVE_PINNED_SCOPE();
  874. }
  875. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  876. END_LEAVE_SCRIPT_INTERNAL(scriptContext);
  877. #ifdef PROFILE_EXEC
  878. scriptContext->ProfileEnd(Js::EvalCompilePhase);
  879. #endif
  880. THROW_KNOWN_HRESULT_EXCEPTIONS(hr);
  881. if (!SUCCEEDED(hrParser))
  882. {
  883. hrParser = SCRIPT_E_RECORDED;
  884. EXCEPINFO ei;
  885. se.GetError(&hrParser, &ei);
  886. ErrorTypeEnum errorType;
  887. switch ((HRESULT)ei.scode)
  888. {
  889. #define RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) \
  890. case name: \
  891. errorType = jst; \
  892. break;
  893. #define RT_PUBLICERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource)
  894. #include "rterrors.h"
  895. #undef RT_PUBLICERROR_MSG
  896. #undef RT_ERROR_MSG
  897. default:
  898. errorType = kjstSyntaxError;
  899. }
  900. JavascriptError::MapAndThrowError(scriptContext, ei.scode, errorType, &ei);
  901. }
  902. else if (!SUCCEEDED(hrCodeGen))
  903. {
  904. Assert(hrCodeGen == SCRIPT_E_RECORDED);
  905. hrCodeGen = se.ei.scode;
  906. /*
  907. * VBSERR_OutOfStack is of type kjstError but we throw a (more specific) StackOverflowError when a hard stack
  908. * overflow occurs. To keep the behavior consistent I'm special casing it here.
  909. */
  910. se.Free();
  911. if (hrCodeGen == VBSERR_OutOfStack)
  912. {
  913. JavascriptError::ThrowStackOverflowError(scriptContext);
  914. }
  915. JavascriptError::MapAndThrowError(scriptContext, hrCodeGen);
  916. }
  917. else
  918. {
  919. Assert(funcBody != nullptr);
  920. funcBody->SetDisplayName(pszTitle);
  921. // Set the functionbody information to dynamic content PROFILER_SCRIPT_TYPE_DYNAMIC
  922. funcBody->SetIsTopLevel(true);
  923. if (registerDocument)
  924. {
  925. funcBody->RegisterFuncToDiag(scriptContext, pszTitle);
  926. funcBody = funcBody->GetParseableFunctionInfo(); // RegisterFunction may parse and update function body
  927. }
  928. NativeCodeGenerator *nativeCodeGenerator = scriptContext->GetNativeCodeGenerator();
  929. Js::FunctionBody *functionBody = funcBody->GetFunctionBody(); // funcBody is ParseableFunctionInfo
  930. if (!functionBody || !functionBody->GetByteCode())
  931. {
  932. return scriptContext->GetLibrary()->GetUndefined();
  933. }
  934. Js::Var retVal = RejitIRViewerFunction(nativeCodeGenerator, functionBody, scriptContext);
  935. return retVal;
  936. }
  937. }
  938. #endif /* IR_VIEWER */
  939. Var GlobalObject::EntryParseInt(RecyclableObject* function, CallInfo callInfo, ...)
  940. {
  941. JIT_HELPER_REENTRANT_HEADER(GlobalObject_ParseInt);
  942. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  943. ARGUMENTS(args, callInfo);
  944. ScriptContext* scriptContext = function->GetScriptContext();
  945. Assert(!(callInfo.Flags & CallFlags_New));
  946. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  947. JavascriptString *str;
  948. int radix = 0;
  949. if(args.Info.Count < 2)
  950. {
  951. // We're really converting "undefined" here, but "undefined" produces
  952. // NaN, so just return that directly.
  953. return JavascriptNumber::ToVarNoCheck(JavascriptNumber::NaN, scriptContext);
  954. }
  955. // Short cut for numbers and radix 10
  956. if (((args.Info.Count == 2) ||
  957. (TaggedInt::Is(args[2]) && TaggedInt::ToInt32(args[2]) == 10) ||
  958. (JavascriptNumber::Is(args[2]) && JavascriptNumber::GetValue(args[2]) == 10)))
  959. {
  960. if (TaggedInt::Is(args[1]))
  961. {
  962. return args[1];
  963. }
  964. if (JavascriptNumber::Is(args[1]))
  965. {
  966. double value = JavascriptNumber::GetValue(args[1]);
  967. // make sure we are in the ranges that don't have exponential notation.
  968. double absValue = Math::Abs(value);
  969. if (absValue < 1.0e21 && absValue >= 1e-5)
  970. {
  971. double result;
  972. #pragma prefast(suppress:6031, "We don't care about the fraction part")
  973. ::modf(value, &result);
  974. return JavascriptNumber::ToVarIntCheck(result, scriptContext);
  975. }
  976. }
  977. }
  978. // convert input to a string
  979. if (VarIs<JavascriptString>(args[1]))
  980. {
  981. str = VarTo<JavascriptString>(args[1]);
  982. }
  983. else
  984. {
  985. str = JavascriptConversion::ToString(args[1], scriptContext);
  986. }
  987. if(args.Info.Count > 2)
  988. {
  989. // retrieve the radix
  990. // TODO : verify for ES5 : radix is 10 when undefined or 0, except when it starts with 0x when it is 16.
  991. radix = JavascriptConversion::ToInt32(args[2], scriptContext);
  992. if(radix < 0 || radix == 1 || radix > 36)
  993. {
  994. //illegal, return NaN
  995. return JavascriptNumber::ToVarNoCheck(JavascriptNumber::NaN, scriptContext);
  996. }
  997. }
  998. Var result = str->ToInteger(radix);
  999. return result;
  1000. JIT_HELPER_END(GlobalObject_ParseInt);
  1001. }
  1002. Var GlobalObject::EntryParseFloat(RecyclableObject* function, CallInfo callInfo, ...)
  1003. {
  1004. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1005. ARGUMENTS(args, callInfo);
  1006. ScriptContext* scriptContext = function->GetScriptContext();
  1007. Assert(!(callInfo.Flags & CallFlags_New));
  1008. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1009. double result = 0;
  1010. ENTER_PINNED_SCOPE(JavascriptString, str);
  1011. if(args.Info.Count < 2)
  1012. {
  1013. // We're really converting "undefined" here, but "undefined" produces
  1014. // NaN, so just return that directly.
  1015. return JavascriptNumber::ToVarNoCheck(JavascriptNumber::NaN, scriptContext);
  1016. }
  1017. // Short cut for numbers
  1018. if (TaggedInt::Is(args[1]))
  1019. {
  1020. return args[1];
  1021. }
  1022. if(JavascriptNumber::Is_NoTaggedIntCheck(args[1]))
  1023. {
  1024. // If the value is negative zero, return positive zero. Since the parameter type is string, -0 would first be
  1025. // converted to the string "0", then parsed to result in positive zero.
  1026. return
  1027. JavascriptNumber::IsNegZero(JavascriptNumber::GetValue(args[1])) ?
  1028. TaggedInt::ToVarUnchecked(0) :
  1029. args[1];
  1030. }
  1031. // convert input to a string
  1032. if (VarIs<JavascriptString>(args[1]))
  1033. {
  1034. str = VarTo<JavascriptString>(args[1]);
  1035. }
  1036. else
  1037. {
  1038. str = JavascriptConversion::ToString(args[1], scriptContext);
  1039. }
  1040. // skip preceding whitespace
  1041. const char16 *pch = scriptContext->GetCharClassifier()->SkipWhiteSpace(str->GetSz());
  1042. // perform the string -> float conversion
  1043. result = NumberUtilities::StrToDbl(pch, &pch, scriptContext);
  1044. LEAVE_PINNED_SCOPE(); // str
  1045. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1046. }
  1047. Var GlobalObject::EntryIsNaN(RecyclableObject* function, CallInfo callInfo, ...)
  1048. {
  1049. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1050. ARGUMENTS(args, callInfo);
  1051. ScriptContext* scriptContext = function->GetScriptContext();
  1052. Assert(!(callInfo.Flags & CallFlags_New));
  1053. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1054. if(args.Info.Count < 2)
  1055. {
  1056. return scriptContext->GetLibrary()->GetTrue();
  1057. }
  1058. return JavascriptBoolean::ToVar(
  1059. JavascriptNumber::IsNan(JavascriptConversion::ToNumber(args[1],scriptContext)),
  1060. scriptContext);
  1061. }
  1062. Var GlobalObject::EntryIsFinite(RecyclableObject* function, CallInfo callInfo, ...)
  1063. {
  1064. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1065. ARGUMENTS(args, callInfo);
  1066. ScriptContext* scriptContext = function->GetScriptContext();
  1067. Assert(!(callInfo.Flags & CallFlags_New));
  1068. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1069. if(args.Info.Count < 2)
  1070. {
  1071. return scriptContext->GetLibrary()->GetFalse();
  1072. }
  1073. return JavascriptBoolean::ToVar(
  1074. NumberUtilities::IsFinite(JavascriptConversion::ToNumber(args[1],scriptContext)),
  1075. scriptContext);
  1076. }
  1077. Var GlobalObject::EntryDecodeURI(RecyclableObject* function, CallInfo callInfo, ...)
  1078. {
  1079. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1080. ARGUMENTS(args, callInfo);
  1081. ScriptContext* scriptContext = function->GetScriptContext();
  1082. Assert(!(callInfo.Flags & CallFlags_New));
  1083. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1084. return UriHelper::DecodeCoreURI(scriptContext, args, UriHelper::URIReserved);
  1085. }
  1086. Var GlobalObject::EntryDecodeURIComponent(RecyclableObject* function, CallInfo callInfo, ...)
  1087. {
  1088. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1089. ARGUMENTS(args, callInfo);
  1090. ScriptContext* scriptContext = function->GetScriptContext();
  1091. Assert(!(callInfo.Flags & CallFlags_New));
  1092. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1093. return UriHelper::DecodeCoreURI(scriptContext, args, UriHelper::URINone);
  1094. }
  1095. Var GlobalObject::EntryEncodeURI(RecyclableObject* function, CallInfo callInfo, ...)
  1096. {
  1097. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1098. ARGUMENTS(args, callInfo);
  1099. ScriptContext* scriptContext = function->GetScriptContext();
  1100. Assert(!(callInfo.Flags & CallFlags_New));
  1101. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1102. return UriHelper::EncodeCoreURI(scriptContext, args, UriHelper::URIReserved | UriHelper::URIUnescaped);
  1103. }
  1104. Var GlobalObject::EntryEncodeURIComponent(RecyclableObject* function, CallInfo callInfo, ...)
  1105. {
  1106. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1107. ARGUMENTS(args, callInfo);
  1108. ScriptContext* scriptContext = function->GetScriptContext();
  1109. Assert(!(callInfo.Flags & CallFlags_New));
  1110. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1111. return UriHelper::EncodeCoreURI(scriptContext, args, UriHelper::URIUnescaped);
  1112. }
  1113. //
  1114. // Part of Appendix B of ES5 spec
  1115. //
  1116. // This is a bit field for the hex values: 00-29, 2C, 3A-3F, 5B-5E, 60, 7B-FF
  1117. // These are the values escape encodes using the default mask (or mask >= 4)
  1118. static const BYTE _grfbitEscape[] =
  1119. {
  1120. 0xFF, 0xFF, // 00 - 0F
  1121. 0xFF, 0xFF, // 10 - 1F
  1122. 0xFF, 0x13, // 20 - 2F
  1123. 0x00, 0xFC, // 30 - 3F
  1124. 0x00, 0x00, // 40 - 4F
  1125. 0x00, 0x78, // 50 - 5F
  1126. 0x01, 0x00, // 60 - 6F
  1127. 0x00, 0xF8, // 70 - 7F
  1128. 0xFF, 0xFF, // 80 - 8F
  1129. 0xFF, 0xFF, // 90 - 9F
  1130. 0xFF, 0xFF, // A0 - AF
  1131. 0xFF, 0xFF, // B0 - BF
  1132. 0xFF, 0xFF, // C0 - CF
  1133. 0xFF, 0xFF, // D0 - DF
  1134. 0xFF, 0xFF, // E0 - EF
  1135. 0xFF, 0xFF, // F0 - FF
  1136. };
  1137. Var GlobalObject::EntryEscape(RecyclableObject* function, CallInfo callInfo, ...)
  1138. {
  1139. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1140. ARGUMENTS(args, callInfo);
  1141. ScriptContext* scriptContext = function->GetScriptContext();
  1142. Assert(!(callInfo.Flags & CallFlags_New));
  1143. if (args.Info.Count <= 1)
  1144. {
  1145. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  1146. }
  1147. CompoundString * bs = nullptr;
  1148. ENTER_PINNED_SCOPE(JavascriptString, src);
  1149. src = JavascriptConversion::ToString(args[1], scriptContext);
  1150. bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
  1151. char16 chw;
  1152. char16 * pchSrc;
  1153. char16 * pchLim;
  1154. const char _rgchHex[] = "0123456789ABCDEF";
  1155. pchSrc = const_cast<char16 *>(src->GetString());
  1156. pchLim = pchSrc + src->GetLength();
  1157. while (pchSrc < pchLim)
  1158. {
  1159. chw = *pchSrc++;
  1160. if (0 != (chw & 0xFF00))
  1161. {
  1162. bs->AppendChars(_u("%u"));
  1163. bs->AppendChars(static_cast<char16>(_rgchHex[(chw >> 12) & 0x0F]));
  1164. bs->AppendChars(static_cast<char16>(_rgchHex[(chw >> 8) & 0x0F]));
  1165. bs->AppendChars(static_cast<char16>(_rgchHex[(chw >> 4) & 0x0F]));
  1166. bs->AppendChars(static_cast<char16>(_rgchHex[chw & 0x0F]));
  1167. }
  1168. else if (_grfbitEscape[chw >> 3] & (1 << (chw & 7)))
  1169. {
  1170. // Escape the byte.
  1171. bs->AppendChars(_u('%'));
  1172. bs->AppendChars(static_cast<char16>(_rgchHex[chw >> 4]));
  1173. bs->AppendChars(static_cast<char16>(_rgchHex[chw & 0x0F]));
  1174. }
  1175. else
  1176. {
  1177. bs->AppendChars(chw);
  1178. }
  1179. }
  1180. LEAVE_PINNED_SCOPE(); // src
  1181. return bs;
  1182. }
  1183. //
  1184. // Part of Appendix B of ES5 spec
  1185. //
  1186. Var GlobalObject::EntryUnEscape(RecyclableObject* function, CallInfo callInfo, ...)
  1187. {
  1188. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1189. ARGUMENTS(args, callInfo);
  1190. ScriptContext* scriptContext = function->GetScriptContext();
  1191. Assert(!(callInfo.Flags & CallFlags_New));
  1192. if (args.Info.Count <= 1)
  1193. {
  1194. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  1195. }
  1196. char16 chw;
  1197. char16 chT;
  1198. char16 * pchSrc;
  1199. char16 * pchLim;
  1200. char16 * pchMin;
  1201. CompoundString * bs = nullptr;
  1202. ENTER_PINNED_SCOPE(JavascriptString, src);
  1203. src = JavascriptConversion::ToString(args[1], scriptContext);
  1204. bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
  1205. pchSrc = const_cast<char16 *>(src->GetString());
  1206. pchLim = pchSrc + src->GetLength();
  1207. while (pchSrc < pchLim)
  1208. {
  1209. if ('%' != (chT = *pchSrc++))
  1210. {
  1211. bs->AppendChars(chT);
  1212. continue;
  1213. }
  1214. pchMin = pchSrc;
  1215. chT = *pchSrc++;
  1216. if ('u' != chT)
  1217. {
  1218. chw = 0;
  1219. goto LTwoHexDigits;
  1220. }
  1221. // 4 hex digits.
  1222. if ((chT = *pchSrc++ - '0') <= 9)
  1223. chw = chT * 0x1000;
  1224. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1225. chw = (chT + 10) * 0x1000;
  1226. else
  1227. goto LHexError;
  1228. if ((chT = *pchSrc++ - '0') <= 9)
  1229. chw += chT * 0x0100;
  1230. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1231. chw += (chT + 10) * 0x0100;
  1232. else
  1233. goto LHexError;
  1234. chT = *pchSrc++;
  1235. LTwoHexDigits:
  1236. if ((chT -= '0') <= 9)
  1237. chw += chT * 0x0010;
  1238. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1239. chw += (chT + 10) * 0x0010;
  1240. else
  1241. goto LHexError;
  1242. if ((chT = *pchSrc++ - '0') <= 9)
  1243. chw += chT;
  1244. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1245. chw += chT + 10;
  1246. else
  1247. {
  1248. LHexError:
  1249. pchSrc = pchMin;
  1250. chw = '%';
  1251. }
  1252. bs->AppendChars(chw);
  1253. }
  1254. LEAVE_PINNED_SCOPE(); // src
  1255. return bs;
  1256. }
  1257. #if DBG
  1258. void DebugClearStack()
  1259. {
  1260. char buffer[1024];
  1261. memset(buffer, 0, sizeof(buffer));
  1262. }
  1263. #endif
  1264. Var GlobalObject::EntryCollectGarbage(RecyclableObject* function, CallInfo callInfo, ...)
  1265. {
  1266. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1267. #if DBG_DUMP
  1268. if (Js::Configuration::Global.flags.TraceWin8Allocations)
  1269. {
  1270. Output::Print(_u("MemoryTrace: GlobalObject::EntryCollectGarbage Invoke\n"));
  1271. Output::Flush();
  1272. }
  1273. #endif
  1274. #if DBG
  1275. // Clear 1K of stack to avoid false positive in debug build.
  1276. // Because we don't debug build don't stack pack
  1277. DebugClearStack();
  1278. #endif
  1279. Assert(!(callInfo.Flags & CallFlags_New));
  1280. ScriptContext* scriptContext = function->GetScriptContext();
  1281. Recycler* recycler = scriptContext->GetRecycler();
  1282. if (recycler)
  1283. {
  1284. #if DBG && defined(RECYCLER_DUMP_OBJECT_GRAPH)
  1285. ARGUMENTS(args, callInfo);
  1286. if (args.Info.Count > 1)
  1287. {
  1288. double value = JavascriptConversion::ToNumber(args[1], function->GetScriptContext());
  1289. if (value == 1.0)
  1290. {
  1291. recycler->dumpObjectOnceOnCollect = true;
  1292. }
  1293. }
  1294. #endif
  1295. recycler->CollectNow<CollectNowDecommitNowExplicit>();
  1296. }
  1297. #if DBG_DUMP
  1298. if (Js::Configuration::Global.flags.TraceWin8Allocations)
  1299. {
  1300. Output::Print(_u("MemoryTrace: GlobalObject::EntryCollectGarbage Exit\n"));
  1301. Output::Flush();
  1302. }
  1303. #endif
  1304. return scriptContext->GetLibrary()->GetUndefined();
  1305. }
  1306. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1307. Var GlobalObject::EntryChWriteTraceEvent(RecyclableObject *function, CallInfo callInfo, ...)
  1308. {
  1309. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1310. ARGUMENTS(args, callInfo);
  1311. if (args.Info.Count < 2)
  1312. {
  1313. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1314. }
  1315. JS_ETW(EventWriteJSCRIPT_INTERNAL_GENERIC_EVENT(Js::JavascriptConversion::ToString(args[1], function->GetScriptContext())->GetSz()));
  1316. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1317. }
  1318. #endif
  1319. #if ENABLE_TTD
  1320. //Log a string in the telemetry system (and print to the console)
  1321. Var GlobalObject::EntryTelemetryLog(RecyclableObject* function, CallInfo callInfo, ...)
  1322. {
  1323. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1324. ARGUMENTS(args, callInfo);
  1325. TTDAssert(args.Info.Count >= 2 && Js::VarIs<Js::JavascriptString>(args[1]), "Bad arguments!!!");
  1326. Js::JavascriptString* jsString = Js::VarTo<Js::JavascriptString>(args[1]);
  1327. bool doPrint = (args.Info.Count == 3) && Js::VarIs<Js::JavascriptBoolean>(args[2]) && (Js::VarTo<Js::JavascriptBoolean>(args[2])->GetValue());
  1328. if(function->GetScriptContext()->ShouldPerformReplayAction())
  1329. {
  1330. function->GetScriptContext()->GetThreadContext()->TTDLog->ReplayTelemetryLogEvent(jsString);
  1331. }
  1332. if(function->GetScriptContext()->ShouldPerformRecordAction())
  1333. {
  1334. function->GetScriptContext()->GetThreadContext()->TTDLog->RecordTelemetryLogEvent(jsString, doPrint);
  1335. }
  1336. if(doPrint)
  1337. {
  1338. //
  1339. //TODO: the host should give us a print callback which we can use here
  1340. //
  1341. Output::Print(_u("%ls\n"), jsString->GetSz());
  1342. fflush(stdout);
  1343. }
  1344. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1345. }
  1346. //Check if diagnostic trace writing is enabled
  1347. Var GlobalObject::EntryEnabledDiagnosticsTrace(RecyclableObject* function, CallInfo callInfo, ...)
  1348. {
  1349. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1350. ARGUMENTS(args, callInfo);
  1351. if (function->GetScriptContext()->ShouldPerformReplayAction())
  1352. {
  1353. TTD::EventLog* ttlog = function->GetScriptContext()->GetThreadContext()->TTDLog;
  1354. bool isEnabled = ttlog->ReplayTTDFetchAutoTraceStatusLogEvent();
  1355. return function->GetScriptContext()->GetLibrary()->CreateBoolean(isEnabled);
  1356. }
  1357. else if (function->GetScriptContext()->ShouldPerformRecordAction())
  1358. {
  1359. TTD::EventLog* ttlog = function->GetScriptContext()->GetThreadContext()->TTDLog;
  1360. bool isEnabled = ttlog->GetAutoTraceEnabled();
  1361. ttlog->RecordTTDFetchAutoTraceStatusEvent(isEnabled);
  1362. return function->GetScriptContext()->GetLibrary()->CreateBoolean(isEnabled);
  1363. }
  1364. else
  1365. {
  1366. return function->GetScriptContext()->GetLibrary()->GetFalse();
  1367. }
  1368. }
  1369. //Write a copy of the current TTD log to a specified location
  1370. Var GlobalObject::EntryEmitTTDLog(RecyclableObject* function, CallInfo callInfo, ...)
  1371. {
  1372. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1373. ARGUMENTS(args, callInfo);
  1374. Js::JavascriptLibrary* jslib = function->GetScriptContext()->GetLibrary();
  1375. if(args.Info.Count != 2 || !Js::VarIs<Js::JavascriptString>(args[1]))
  1376. {
  1377. return jslib->GetFalse();
  1378. }
  1379. if(function->GetScriptContext()->ShouldPerformReplayAction())
  1380. {
  1381. function->GetScriptContext()->GetThreadContext()->TTDLog->ReplayEmitLogEvent();
  1382. return jslib->GetTrue();
  1383. }
  1384. if(function->GetScriptContext()->ShouldPerformRecordAction())
  1385. {
  1386. Js::JavascriptString* jsString = Js::VarTo<Js::JavascriptString>(args[1]);
  1387. function->GetScriptContext()->GetThreadContext()->TTDLog->RecordEmitLogEvent(jsString);
  1388. return jslib->GetTrue();
  1389. }
  1390. return jslib->GetFalse();
  1391. }
  1392. #endif
  1393. //Pattern match is unique to RuntimeObject. Only leading and trailing * are implemented
  1394. //Example: *pat*tern* actually matches all the strings having pat*tern as substring.
  1395. BOOL GlobalObject::MatchPatternHelper(JavascriptString *propertyName, JavascriptString *pattern, ScriptContext *scriptContext)
  1396. {
  1397. if (nullptr == propertyName || nullptr == pattern)
  1398. {
  1399. return FALSE;
  1400. }
  1401. charcount_t patternLength = pattern->GetLength();
  1402. charcount_t nameLength = propertyName->GetLength();
  1403. BOOL bStart;
  1404. BOOL bEnd;
  1405. if (0 == patternLength)
  1406. {
  1407. return TRUE; // empty pattern matches all
  1408. }
  1409. bStart = (_u('*') == pattern->GetItem(0));// Is there a start star?
  1410. bEnd = (_u('*') == pattern->GetItem(patternLength - 1));// Is there an end star?
  1411. //deal with the stars
  1412. if (bStart || bEnd)
  1413. {
  1414. JavascriptString *subPattern;
  1415. int idxStart = bStart? 1: 0;
  1416. int idxEnd = bEnd? (patternLength - 1): patternLength;
  1417. if (idxEnd <= idxStart)
  1418. {
  1419. return TRUE; //scenario double star **
  1420. }
  1421. //get a pattern which doesn't contain leading and trailing stars
  1422. subPattern = VarTo<JavascriptString>(JavascriptString::SubstringCore(pattern, idxStart, idxEnd - idxStart, scriptContext));
  1423. uint index = JavascriptString::strstr(propertyName, subPattern, false);
  1424. if (index == (uint)-1)
  1425. {
  1426. return FALSE;
  1427. }
  1428. if (FALSE == bStart)
  1429. {
  1430. return index == 0; //begin at the same place;
  1431. }
  1432. else if (FALSE == bEnd)
  1433. {
  1434. return (index + patternLength - 1) == (nameLength);
  1435. }
  1436. return TRUE;
  1437. }
  1438. else
  1439. {
  1440. //full match
  1441. if (0 == JavascriptString::strcmp(propertyName, pattern))
  1442. {
  1443. return TRUE;
  1444. }
  1445. }
  1446. return FALSE;
  1447. }
  1448. PropertyQueryFlags GlobalObject::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
  1449. {
  1450. return JavascriptConversion::BooleanToPropertyQueryFlags(JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, info)) ||
  1451. (this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject, propertyId)) ||
  1452. (this->hostObject && JavascriptOperators::HasProperty(this->hostObject, propertyId)));
  1453. }
  1454. BOOL GlobalObject::HasRootProperty(PropertyId propertyId)
  1455. {
  1456. return __super::HasRootProperty(propertyId) ||
  1457. (this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject, propertyId)) ||
  1458. (this->hostObject && JavascriptOperators::HasProperty(this->hostObject, propertyId));
  1459. }
  1460. BOOL GlobalObject::HasOwnProperty(PropertyId propertyId)
  1461. {
  1462. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, nullptr /*info*/)) ||
  1463. (this->directHostObject && this->directHostObject->HasProperty(propertyId));
  1464. }
  1465. BOOL GlobalObject::HasOwnPropertyNoHostObject(PropertyId propertyId)
  1466. {
  1467. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, nullptr /*info*/));
  1468. }
  1469. PropertyQueryFlags GlobalObject::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1470. {
  1471. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext)))
  1472. {
  1473. return PropertyQueryFlags::Property_Found;
  1474. }
  1475. return JavascriptConversion::BooleanToPropertyQueryFlags((this->directHostObject && JavascriptOperators::GetProperty(this->directHostObject, propertyId, value, requestContext, info)) ||
  1476. (this->hostObject && JavascriptOperators::GetProperty(this->hostObject, propertyId, value, requestContext, info)));
  1477. }
  1478. PropertyQueryFlags GlobalObject::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1479. {
  1480. PropertyRecord const* propertyRecord;
  1481. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  1482. return GlobalObject::GetPropertyQuery(originalInstance, propertyRecord->GetPropertyId(), value, info, requestContext);
  1483. }
  1484. BOOL GlobalObject::GetRootProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1485. {
  1486. if (__super::GetRootProperty(originalInstance, propertyId, value, info, requestContext))
  1487. {
  1488. return TRUE;
  1489. }
  1490. return (this->directHostObject && JavascriptOperators::GetProperty(this->directHostObject, propertyId, value, requestContext, info)) ||
  1491. (this->hostObject && JavascriptOperators::GetProperty(this->hostObject, propertyId, value, requestContext, info));
  1492. }
  1493. _Check_return_ _Success_(return) BOOL GlobalObject::GetAccessors(PropertyId propertyId, _Outptr_result_maybenull_ Var* getter, _Outptr_result_maybenull_ Var* setter, ScriptContext* requestContext)
  1494. {
  1495. if (DynamicObject::GetAccessors(propertyId, getter, setter, requestContext))
  1496. {
  1497. return TRUE;
  1498. }
  1499. if (this->directHostObject)
  1500. {
  1501. return this->directHostObject->GetAccessors(propertyId, getter, setter, requestContext);
  1502. }
  1503. else if (this->hostObject)
  1504. {
  1505. return this->hostObject->GetAccessors(propertyId, getter, setter, requestContext);
  1506. }
  1507. return FALSE;
  1508. }
  1509. PropertyQueryFlags GlobalObject::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info,
  1510. ScriptContext* requestContext)
  1511. {
  1512. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyReferenceQuery(originalInstance, propertyId, value, info, requestContext)))
  1513. {
  1514. return PropertyQueryFlags::Property_Found;
  1515. }
  1516. return JavascriptConversion::BooleanToPropertyQueryFlags((this->directHostObject && JavascriptOperators::GetPropertyReference(this->directHostObject, propertyId, value, requestContext, info)) ||
  1517. (this->hostObject && JavascriptOperators::GetPropertyReference(this->hostObject, propertyId, value, requestContext, info)));
  1518. }
  1519. BOOL GlobalObject::GetRootPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info,
  1520. ScriptContext* requestContext)
  1521. {
  1522. if (__super::GetRootPropertyReference(originalInstance, propertyId, value, info, requestContext))
  1523. {
  1524. return true;
  1525. }
  1526. return (this->directHostObject && JavascriptOperators::GetPropertyReference(this->directHostObject, propertyId, value, requestContext, info)) ||
  1527. (this->hostObject && JavascriptOperators::GetPropertyReference(this->hostObject, propertyId, value, requestContext, info));
  1528. }
  1529. BOOL GlobalObject::InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1530. {
  1531. // var x = 10; variables declared with "var" at global scope
  1532. // These cannot be deleted
  1533. // In ES5 they are enumerable.
  1534. PropertyAttributes attributes = PropertyWritable | PropertyEnumerable | PropertyDeclaredGlobal;
  1535. flags = static_cast<PropertyOperationFlags>(flags | PropertyOperation_ThrowIfNotExtensible);
  1536. return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info, flags);
  1537. }
  1538. BOOL GlobalObject::InitPropertyInEval(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1539. {
  1540. // This is var/function declared inside the 'eval'
  1541. PropertyAttributes attributes = PropertyDynamicTypeDefaults | PropertyDeclaredGlobal;
  1542. flags = static_cast<PropertyOperationFlags>(flags | PropertyOperation_ThrowIfNotExtensible);
  1543. return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info, flags);
  1544. }
  1545. BOOL GlobalObject::InitPropertyScoped(PropertyId propertyId, Var value)
  1546. {
  1547. // var x = 10; variables declared with "var" inside "eval"
  1548. // These CAN be deleted
  1549. // in ES5 they are enumerable.
  1550. //
  1551. PropertyAttributes attributes = PropertyDynamicTypeDefaults | PropertyDeclaredGlobal;
  1552. return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, NULL, PropertyOperation_ThrowIfNotExtensible);
  1553. }
  1554. BOOL GlobalObject::InitFuncScoped(PropertyId propertyId, Var value)
  1555. {
  1556. // Var binding of functions declared in eval are elided when conflicting
  1557. // with global scope let/const variables, so do not actually set the
  1558. // property if it exists and is a let/const variable.
  1559. bool noRedecl = false;
  1560. if (!GetTypeHandler()->HasRootProperty(this, propertyId, &noRedecl) || !noRedecl)
  1561. {
  1562. //
  1563. // var x = 10; variables declared with "var" inside "eval"
  1564. // These CAN be deleted
  1565. // in ES5 they are enumerable.
  1566. PropertyAttributes attributes = PropertyDynamicTypeDefaults;
  1567. DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, NULL, PropertyOperation_ThrowIfNotExtensible);
  1568. }
  1569. return true;
  1570. }
  1571. BOOL GlobalObject::SetExistingProperty(PropertyId propertyId, Var value, PropertyValueInfo* info, BOOL *setAttempted)
  1572. {
  1573. BOOL hasOwnProperty = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, nullptr /*info*/));
  1574. BOOL hasProperty = JavascriptOperators::HasProperty(this->GetPrototype(), propertyId);
  1575. *setAttempted = TRUE;
  1576. if (this->directHostObject &&
  1577. !hasOwnProperty &&
  1578. !hasProperty &&
  1579. this->directHostObject->HasProperty(propertyId))
  1580. {
  1581. // directHostObject->HasProperty returns true for things in global collections, however, they are not able to be set.
  1582. // When we call SetProperty we'll return FALSE which means fall back to GlobalObject::SetProperty and shadow our collection
  1583. // object rather than failing the set altogether. See bug Windows Out Of Band Releases 1144780 and linked bugs for details.
  1584. if (this->directHostObject->SetProperty(propertyId, value, PropertyOperation_None, info))
  1585. {
  1586. return TRUE;
  1587. }
  1588. }
  1589. else
  1590. if (this->hostObject &&
  1591. // Consider to revert to the commented line and ignore the prototype chain when direct host is on by default in IE9 mode
  1592. !hasOwnProperty &&
  1593. !hasProperty &&
  1594. this->hostObject->HasProperty(propertyId))
  1595. {
  1596. return this->hostObject->SetProperty(propertyId, value, PropertyOperation_None, NULL);
  1597. }
  1598. if (hasOwnProperty || hasProperty)
  1599. {
  1600. return DynamicObject::SetProperty(propertyId, value, PropertyOperation_None, info);
  1601. }
  1602. *setAttempted = FALSE;
  1603. return FALSE;
  1604. }
  1605. BOOL GlobalObject::SetExistingRootProperty(PropertyId propertyId, Var value, PropertyValueInfo* info, BOOL *setAttempted)
  1606. {
  1607. BOOL hasOwnProperty = __super::HasRootProperty(propertyId);
  1608. BOOL hasProperty = JavascriptOperators::HasProperty(this->GetPrototype(), propertyId);
  1609. *setAttempted = TRUE;
  1610. if (this->directHostObject &&
  1611. !hasOwnProperty &&
  1612. !hasProperty &&
  1613. this->directHostObject->HasProperty(propertyId))
  1614. {
  1615. // directHostObject->HasProperty returns true for things in global collections, however, they are not able to be set.
  1616. // When we call SetProperty we'll return FALSE which means fall back to GlobalObject::SetProperty and shadow our collection
  1617. // object rather than failing the set altogether. See bug Windows Out Of Band Releases 1144780 and linked bugs for details.
  1618. if (this->directHostObject->SetProperty(propertyId, value, PropertyOperation_None, info))
  1619. {
  1620. return TRUE;
  1621. }
  1622. }
  1623. else
  1624. if (this->hostObject &&
  1625. // Consider to revert to the commented line and ignore the prototype chain when direct host is on by default in IE9 mode
  1626. !hasOwnProperty &&
  1627. !hasProperty &&
  1628. this->hostObject->HasProperty(propertyId))
  1629. {
  1630. return this->hostObject->SetProperty(propertyId, value, PropertyOperation_None, NULL);
  1631. }
  1632. if (hasOwnProperty || hasProperty)
  1633. {
  1634. return __super::SetRootProperty(propertyId, value, PropertyOperation_None, info);
  1635. }
  1636. *setAttempted = FALSE;
  1637. return FALSE;
  1638. }
  1639. BOOL GlobalObject::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1640. {
  1641. Assert(!(flags & PropertyOperation_Root));
  1642. BOOL setAttempted = TRUE;
  1643. if (this->SetExistingProperty(propertyId, value, info, &setAttempted))
  1644. {
  1645. return TRUE;
  1646. }
  1647. //
  1648. // Set was attempted. But the set operation returned false.
  1649. // This happens, when the property is read only.
  1650. // In those scenarios, we should be setting the property with default attributes
  1651. //
  1652. if (setAttempted)
  1653. {
  1654. return FALSE;
  1655. }
  1656. // Windows 8 430092: When we set a new property on globalObject there may be stale inline caches holding onto directHostObject->prototype
  1657. // properties of the same name. So we need to clear proto caches in this scenario. But check for same property in directHostObject->prototype
  1658. // chain is expensive (call to DOM) compared to just invalidating the cache.
  1659. // If this blind invalidation is expensive in any scenario then we need to revisit this.
  1660. // Another solution proposed was not to cache any of the properties of window->directHostObject->prototype.
  1661. // if ((this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject->GetPrototype(), propertyId)) ||
  1662. // (this->hostObject && JavascriptOperators::HasProperty(this->hostObject->GetPrototype(), propertyId)))
  1663. this->GetScriptContext()->InvalidateProtoCaches(propertyId);
  1664. //
  1665. // x = 10; implicit/phantom variable at global scope
  1666. // These CAN be deleted
  1667. // In ES5 they are enumerable.
  1668. PropertyAttributes attributes = PropertyDynamicTypeDefaults;
  1669. return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info);
  1670. }
  1671. BOOL GlobalObject::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1672. {
  1673. PropertyRecord const * propertyRecord;
  1674. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  1675. return GlobalObject::SetProperty(propertyRecord->GetPropertyId(), value, flags, info);
  1676. }
  1677. BOOL GlobalObject::SetRootProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1678. {
  1679. Assert(flags & PropertyOperation_Root);
  1680. BOOL setAttempted = TRUE;
  1681. if (this->SetExistingRootProperty(propertyId, value, info, &setAttempted))
  1682. {
  1683. return TRUE;
  1684. }
  1685. //
  1686. // Set was attempted. But the set operation returned false.
  1687. // This happens, when the property is read only.
  1688. // In those scenarios, we should be setting the property with default attributes
  1689. //
  1690. if (setAttempted)
  1691. {
  1692. return FALSE;
  1693. }
  1694. if (flags & PropertyOperation_StrictMode)
  1695. {
  1696. if (!GetScriptContext()->GetThreadContext()->RecordImplicitException())
  1697. {
  1698. return FALSE;
  1699. }
  1700. JavascriptError::ThrowReferenceError(GetScriptContext(), JSERR_RefErrorUndefVariable);
  1701. }
  1702. // Windows 8 430092: When we set a new property on globalObject there may be stale inline caches holding onto directHostObject->prototype
  1703. // properties of the same name. So we need to clear proto caches in this scenario. But check for same property in directHostObject->prototype
  1704. // chain is expensive (call to DOM) compared to just invalidating the cache.
  1705. // If this blind invalidation is expensive in any scenario then we need to revisit this.
  1706. // Another solution proposed was not to cache any of the properties of window->directHostObject->prototype.
  1707. // if ((this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject->GetPrototype(), propertyId)) ||
  1708. // (this->hostObject && JavascriptOperators::HasProperty(this->hostObject->GetPrototype(), propertyId)))
  1709. this->GetScriptContext()->InvalidateProtoCaches(propertyId);
  1710. return __super::SetRootProperty(propertyId, value, flags, info);
  1711. }
  1712. BOOL GlobalObject::SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
  1713. {
  1714. if (DynamicObject::SetAccessors(propertyId, getter, setter, flags))
  1715. {
  1716. return TRUE;
  1717. }
  1718. if (this->directHostObject)
  1719. {
  1720. return this->directHostObject->SetAccessors(propertyId, getter, setter, flags);
  1721. }
  1722. if (this->hostObject)
  1723. {
  1724. return this->hostObject->SetAccessors(propertyId, getter, setter, flags);
  1725. }
  1726. return TRUE;
  1727. }
  1728. DescriptorFlags GlobalObject::GetSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1729. {
  1730. DescriptorFlags flags = DynamicObject::GetSetter(propertyId, setterValue, info, requestContext);
  1731. if (flags == None)
  1732. {
  1733. if (this->directHostObject)
  1734. {
  1735. // We need to look up the prototype chain here.
  1736. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->directHostObject, propertyId, setterValue, &flags, info, requestContext);
  1737. }
  1738. else if (this->hostObject)
  1739. {
  1740. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->hostObject, propertyId, setterValue, &flags, info, requestContext);
  1741. }
  1742. }
  1743. return flags;
  1744. }
  1745. DescriptorFlags GlobalObject::GetSetter(JavascriptString* propertyNameString, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1746. {
  1747. PropertyRecord const* propertyRecord;
  1748. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  1749. return GlobalObject::GetSetter(propertyRecord->GetPropertyId(), setterValue, info, requestContext);
  1750. }
  1751. DescriptorFlags GlobalObject::GetRootSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1752. {
  1753. DescriptorFlags flags = __super::GetRootSetter(propertyId, setterValue, info, requestContext);
  1754. if (flags == None)
  1755. {
  1756. if (this->directHostObject)
  1757. {
  1758. // We need to look up the prototype chain here.
  1759. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->directHostObject, propertyId, setterValue, &flags, info, requestContext);
  1760. }
  1761. else if (this->hostObject)
  1762. {
  1763. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->hostObject, propertyId, setterValue, &flags, info, requestContext);
  1764. }
  1765. }
  1766. return flags;
  1767. }
  1768. DescriptorFlags GlobalObject::GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext)
  1769. {
  1770. DescriptorFlags flags = DynamicObject::GetItemSetter(index, setterValue, requestContext);
  1771. if (flags == None)
  1772. {
  1773. if (this->directHostObject)
  1774. {
  1775. // We need to look up the prototype chain here.
  1776. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableItem(this->directHostObject, index, setterValue, &flags, requestContext);
  1777. }
  1778. else if (this->hostObject)
  1779. {
  1780. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableItem(this->hostObject, index, setterValue, &flags, requestContext);
  1781. }
  1782. }
  1783. return flags;
  1784. }
  1785. BOOL GlobalObject::DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags)
  1786. {
  1787. if (JavascriptConversion::PropertyQueryFlagsToBoolean(__super::HasPropertyQuery(propertyId, nullptr /*info*/)))
  1788. {
  1789. return __super::DeleteProperty(propertyId, flags);
  1790. }
  1791. else if (this->directHostObject && this->directHostObject->HasProperty(propertyId))
  1792. {
  1793. return this->directHostObject->DeleteProperty(propertyId, flags);
  1794. }
  1795. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  1796. {
  1797. return this->hostObject->DeleteProperty(propertyId, flags);
  1798. }
  1799. // Non-existent property
  1800. return TRUE;
  1801. }
  1802. BOOL GlobalObject::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
  1803. {
  1804. PropertyRecord const *propertyRecord = nullptr;
  1805. if (JavascriptOperators::ShouldTryDeleteProperty(this, propertyNameString, &propertyRecord))
  1806. {
  1807. Assert(propertyRecord);
  1808. return DeleteProperty(propertyRecord->GetPropertyId(), flags);
  1809. }
  1810. return TRUE;
  1811. }
  1812. BOOL GlobalObject::DeleteRootProperty(PropertyId propertyId, PropertyOperationFlags flags)
  1813. {
  1814. if (__super::HasRootProperty(propertyId))
  1815. {
  1816. return __super::DeleteRootProperty(propertyId, flags);
  1817. }
  1818. else if (this->directHostObject && this->directHostObject->HasProperty(propertyId))
  1819. {
  1820. return this->directHostObject->DeleteProperty(propertyId, flags);
  1821. }
  1822. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  1823. {
  1824. return this->hostObject->DeleteProperty(propertyId, flags);
  1825. }
  1826. // Non-existent property
  1827. return TRUE;
  1828. }
  1829. PropertyQueryFlags GlobalObject::HasItemQuery(uint32 index)
  1830. {
  1831. return JavascriptConversion::BooleanToPropertyQueryFlags(JavascriptConversion::PropertyQueryFlagsToBoolean((DynamicObject::HasItemQuery(index)))
  1832. || (this->directHostObject && JavascriptOperators::HasItem(this->directHostObject, index))
  1833. || (this->hostObject && JavascriptOperators::HasItem(this->hostObject, index)));
  1834. }
  1835. BOOL GlobalObject::HasOwnItem(uint32 index)
  1836. {
  1837. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasItemQuery(index))
  1838. || (this->directHostObject && this->directHostObject->HasItem(index));
  1839. }
  1840. PropertyQueryFlags GlobalObject::GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext* requestContext)
  1841. {
  1842. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemReferenceQuery(originalInstance, index, value, requestContext)))
  1843. {
  1844. return PropertyQueryFlags::Property_Found;
  1845. }
  1846. return JavascriptConversion::BooleanToPropertyQueryFlags(
  1847. (this->directHostObject && JavascriptConversion::PropertyQueryFlagsToBoolean(this->directHostObject->GetItemReferenceQuery(originalInstance, index, value, requestContext))) ||
  1848. (this->hostObject && JavascriptConversion::PropertyQueryFlagsToBoolean(this->hostObject->GetItemReferenceQuery(originalInstance, index, value, requestContext))));
  1849. }
  1850. BOOL GlobalObject::SetItem(uint32 index, Var value, PropertyOperationFlags flags)
  1851. {
  1852. BOOL result = DynamicObject::SetItem(index, value, flags);
  1853. return result;
  1854. }
  1855. PropertyQueryFlags GlobalObject::GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext* requestContext)
  1856. {
  1857. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemQuery(originalInstance, index, value, requestContext)))
  1858. {
  1859. return PropertyQueryFlags::Property_Found;
  1860. }
  1861. return JavascriptConversion::BooleanToPropertyQueryFlags((this->directHostObject && this->directHostObject->GetItem(originalInstance, index, value, requestContext)) ||
  1862. (this->hostObject && this->hostObject->GetItem(originalInstance, index, value, requestContext)));
  1863. }
  1864. BOOL GlobalObject::DeleteItem(uint32 index, PropertyOperationFlags flags)
  1865. {
  1866. if (DynamicObject::DeleteItem(index, flags))
  1867. {
  1868. return TRUE;
  1869. }
  1870. if (this->directHostObject)
  1871. {
  1872. return this->directHostObject->DeleteItem(index, flags);
  1873. }
  1874. if (this->hostObject)
  1875. {
  1876. return this->hostObject->DeleteItem(index, flags);
  1877. }
  1878. return FALSE;
  1879. }
  1880. BOOL GlobalObject::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1881. {
  1882. stringBuilder->AppendCppLiteral(_u("{...}"));
  1883. return TRUE;
  1884. }
  1885. BOOL GlobalObject::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1886. {
  1887. stringBuilder->AppendCppLiteral(_u("Object, (Global)"));
  1888. return TRUE;
  1889. }
  1890. BOOL GlobalObject::StrictEquals(__in Js::Var other, __out BOOL* value, ScriptContext * requestContext)
  1891. {
  1892. if (this == other)
  1893. {
  1894. *value = TRUE;
  1895. return TRUE;
  1896. }
  1897. else if (this->directHostObject)
  1898. {
  1899. return this->directHostObject->StrictEquals(other, value, requestContext);
  1900. }
  1901. else if (this->hostObject)
  1902. {
  1903. return this->hostObject->StrictEquals(other, value, requestContext);
  1904. }
  1905. *value = FALSE;
  1906. return FALSE;
  1907. }
  1908. BOOL GlobalObject::Equals(__in Js::Var other, __out BOOL* value, ScriptContext * requestContext)
  1909. {
  1910. if (this == other)
  1911. {
  1912. *value = TRUE;
  1913. return TRUE;
  1914. }
  1915. else if (this->directHostObject)
  1916. {
  1917. return this->directHostObject->Equals(other, value, requestContext);
  1918. }
  1919. else if (this->hostObject)
  1920. {
  1921. return this->hostObject->Equals(other, value, requestContext);
  1922. }
  1923. *value = FALSE;
  1924. return TRUE;
  1925. }
  1926. #if ENABLE_TTD
  1927. TTD::NSSnapObjects::SnapObjectType GlobalObject::GetSnapTag_TTD() const
  1928. {
  1929. return TTD::NSSnapObjects::SnapObjectType::SnapWellKnownObject;
  1930. }
  1931. void GlobalObject::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  1932. {
  1933. //
  1934. //TODO: we assume that the global object is always set right (e.g., ignore the directHostObject and secureDirectHostObject values) we need to verify that this is ok and/or what to do about it
  1935. //
  1936. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<void*, TTD::NSSnapObjects::SnapObjectType::SnapWellKnownObject>(objData, nullptr);
  1937. }
  1938. #endif