GlobalObject.cpp 90 KB

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