GlobalObject.cpp 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332
  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 (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(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. ScriptFunction *pfuncScript = nullptr;
  493. ENTER_PINNED_SCOPE(JavascriptString, argString);
  494. argString = JavascriptString::FromVar(evalArg);
  495. char16 const * sourceString = argString->GetSz();
  496. charcount_t sourceLen = argString->GetLength();
  497. FastEvalMapString key(sourceString, sourceLen, moduleID, strictMode, isLibraryCode);
  498. bool found = scriptContext->IsInEvalMap(key, isIndirect, &pfuncScript);
  499. if (!found || (!isIndirect && pfuncScript->GetEnvironment() != &NullFrameDisplay))
  500. {
  501. uint32 grfscr = additionalGrfscr | fscrReturnExpression | fscrEval | fscrEvalCode | fscrGlobalCode;
  502. if (isLibraryCode)
  503. {
  504. grfscr |= fscrIsLibraryCode;
  505. }
  506. pfuncScript = library->GetGlobalObject()->EvalHelper(scriptContext, argString->GetSz(), argString->GetLength(), moduleID,
  507. grfscr, Constants::EvalCode, doRegisterDocument, isIndirect, strictMode);
  508. if (!found)
  509. {
  510. scriptContext->AddToEvalMap(key, isIndirect, pfuncScript);
  511. }
  512. }
  513. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  514. else
  515. {
  516. Js::Utf8SourceInfo* utf8SourceInfo = pfuncScript->GetFunctionBody()->GetUtf8SourceInfo();
  517. if (scriptContext->IsScriptContextInDebugMode() && !utf8SourceInfo->GetIsLibraryCode() && !utf8SourceInfo->IsInDebugMode())
  518. {
  519. // Identifying if any non library function escaped for not being in debug mode.
  520. Throw::FatalInternalError();
  521. }
  522. }
  523. #endif
  524. #if ENABLE_TTD
  525. //
  526. //TODO: We may (probably?) want to use the debugger source rundown functionality here instead
  527. //
  528. if(!isLibraryCode && pfuncScript != nullptr && (scriptContext->IsTTDRecordModeEnabled() || scriptContext->ShouldPerformReplayAction()))
  529. {
  530. //Make sure we have the body and text information available
  531. FunctionBody* globalBody = TTD::JsSupport::ForceAndGetFunctionBody(pfuncScript->GetParseableFunctionInfo());
  532. if(!scriptContext->TTDContextInfo->IsBodyAlreadyLoadedAtTopLevel(globalBody))
  533. {
  534. uint32 bodyIdCtr = 0;
  535. if(scriptContext->IsTTDRecordModeEnabled())
  536. {
  537. const TTD::NSSnapValues::TopLevelEvalFunctionBodyResolveInfo* tbfi = scriptContext->GetThreadContext()->TTDLog->AddEvalFunction(globalBody, moduleID, sourceString, sourceLen, additionalGrfscr, registerDocument, isIndirect, strictMode);
  538. //We always want to register the top-level load but we don't always need to log the event
  539. if(scriptContext->ShouldPerformRecordAction())
  540. {
  541. scriptContext->GetThreadContext()->TTDLog->RecordTopLevelCodeAction(tbfi->TopLevelBase.TopLevelBodyCtr);
  542. }
  543. bodyIdCtr = tbfi->TopLevelBase.TopLevelBodyCtr;
  544. }
  545. if(scriptContext->ShouldPerformReplayAction())
  546. {
  547. bodyIdCtr = scriptContext->GetThreadContext()->TTDLog->ReplayTopLevelCodeAction();
  548. }
  549. //walk global body to (1) add functions to pin set (2) build parent map
  550. scriptContext->TTDContextInfo->ProcessFunctionBodyOnLoad(globalBody, nullptr);
  551. scriptContext->TTDContextInfo->RegisterEvalScript(globalBody, bodyIdCtr);
  552. if(scriptContext->ShouldPerformRecordOrReplayAction())
  553. {
  554. globalBody->GetUtf8SourceInfo()->SetSourceInfoForDebugReplay_TTD(bodyIdCtr);
  555. }
  556. if(scriptContext->ShouldPerformDebuggerAction())
  557. {
  558. scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessScriptLoad(scriptContext, bodyIdCtr, globalBody, globalBody->GetUtf8SourceInfo(), nullptr);
  559. }
  560. }
  561. }
  562. #endif
  563. LEAVE_PINNED_SCOPE(); // argString
  564. //We shouldn't be serializing eval functions; unless with -ForceSerialized flag
  565. if (CONFIG_FLAG(ForceSerialized)) {
  566. pfuncScript->GetFunctionProxy()->EnsureDeserialized();
  567. }
  568. if (pfuncScript->GetFunctionBody()->GetHasThis())
  569. {
  570. // The eval expression refers to "this"
  571. if (args.Info.Flags & CallFlags_ExtraArg)
  572. {
  573. JavascriptFunction* pfuncCaller = nullptr;
  574. // 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.
  575. bool successful = false;
  576. if (JavascriptStackWalker::GetCaller(&pfuncCaller, scriptContext))
  577. {
  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. successful = true;
  585. }
  586. }
  587. if (!successful)
  588. {
  589. JavascriptStackWalker::GetThis(&varThis, moduleID, scriptContext);
  590. UpdateThisForEval(varThis, moduleID, scriptContext, strictMode);
  591. }
  592. }
  593. else
  594. {
  595. // The expression, which refers to "this", is evaluated by an indirect eval.
  596. // Set "this" to the current module root.
  597. varThis = JavascriptOperators::OP_GetThis(scriptContext->GetLibrary()->GetUndefined(), moduleID, scriptContext);
  598. }
  599. }
  600. if (pfuncScript->HasSuperReference())
  601. {
  602. // Indirect evals cannot have a super reference.
  603. if (!(args.Info.Flags & CallFlags_ExtraArg))
  604. {
  605. JavascriptError::ThrowSyntaxError(scriptContext, ERRSuperInIndirectEval, _u("super"));
  606. }
  607. }
  608. return library->GetGlobalObject()->ExecuteEvalParsedFunction(pfuncScript, environment, varThis, scriptContext);
  609. }
  610. void GlobalObject::UpdateThisForEval(Var &varThis, ModuleID moduleID, ScriptContext *scriptContext, BOOL strictMode)
  611. {
  612. if (strictMode)
  613. {
  614. varThis = JavascriptOperators::OP_StrictGetThis(varThis, scriptContext);
  615. }
  616. else
  617. {
  618. varThis = JavascriptOperators::OP_GetThisNoFastPath(varThis, moduleID, scriptContext);
  619. }
  620. }
  621. Var GlobalObject::ExecuteEvalParsedFunction(ScriptFunction *pfuncScript, FrameDisplay* environment, Var &varThis, ScriptContext *scriptContext)
  622. {
  623. Assert(pfuncScript != nullptr);
  624. pfuncScript->SetEnvironment(environment);
  625. //This function is supposed to be deserialized
  626. Assert(pfuncScript->GetFunctionBody());
  627. if (pfuncScript->GetFunctionBody()->GetFuncEscapes())
  628. {
  629. // Executing the eval causes the scope chain to escape.
  630. pfuncScript->InvalidateCachedScopeChain();
  631. }
  632. Var varResult = CALL_FUNCTION(scriptContext->GetThreadContext(), pfuncScript, CallInfo(CallFlags_Eval, 1), varThis);
  633. pfuncScript->SetEnvironment((FrameDisplay*)&NullFrameDisplay);
  634. return varResult;
  635. }
  636. #ifdef ENABLE_SCRIPT_PROFILING
  637. ScriptFunction* GlobalObject::ProfileModeEvalHelper(ScriptContext* scriptContext, const char16 *source, int sourceLength, ModuleID moduleID, uint32 grfscr, LPCOLESTR pszTitle, BOOL registerDocument, BOOL isIndirect, BOOL strictMode)
  638. {
  639. #if ENABLE_DEBUG_CONFIG_OPTIONS
  640. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  641. #endif
  642. ScriptFunction *pEvalFunction = DefaultEvalHelper(scriptContext, source, sourceLength, moduleID, grfscr, pszTitle, registerDocument, isIndirect, strictMode);
  643. Assert(pEvalFunction);
  644. Js::FunctionProxy *proxy = pEvalFunction->GetFunctionProxy();
  645. Assert(proxy);
  646. OUTPUT_TRACE(Js::ScriptProfilerPhase, _u("GlobalObject::ProfileModeEvalHelper FunctionNumber : %s, Entrypoint : 0x%08X IsFunctionDefer : %d\n"),
  647. proxy->GetDebugNumberSet(debugStringBuffer), pEvalFunction->GetEntryPoint(), proxy->IsDeferred());
  648. if (proxy->IsDeferred())
  649. {
  650. // 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)
  651. Js::JavascriptFunction::DeferredParse(&pEvalFunction);
  652. proxy = pEvalFunction->GetFunctionProxy();
  653. }
  654. scriptContext->RegisterScript(proxy);
  655. return pEvalFunction;
  656. }
  657. #endif
  658. void GlobalObject::ValidateSyntax(ScriptContext* scriptContext, const char16 *source, int sourceLength, bool isGenerator, bool isAsync, void (Parser::*validateSyntax)())
  659. {
  660. Assert(sourceLength >= 0);
  661. HRESULT hr = S_OK;
  662. HRESULT hrParser = E_FAIL;
  663. CompileScriptException se;
  664. BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext);
  665. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
  666. {
  667. ArenaAllocator tempAlloc(_u("ValidateSyntaxArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Throw::OutOfMemory);
  668. size_t cchSource = sourceLength;
  669. size_t cbUtf8Buffer = UInt32Math::AddMul<1, 3>(sourceLength);
  670. LPUTF8 utf8Source = AnewArray(&tempAlloc, utf8char_t, cbUtf8Buffer);
  671. Assert(cchSource < MAXLONG);
  672. size_t cbSource = utf8::EncodeIntoAndNullTerminate(utf8Source, source, static_cast< charcount_t >(cchSource));
  673. utf8Source = reinterpret_cast< LPUTF8 >( tempAlloc.Realloc(utf8Source, cbUtf8Buffer, cbSource + 1) );
  674. Parser parser(scriptContext);
  675. hrParser = parser.ValidateSyntax(utf8Source, cbSource, isGenerator, isAsync, &se, validateSyntax);
  676. }
  677. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  678. END_LEAVE_SCRIPT_INTERNAL(scriptContext);
  679. if (FAILED(hr))
  680. {
  681. if (hr == E_OUTOFMEMORY)
  682. {
  683. JavascriptError::ThrowOutOfMemoryError(scriptContext);
  684. }
  685. if (hr == VBSERR_OutOfStack)
  686. {
  687. JavascriptError::ThrowStackOverflowError(scriptContext);
  688. }
  689. }
  690. if (!SUCCEEDED(hrParser))
  691. {
  692. hrParser = SCRIPT_E_RECORDED;
  693. EXCEPINFO ei;
  694. se.GetError(&hrParser, &ei);
  695. ErrorTypeEnum errorType;
  696. switch ((HRESULT)ei.scode)
  697. {
  698. #define RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) \
  699. case name: \
  700. errorType = jst; \
  701. break;
  702. #define RT_PUBLICERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource)
  703. #include "rterrors.h"
  704. #undef RT_PUBLICERROR_MSG
  705. #undef RT_ERROR_MSG
  706. default:
  707. errorType = kjstSyntaxError;
  708. }
  709. JavascriptError::MapAndThrowError(scriptContext, ei.scode, errorType, &ei);
  710. }
  711. }
  712. ScriptFunction* GlobalObject::DefaultEvalHelper(ScriptContext* scriptContext, const char16 *source, int sourceLength, ModuleID moduleID, uint32 grfscr, LPCOLESTR pszTitle, BOOL registerDocument, BOOL isIndirect, BOOL strictMode)
  713. {
  714. Assert(sourceLength >= 0);
  715. AnalysisAssert(scriptContext);
  716. if (scriptContext->GetThreadContext()->EvalDisabled())
  717. {
  718. throw Js::EvalDisabledException();
  719. }
  720. #ifdef PROFILE_EXEC
  721. scriptContext->ProfileBegin(Js::EvalCompilePhase);
  722. #endif
  723. void * frameAddr = nullptr;
  724. GET_CURRENT_FRAME_ID(frameAddr);
  725. HRESULT hr = S_OK;
  726. HRESULT hrParser = S_OK;
  727. HRESULT hrCodeGen = S_OK;
  728. CompileScriptException se;
  729. Js::ParseableFunctionInfo * funcBody = NULL;
  730. BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext);
  731. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
  732. {
  733. uint cchSource = sourceLength;
  734. size_t cbUtf8Buffer = UInt32Math::AddMul<1, 3>(cchSource);
  735. ArenaAllocator tempArena(_u("EvalHelperArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory);
  736. LPUTF8 utf8Source = AnewArray(&tempArena, utf8char_t, cbUtf8Buffer);
  737. Assert(cchSource < MAXLONG);
  738. size_t cbSource = utf8::EncodeIntoAndNullTerminate(utf8Source, source, static_cast< charcount_t >(cchSource));
  739. Assert(cbSource + 1 <= cbUtf8Buffer);
  740. SRCINFO const * pSrcInfo = scriptContext->GetModuleSrcInfo(moduleID);
  741. // Source Info objects are kept alive by the function bodies that are referencing it
  742. // The function body is created in GenerateByteCode but the source info isn't passed in, only the index
  743. // So we need to pin it here (TODO: Change GenerateByteCode to take in the sourceInfo itself)
  744. ENTER_PINNED_SCOPE(Utf8SourceInfo, sourceInfo);
  745. sourceInfo = Utf8SourceInfo::New(scriptContext, utf8Source, cchSource,
  746. cbSource, pSrcInfo, ((grfscr & fscrIsLibraryCode) != 0));
  747. Parser parser(scriptContext, strictMode);
  748. bool forceNoNative = false;
  749. ParseNodePtr parseTree = nullptr;
  750. SourceContextInfo * sourceContextInfo = pSrcInfo->sourceContextInfo;
  751. ULONG deferParseThreshold = Parser::GetDeferralThreshold(sourceContextInfo->IsSourceProfileLoaded());
  752. if ((ULONG)sourceLength > deferParseThreshold && !PHASE_OFF1(Phase::DeferParsePhase))
  753. {
  754. // Defer function bodies declared inside large dynamic blocks.
  755. grfscr |= fscrDeferFncParse;
  756. }
  757. grfscr = grfscr | fscrDynamicCode;
  758. // fscrEval signifies direct eval in parser
  759. hrParser = parser.ParseCesu8Source(&parseTree, utf8Source, cbSource, isIndirect ? grfscr & ~fscrEval : grfscr, &se, &sourceContextInfo->nextLocalFunctionId,
  760. sourceContextInfo);
  761. sourceInfo->SetParseFlags(grfscr);
  762. if (SUCCEEDED(hrParser) && parseTree)
  763. {
  764. // This keeps function bodies generated by the byte code alive till we return
  765. Js::AutoDynamicCodeReference dynamicFunctionReference(scriptContext);
  766. Assert(cchSource < MAXLONG);
  767. uint sourceIndex = scriptContext->SaveSourceNoCopy(sourceInfo, cchSource, true);
  768. // Tell byte code gen not to attempt to interact with the caller's context if this is indirect eval.
  769. // TODO: Handle strict mode.
  770. if (isIndirect &&
  771. !strictMode &&
  772. !parseTree->sxFnc.GetStrictMode())
  773. {
  774. grfscr &= ~fscrEval;
  775. }
  776. hrCodeGen = GenerateByteCode(parseTree, grfscr, scriptContext, &funcBody, sourceIndex, forceNoNative, &parser, &se);
  777. sourceInfo->SetByteCodeGenerationFlags(grfscr);
  778. }
  779. LEAVE_PINNED_SCOPE();
  780. }
  781. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  782. END_LEAVE_SCRIPT_INTERNAL(scriptContext);
  783. #ifdef PROFILE_EXEC
  784. scriptContext->ProfileEnd(Js::EvalCompilePhase);
  785. #endif
  786. THROW_KNOWN_HRESULT_EXCEPTIONS(hr, scriptContext);
  787. if (!SUCCEEDED(hrParser))
  788. {
  789. JavascriptError::ThrowParserError(scriptContext, hrParser, &se);
  790. }
  791. else if (!SUCCEEDED(hrCodeGen))
  792. {
  793. Assert(hrCodeGen == SCRIPT_E_RECORDED);
  794. hrCodeGen = se.ei.scode;
  795. /*
  796. * VBSERR_OutOfStack is of type kjstError but we throw a (more specific) StackOverflowError when a hard stack
  797. * overflow occurs. To keep the behavior consistent I'm special casing it here.
  798. */
  799. se.Free();
  800. if (hrCodeGen == VBSERR_OutOfStack)
  801. {
  802. JavascriptError::ThrowStackOverflowError(scriptContext);
  803. }
  804. else if (hrCodeGen == JSERR_AsmJsCompileError)
  805. {
  806. // if asm.js compilation succeeded, retry with asm.js disabled
  807. grfscr |= fscrNoAsmJs;
  808. return DefaultEvalHelper(scriptContext, source, sourceLength, moduleID, grfscr, pszTitle, registerDocument, isIndirect, strictMode);
  809. }
  810. JavascriptError::MapAndThrowError(scriptContext, hrCodeGen);
  811. }
  812. else
  813. {
  814. Assert(funcBody != nullptr);
  815. funcBody->SetDisplayName(pszTitle);
  816. // Set the functionbody information to dynamic content PROFILER_SCRIPT_TYPE_DYNAMIC
  817. funcBody->SetIsTopLevel(true);
  818. // If not library code then let's find the parent, we may need to register this source if any exception happens later
  819. if ((grfscr & fscrIsLibraryCode) == 0)
  820. {
  821. // For parented eval get the caller's utf8SourceInfo
  822. JavascriptFunction* pfuncCaller = nullptr;
  823. if (JavascriptStackWalker::GetCaller(&pfuncCaller, scriptContext) && pfuncCaller && pfuncCaller->IsScriptFunction())
  824. {
  825. FunctionBody* parentFuncBody = pfuncCaller->GetFunctionBody();
  826. Utf8SourceInfo* parentUtf8SourceInfo = parentFuncBody->GetUtf8SourceInfo();
  827. Utf8SourceInfo* utf8SourceInfo = funcBody->GetUtf8SourceInfo();
  828. utf8SourceInfo->SetCallerUtf8SourceInfo(parentUtf8SourceInfo);
  829. }
  830. }
  831. if (registerDocument)
  832. {
  833. funcBody->RegisterFuncToDiag(scriptContext, pszTitle);
  834. funcBody = funcBody->GetParseableFunctionInfo(); // RegisterFunction may parse and update function body
  835. }
  836. ScriptFunction* pfuncScript = funcBody->IsCoroutine() ?
  837. scriptContext->GetLibrary()->CreateGeneratorVirtualScriptFunction(funcBody) :
  838. scriptContext->GetLibrary()->CreateScriptFunction(funcBody);
  839. return pfuncScript;
  840. }
  841. }
  842. #ifdef IR_VIEWER
  843. Var GlobalObject::IRDumpEvalHelper(ScriptContext* scriptContext, const char16 *source,
  844. int sourceLength, ModuleID moduleID, uint32 grfscr, LPCOLESTR pszTitle,
  845. BOOL registerDocument, BOOL isIndirect, BOOL strictMode)
  846. {
  847. // TODO (t-doilij) clean up this function, specifically used for IR dump (don't execute bytecode; potentially dangerous)
  848. Assert(sourceLength >= 0);
  849. if (scriptContext->GetThreadContext()->EvalDisabled())
  850. {
  851. throw Js::EvalDisabledException();
  852. }
  853. #ifdef PROFILE_EXEC
  854. scriptContext->ProfileBegin(Js::EvalCompilePhase);
  855. #endif
  856. void * frameAddr = nullptr;
  857. GET_CURRENT_FRAME_ID(frameAddr);
  858. HRESULT hr = S_OK;
  859. HRESULT hrParser = S_OK;
  860. HRESULT hrCodeGen = S_OK;
  861. CompileScriptException se;
  862. Js::ParseableFunctionInfo * funcBody = NULL;
  863. BEGIN_LEAVE_SCRIPT_INTERNAL(scriptContext);
  864. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
  865. {
  866. size_t cchSource = sourceLength;
  867. size_t cbUtf8Buffer = UInt32Math::AddMul<1, 3>(sourceLength);
  868. ArenaAllocator tempArena(_u("EvalHelperArena"), scriptContext->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory);
  869. LPUTF8 utf8Source = AnewArray(&tempArena, utf8char_t, cbUtf8Buffer);
  870. Assert(cchSource < MAXLONG);
  871. size_t cbSource = utf8::EncodeIntoAndNullTerminate(utf8Source, source, static_cast< charcount_t >(cchSource));
  872. Assert(cbSource + 1 <= cbUtf8Buffer);
  873. SRCINFO const * pSrcInfo = scriptContext->GetModuleSrcInfo(moduleID);
  874. // Source Info objects are kept alive by the function bodies that are referencing it
  875. // The function body is created in GenerateByteCode but the source info isn't passed in, only the index
  876. // So we need to pin it here (TODO: Change GenerateByteCode to take in the sourceInfo itself)
  877. ENTER_PINNED_SCOPE(Utf8SourceInfo, sourceInfo);
  878. sourceInfo = Utf8SourceInfo::New(scriptContext, utf8Source, cchSource, cbSource, pSrcInfo, ((grfscr & fscrIsLibraryCode) != 0));
  879. Parser parser(scriptContext, strictMode);
  880. bool forceNoNative = false;
  881. ParseNodePtr parseTree = nullptr;
  882. SourceContextInfo * sourceContextInfo = pSrcInfo->sourceContextInfo;
  883. grfscr = grfscr | fscrDynamicCode;
  884. hrParser = parser.ParseCesu8Source(&parseTree, utf8Source, cbSource, grfscr, &se, &sourceContextInfo->nextLocalFunctionId,
  885. sourceContextInfo);
  886. sourceInfo->SetParseFlags(grfscr);
  887. if (SUCCEEDED(hrParser) && parseTree)
  888. {
  889. // This keeps function bodies generated by the byte code alive till we return
  890. Js::AutoDynamicCodeReference dynamicFunctionReference(scriptContext);
  891. Assert(cchSource < MAXLONG);
  892. uint sourceIndex = scriptContext->SaveSourceNoCopy(sourceInfo, cchSource, true);
  893. grfscr = grfscr | fscrIrDumpEnable;
  894. hrCodeGen = GenerateByteCode(parseTree, grfscr, scriptContext, &funcBody, sourceIndex, forceNoNative, &parser, &se);
  895. sourceInfo->SetByteCodeGenerationFlags(grfscr);
  896. }
  897. LEAVE_PINNED_SCOPE();
  898. }
  899. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  900. END_LEAVE_SCRIPT_INTERNAL(scriptContext);
  901. #ifdef PROFILE_EXEC
  902. scriptContext->ProfileEnd(Js::EvalCompilePhase);
  903. #endif
  904. THROW_KNOWN_HRESULT_EXCEPTIONS(hr);
  905. if (!SUCCEEDED(hrParser))
  906. {
  907. hrParser = SCRIPT_E_RECORDED;
  908. EXCEPINFO ei;
  909. se.GetError(&hrParser, &ei);
  910. ErrorTypeEnum errorType;
  911. switch ((HRESULT)ei.scode)
  912. {
  913. #define RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) \
  914. case name: \
  915. errorType = jst; \
  916. break;
  917. #define RT_PUBLICERROR_MSG(name, errnum, str1, str2, jst, errorNumSource) RT_ERROR_MSG(name, errnum, str1, str2, jst, errorNumSource)
  918. #include "rterrors.h"
  919. #undef RT_PUBLICERROR_MSG
  920. #undef RT_ERROR_MSG
  921. default:
  922. errorType = kjstSyntaxError;
  923. }
  924. JavascriptError::MapAndThrowError(scriptContext, ei.scode, errorType, &ei);
  925. }
  926. else if (!SUCCEEDED(hrCodeGen))
  927. {
  928. Assert(hrCodeGen == SCRIPT_E_RECORDED);
  929. hrCodeGen = se.ei.scode;
  930. /*
  931. * VBSERR_OutOfStack is of type kjstError but we throw a (more specific) StackOverflowError when a hard stack
  932. * overflow occurs. To keep the behavior consistent I'm special casing it here.
  933. */
  934. se.Free();
  935. if (hrCodeGen == VBSERR_OutOfStack)
  936. {
  937. JavascriptError::ThrowStackOverflowError(scriptContext);
  938. }
  939. JavascriptError::MapAndThrowError(scriptContext, hrCodeGen);
  940. }
  941. else
  942. {
  943. Assert(funcBody != nullptr);
  944. funcBody->SetDisplayName(pszTitle);
  945. // Set the functionbody information to dynamic content PROFILER_SCRIPT_TYPE_DYNAMIC
  946. funcBody->SetIsTopLevel(true);
  947. if (registerDocument)
  948. {
  949. funcBody->RegisterFuncToDiag(scriptContext, pszTitle);
  950. funcBody = funcBody->GetParseableFunctionInfo(); // RegisterFunction may parse and update function body
  951. }
  952. NativeCodeGenerator *nativeCodeGenerator = scriptContext->GetNativeCodeGenerator();
  953. Js::FunctionBody *functionBody = funcBody->GetFunctionBody(); // funcBody is ParseableFunctionInfo
  954. if (!functionBody || !functionBody->GetByteCode())
  955. {
  956. return scriptContext->GetLibrary()->GetUndefined();
  957. }
  958. Js::Var retVal = RejitIRViewerFunction(nativeCodeGenerator, functionBody, scriptContext);
  959. return retVal;
  960. }
  961. }
  962. #endif /* IR_VIEWER */
  963. Var GlobalObject::EntryParseInt(RecyclableObject* function, CallInfo callInfo, ...)
  964. {
  965. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  966. ARGUMENTS(args, callInfo);
  967. ScriptContext* scriptContext = function->GetScriptContext();
  968. Assert(!(callInfo.Flags & CallFlags_New));
  969. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  970. JavascriptString *str;
  971. int radix = 0;
  972. if(args.Info.Count < 2)
  973. {
  974. // We're really converting "undefined" here, but "undefined" produces
  975. // NaN, so just return that directly.
  976. return JavascriptNumber::ToVarNoCheck(JavascriptNumber::NaN, scriptContext);
  977. }
  978. // Short cut for numbers and radix 10
  979. if (((args.Info.Count == 2) ||
  980. (TaggedInt::Is(args[2]) && TaggedInt::ToInt32(args[2]) == 10) ||
  981. (JavascriptNumber::Is(args[2]) && JavascriptNumber::GetValue(args[2]) == 10)))
  982. {
  983. if (TaggedInt::Is(args[1]))
  984. {
  985. return args[1];
  986. }
  987. if (JavascriptNumber::Is(args[1]))
  988. {
  989. double value = JavascriptNumber::GetValue(args[1]);
  990. // make sure we are in the ranges that don't have exponential notation.
  991. double absValue = Math::Abs(value);
  992. if (absValue < 1.0e21 && absValue >= 1e-5)
  993. {
  994. double result;
  995. #pragma prefast(suppress:6031, "We don't care about the fraction part")
  996. ::modf(value, &result);
  997. return JavascriptNumber::ToVarIntCheck(result, scriptContext);
  998. }
  999. }
  1000. }
  1001. // convert input to a string
  1002. if (JavascriptString::Is(args[1]))
  1003. {
  1004. str = JavascriptString::FromVar(args[1]);
  1005. }
  1006. else
  1007. {
  1008. str = JavascriptConversion::ToString(args[1], scriptContext);
  1009. }
  1010. if(args.Info.Count > 2)
  1011. {
  1012. // retrieve the radix
  1013. // TODO : verify for ES5 : radix is 10 when undefined or 0, except when it starts with 0x when it is 16.
  1014. radix = JavascriptConversion::ToInt32(args[2], scriptContext);
  1015. if(radix < 0 || radix == 1 || radix > 36)
  1016. {
  1017. //illegal, return NaN
  1018. return JavascriptNumber::ToVarNoCheck(JavascriptNumber::NaN, scriptContext);
  1019. }
  1020. }
  1021. Var result = str->ToInteger(radix);
  1022. return result;
  1023. }
  1024. Var GlobalObject::EntryParseFloat(RecyclableObject* function, CallInfo callInfo, ...)
  1025. {
  1026. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1027. ARGUMENTS(args, callInfo);
  1028. ScriptContext* scriptContext = function->GetScriptContext();
  1029. Assert(!(callInfo.Flags & CallFlags_New));
  1030. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1031. double result = 0;
  1032. ENTER_PINNED_SCOPE(JavascriptString, str);
  1033. if(args.Info.Count < 2)
  1034. {
  1035. // We're really converting "undefined" here, but "undefined" produces
  1036. // NaN, so just return that directly.
  1037. return JavascriptNumber::ToVarNoCheck(JavascriptNumber::NaN, scriptContext);
  1038. }
  1039. // Short cut for numbers
  1040. if (TaggedInt::Is(args[1]))
  1041. {
  1042. return args[1];
  1043. }
  1044. if(JavascriptNumber::Is_NoTaggedIntCheck(args[1]))
  1045. {
  1046. // If the value is negative zero, return positive zero. Since the parameter type is string, -0 would first be
  1047. // converted to the string "0", then parsed to result in positive zero.
  1048. return
  1049. JavascriptNumber::IsNegZero(JavascriptNumber::GetValue(args[1])) ?
  1050. TaggedInt::ToVarUnchecked(0) :
  1051. args[1];
  1052. }
  1053. // convert input to a string
  1054. if (JavascriptString::Is(args[1]))
  1055. {
  1056. str = JavascriptString::FromVar(args[1]);
  1057. }
  1058. else
  1059. {
  1060. str = JavascriptConversion::ToString(args[1], scriptContext);
  1061. }
  1062. // skip preceding whitespace
  1063. const char16 *pch = scriptContext->GetCharClassifier()->SkipWhiteSpace(str->GetSz());
  1064. // perform the string -> float conversion
  1065. result = NumberUtilities::StrToDbl(pch, &pch, scriptContext);
  1066. LEAVE_PINNED_SCOPE(); // str
  1067. return JavascriptNumber::ToVarNoCheck(result, scriptContext);
  1068. }
  1069. Var GlobalObject::EntryIsNaN(RecyclableObject* function, CallInfo callInfo, ...)
  1070. {
  1071. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1072. ARGUMENTS(args, callInfo);
  1073. ScriptContext* scriptContext = function->GetScriptContext();
  1074. Assert(!(callInfo.Flags & CallFlags_New));
  1075. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1076. if(args.Info.Count < 2)
  1077. {
  1078. return scriptContext->GetLibrary()->GetTrue();
  1079. }
  1080. return JavascriptBoolean::ToVar(
  1081. JavascriptNumber::IsNan(JavascriptConversion::ToNumber(args[1],scriptContext)),
  1082. scriptContext);
  1083. }
  1084. Var GlobalObject::EntryIsFinite(RecyclableObject* function, CallInfo callInfo, ...)
  1085. {
  1086. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1087. ARGUMENTS(args, callInfo);
  1088. ScriptContext* scriptContext = function->GetScriptContext();
  1089. Assert(!(callInfo.Flags & CallFlags_New));
  1090. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1091. if(args.Info.Count < 2)
  1092. {
  1093. return scriptContext->GetLibrary()->GetFalse();
  1094. }
  1095. return JavascriptBoolean::ToVar(
  1096. NumberUtilities::IsFinite(JavascriptConversion::ToNumber(args[1],scriptContext)),
  1097. scriptContext);
  1098. }
  1099. Var GlobalObject::EntryDecodeURI(RecyclableObject* function, CallInfo callInfo, ...)
  1100. {
  1101. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1102. ARGUMENTS(args, callInfo);
  1103. ScriptContext* scriptContext = function->GetScriptContext();
  1104. Assert(!(callInfo.Flags & CallFlags_New));
  1105. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1106. return UriHelper::DecodeCoreURI(scriptContext, args, UriHelper::URIReserved);
  1107. }
  1108. Var GlobalObject::EntryDecodeURIComponent(RecyclableObject* function, CallInfo callInfo, ...)
  1109. {
  1110. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1111. ARGUMENTS(args, callInfo);
  1112. ScriptContext* scriptContext = function->GetScriptContext();
  1113. Assert(!(callInfo.Flags & CallFlags_New));
  1114. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1115. return UriHelper::DecodeCoreURI(scriptContext, args, UriHelper::URINone);
  1116. }
  1117. Var GlobalObject::EntryEncodeURI(RecyclableObject* function, CallInfo callInfo, ...)
  1118. {
  1119. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1120. ARGUMENTS(args, callInfo);
  1121. ScriptContext* scriptContext = function->GetScriptContext();
  1122. Assert(!(callInfo.Flags & CallFlags_New));
  1123. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1124. return UriHelper::EncodeCoreURI(scriptContext, args, UriHelper::URIReserved | UriHelper::URIUnescaped);
  1125. }
  1126. Var GlobalObject::EntryEncodeURIComponent(RecyclableObject* function, CallInfo callInfo, ...)
  1127. {
  1128. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1129. ARGUMENTS(args, callInfo);
  1130. ScriptContext* scriptContext = function->GetScriptContext();
  1131. Assert(!(callInfo.Flags & CallFlags_New));
  1132. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1133. return UriHelper::EncodeCoreURI(scriptContext, args, UriHelper::URIUnescaped);
  1134. }
  1135. //
  1136. // Part of Appendix B of ES5 spec
  1137. //
  1138. // This is a bit field for the hex values: 00-29, 2C, 3A-3F, 5B-5E, 60, 7B-FF
  1139. // These are the values escape encodes using the default mask (or mask >= 4)
  1140. static const BYTE _grfbitEscape[] =
  1141. {
  1142. 0xFF, 0xFF, // 00 - 0F
  1143. 0xFF, 0xFF, // 10 - 1F
  1144. 0xFF, 0x13, // 20 - 2F
  1145. 0x00, 0xFC, // 30 - 3F
  1146. 0x00, 0x00, // 40 - 4F
  1147. 0x00, 0x78, // 50 - 5F
  1148. 0x01, 0x00, // 60 - 6F
  1149. 0x00, 0xF8, // 70 - 7F
  1150. 0xFF, 0xFF, // 80 - 8F
  1151. 0xFF, 0xFF, // 90 - 9F
  1152. 0xFF, 0xFF, // A0 - AF
  1153. 0xFF, 0xFF, // B0 - BF
  1154. 0xFF, 0xFF, // C0 - CF
  1155. 0xFF, 0xFF, // D0 - DF
  1156. 0xFF, 0xFF, // E0 - EF
  1157. 0xFF, 0xFF, // F0 - FF
  1158. };
  1159. Var GlobalObject::EntryEscape(RecyclableObject* function, CallInfo callInfo, ...)
  1160. {
  1161. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1162. ARGUMENTS(args, callInfo);
  1163. ScriptContext* scriptContext = function->GetScriptContext();
  1164. Assert(!(callInfo.Flags & CallFlags_New));
  1165. if (args.Info.Count <= 1)
  1166. {
  1167. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  1168. }
  1169. CompoundString * bs = nullptr;
  1170. ENTER_PINNED_SCOPE(JavascriptString, src);
  1171. src = JavascriptConversion::ToString(args[1], scriptContext);
  1172. bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
  1173. char16 chw;
  1174. char16 * pchSrc;
  1175. char16 * pchLim;
  1176. const char _rgchHex[] = "0123456789ABCDEF";
  1177. pchSrc = const_cast<char16 *>(src->GetString());
  1178. pchLim = pchSrc + src->GetLength();
  1179. while (pchSrc < pchLim)
  1180. {
  1181. chw = *pchSrc++;
  1182. if (0 != (chw & 0xFF00))
  1183. {
  1184. bs->AppendChars(_u("%u"));
  1185. bs->AppendChars(static_cast<char16>(_rgchHex[(chw >> 12) & 0x0F]));
  1186. bs->AppendChars(static_cast<char16>(_rgchHex[(chw >> 8) & 0x0F]));
  1187. bs->AppendChars(static_cast<char16>(_rgchHex[(chw >> 4) & 0x0F]));
  1188. bs->AppendChars(static_cast<char16>(_rgchHex[chw & 0x0F]));
  1189. }
  1190. else if (_grfbitEscape[chw >> 3] & (1 << (chw & 7)))
  1191. {
  1192. // Escape the byte.
  1193. bs->AppendChars(_u('%'));
  1194. bs->AppendChars(static_cast<char16>(_rgchHex[chw >> 4]));
  1195. bs->AppendChars(static_cast<char16>(_rgchHex[chw & 0x0F]));
  1196. }
  1197. else
  1198. {
  1199. bs->AppendChars(chw);
  1200. }
  1201. }
  1202. LEAVE_PINNED_SCOPE(); // src
  1203. return bs;
  1204. }
  1205. //
  1206. // Part of Appendix B of ES5 spec
  1207. //
  1208. Var GlobalObject::EntryUnEscape(RecyclableObject* function, CallInfo callInfo, ...)
  1209. {
  1210. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1211. ARGUMENTS(args, callInfo);
  1212. ScriptContext* scriptContext = function->GetScriptContext();
  1213. Assert(!(callInfo.Flags & CallFlags_New));
  1214. if (args.Info.Count <= 1)
  1215. {
  1216. return scriptContext->GetLibrary()->GetUndefinedDisplayString();
  1217. }
  1218. char16 chw;
  1219. char16 chT;
  1220. char16 * pchSrc;
  1221. char16 * pchLim;
  1222. char16 * pchMin;
  1223. CompoundString * bs = nullptr;
  1224. ENTER_PINNED_SCOPE(JavascriptString, src);
  1225. src = JavascriptConversion::ToString(args[1], scriptContext);
  1226. bs = CompoundString::NewWithCharCapacity(src->GetLength(), scriptContext->GetLibrary());
  1227. pchSrc = const_cast<char16 *>(src->GetString());
  1228. pchLim = pchSrc + src->GetLength();
  1229. while (pchSrc < pchLim)
  1230. {
  1231. if ('%' != (chT = *pchSrc++))
  1232. {
  1233. bs->AppendChars(chT);
  1234. continue;
  1235. }
  1236. pchMin = pchSrc;
  1237. chT = *pchSrc++;
  1238. if ('u' != chT)
  1239. {
  1240. chw = 0;
  1241. goto LTwoHexDigits;
  1242. }
  1243. // 4 hex digits.
  1244. if ((chT = *pchSrc++ - '0') <= 9)
  1245. chw = chT * 0x1000;
  1246. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1247. chw = (chT + 10) * 0x1000;
  1248. else
  1249. goto LHexError;
  1250. if ((chT = *pchSrc++ - '0') <= 9)
  1251. chw += chT * 0x0100;
  1252. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1253. chw += (chT + 10) * 0x0100;
  1254. else
  1255. goto LHexError;
  1256. chT = *pchSrc++;
  1257. LTwoHexDigits:
  1258. if ((chT -= '0') <= 9)
  1259. chw += chT * 0x0010;
  1260. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1261. chw += (chT + 10) * 0x0010;
  1262. else
  1263. goto LHexError;
  1264. if ((chT = *pchSrc++ - '0') <= 9)
  1265. chw += chT;
  1266. else if ((chT -= 'A' - '0') <= 5 || (chT -= 'a' - 'A') <= 5)
  1267. chw += chT + 10;
  1268. else
  1269. {
  1270. LHexError:
  1271. pchSrc = pchMin;
  1272. chw = '%';
  1273. }
  1274. bs->AppendChars(chw);
  1275. }
  1276. LEAVE_PINNED_SCOPE(); // src
  1277. return bs;
  1278. }
  1279. #if DBG
  1280. void DebugClearStack()
  1281. {
  1282. char buffer[1024];
  1283. memset(buffer, 0, sizeof(buffer));
  1284. }
  1285. #endif
  1286. Var GlobalObject::EntryCollectGarbage(RecyclableObject* function, CallInfo callInfo, ...)
  1287. {
  1288. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1289. #if DBG_DUMP
  1290. if (Js::Configuration::Global.flags.TraceWin8Allocations)
  1291. {
  1292. Output::Print(_u("MemoryTrace: GlobalObject::EntryCollectGarbage Invoke\n"));
  1293. Output::Flush();
  1294. }
  1295. #endif
  1296. #if DBG
  1297. // Clear 1K of stack to avoid false positive in debug build.
  1298. // Because we don't debug build don't stack pack
  1299. DebugClearStack();
  1300. #endif
  1301. Assert(!(callInfo.Flags & CallFlags_New));
  1302. ScriptContext* scriptContext = function->GetScriptContext();
  1303. if (!scriptContext->GetConfig()->IsCollectGarbageEnabled()
  1304. #ifdef ENABLE_PROJECTION
  1305. && scriptContext->GetConfig()->GetHostType() != HostType::HostTypeApplication
  1306. && scriptContext->GetConfig()->GetHostType() != HostType::HostTypeWebview
  1307. #endif
  1308. )
  1309. {
  1310. // We expose the CollectGarbage API with flag for compat reasons.
  1311. // If CollectGarbage key is not enabled, and if the HostType is neither
  1312. // HostType::HostTypeApplication nor HostType::HostTypeWebview,
  1313. // then we do not trigger collection.
  1314. return scriptContext->GetLibrary()->GetUndefined();
  1315. }
  1316. Recycler* recycler = scriptContext->GetRecycler();
  1317. if (recycler)
  1318. {
  1319. #if DBG && defined(RECYCLER_DUMP_OBJECT_GRAPH)
  1320. ARGUMENTS(args, callInfo);
  1321. if (args.Info.Count > 1)
  1322. {
  1323. double value = JavascriptConversion::ToNumber(args[1], function->GetScriptContext());
  1324. if (value == 1.0)
  1325. {
  1326. recycler->dumpObjectOnceOnCollect = true;
  1327. }
  1328. }
  1329. #endif
  1330. recycler->CollectNow<CollectNowDecommitNowExplicit>();
  1331. }
  1332. #if DBG_DUMP
  1333. #ifdef ENABLE_PROJECTION
  1334. scriptContext->GetThreadContext()->DumpProjectionContextMemoryStats(_u("Stats after GlobalObject::EntryCollectGarbage call"));
  1335. #endif
  1336. if (Js::Configuration::Global.flags.TraceWin8Allocations)
  1337. {
  1338. Output::Print(_u("MemoryTrace: GlobalObject::EntryCollectGarbage Exit\n"));
  1339. Output::Flush();
  1340. }
  1341. #endif
  1342. return scriptContext->GetLibrary()->GetUndefined();
  1343. }
  1344. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1345. Var GlobalObject::EntryChWriteTraceEvent(RecyclableObject *function, CallInfo callInfo, ...)
  1346. {
  1347. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1348. ARGUMENTS(args, callInfo);
  1349. if (args.Info.Count < 2)
  1350. {
  1351. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1352. }
  1353. Js::JavascriptString* jsString = Js::JavascriptConversion::ToString(args[1], function->GetScriptContext());
  1354. PlatformAgnostic::EventTrace::FireGenericEventTrace(jsString->GetSz());
  1355. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1356. }
  1357. #endif
  1358. #if ENABLE_TTD
  1359. //Log a string in the telemetry system (and print to the console)
  1360. Var GlobalObject::EntryTelemetryLog(RecyclableObject* function, CallInfo callInfo, ...)
  1361. {
  1362. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1363. ARGUMENTS(args, callInfo);
  1364. TTDAssert(args.Info.Count >= 2 && Js::JavascriptString::Is(args[1]), "Bad arguments!!!");
  1365. Js::JavascriptString* jsString = Js::JavascriptString::FromVar(args[1]);
  1366. bool doPrint = (args.Info.Count == 3) && Js::JavascriptBoolean::Is(args[2]) && (Js::JavascriptBoolean::FromVar(args[2])->GetValue());
  1367. if(function->GetScriptContext()->ShouldPerformReplayAction())
  1368. {
  1369. function->GetScriptContext()->GetThreadContext()->TTDLog->ReplayTelemetryLogEvent(jsString);
  1370. }
  1371. if(function->GetScriptContext()->ShouldPerformRecordAction())
  1372. {
  1373. function->GetScriptContext()->GetThreadContext()->TTDLog->RecordTelemetryLogEvent(jsString, doPrint);
  1374. }
  1375. if(doPrint)
  1376. {
  1377. //
  1378. //TODO: the host should give us a print callback which we can use here
  1379. //
  1380. wprintf(_u("%ls\n"), jsString->GetSz());
  1381. fflush(stdout);
  1382. }
  1383. return function->GetScriptContext()->GetLibrary()->GetUndefined();
  1384. }
  1385. //Check if diagnostic trace writing is enabled
  1386. Var GlobalObject::EntryEnabledDiagnosticsTrace(RecyclableObject* function, CallInfo callInfo, ...)
  1387. {
  1388. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1389. ARGUMENTS(args, callInfo);
  1390. if(function->GetScriptContext()->ShouldPerformRecordOrReplayAction())
  1391. {
  1392. return function->GetScriptContext()->GetLibrary()->GetTrue();
  1393. }
  1394. else
  1395. {
  1396. return function->GetScriptContext()->GetLibrary()->GetFalse();
  1397. }
  1398. }
  1399. //Write a copy of the current TTD log to a specified location
  1400. Var GlobalObject::EntryEmitTTDLog(RecyclableObject* function, CallInfo callInfo, ...)
  1401. {
  1402. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1403. ARGUMENTS(args, callInfo);
  1404. Js::JavascriptLibrary* jslib = function->GetScriptContext()->GetLibrary();
  1405. if(args.Info.Count != 2 || !Js::JavascriptString::Is(args[1]))
  1406. {
  1407. return jslib->GetFalse();
  1408. }
  1409. if(function->GetScriptContext()->ShouldPerformReplayAction())
  1410. {
  1411. function->GetScriptContext()->GetThreadContext()->TTDLog->ReplayEmitLogEvent();
  1412. return jslib->GetTrue();
  1413. }
  1414. if(function->GetScriptContext()->ShouldPerformRecordAction())
  1415. {
  1416. Js::JavascriptString* jsString = Js::JavascriptString::FromVar(args[1]);
  1417. function->GetScriptContext()->GetThreadContext()->TTDLog->RecordEmitLogEvent(jsString);
  1418. return jslib->GetTrue();
  1419. }
  1420. return jslib->GetFalse();
  1421. }
  1422. #endif
  1423. //Pattern match is unique to RuntimeObject. Only leading and trailing * are implemented
  1424. //Example: *pat*tern* actually matches all the strings having pat*tern as substring.
  1425. BOOL GlobalObject::MatchPatternHelper(JavascriptString *propertyName, JavascriptString *pattern, ScriptContext *scriptContext)
  1426. {
  1427. if (nullptr == propertyName || nullptr == pattern)
  1428. {
  1429. return FALSE;
  1430. }
  1431. charcount_t patternLength = pattern->GetLength();
  1432. charcount_t nameLength = propertyName->GetLength();
  1433. BOOL bStart;
  1434. BOOL bEnd;
  1435. if (0 == patternLength)
  1436. {
  1437. return TRUE; // empty pattern matches all
  1438. }
  1439. bStart = (_u('*') == pattern->GetItem(0));// Is there a start star?
  1440. bEnd = (_u('*') == pattern->GetItem(patternLength - 1));// Is there an end star?
  1441. //deal with the stars
  1442. if (bStart || bEnd)
  1443. {
  1444. JavascriptString *subPattern;
  1445. int idxStart = bStart? 1: 0;
  1446. int idxEnd = bEnd? (patternLength - 1): patternLength;
  1447. if (idxEnd <= idxStart)
  1448. {
  1449. return TRUE; //scenario double star **
  1450. }
  1451. //get a pattern which doesn't contain leading and trailing stars
  1452. subPattern = JavascriptString::FromVar(JavascriptString::SubstringCore(pattern, idxStart, idxEnd - idxStart, scriptContext));
  1453. uint index = JavascriptString::strstr(propertyName, subPattern, false);
  1454. if (index == (uint)-1)
  1455. {
  1456. return FALSE;
  1457. }
  1458. if (FALSE == bStart)
  1459. {
  1460. return index == 0; //begin at the same place;
  1461. }
  1462. else if (FALSE == bEnd)
  1463. {
  1464. return (index + patternLength - 1) == (nameLength);
  1465. }
  1466. return TRUE;
  1467. }
  1468. else
  1469. {
  1470. //full match
  1471. if (0 == JavascriptString::strcmp(propertyName, pattern))
  1472. {
  1473. return TRUE;
  1474. }
  1475. }
  1476. return FALSE;
  1477. }
  1478. PropertyQueryFlags GlobalObject::HasPropertyQuery(PropertyId propertyId)
  1479. {
  1480. return JavascriptConversion::BooleanToPropertyQueryFlags(JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId)) ||
  1481. (this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject, propertyId)) ||
  1482. (this->hostObject && JavascriptOperators::HasProperty(this->hostObject, propertyId)));
  1483. }
  1484. BOOL GlobalObject::HasRootProperty(PropertyId propertyId)
  1485. {
  1486. return __super::HasRootProperty(propertyId) ||
  1487. (this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject, propertyId)) ||
  1488. (this->hostObject && JavascriptOperators::HasProperty(this->hostObject, propertyId));
  1489. }
  1490. BOOL GlobalObject::HasOwnProperty(PropertyId propertyId)
  1491. {
  1492. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId)) ||
  1493. (this->directHostObject && this->directHostObject->HasProperty(propertyId));
  1494. }
  1495. BOOL GlobalObject::HasOwnPropertyNoHostObject(PropertyId propertyId)
  1496. {
  1497. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId));
  1498. }
  1499. PropertyQueryFlags GlobalObject::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1500. {
  1501. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext)))
  1502. {
  1503. return PropertyQueryFlags::Property_Found;
  1504. }
  1505. return JavascriptConversion::BooleanToPropertyQueryFlags((this->directHostObject && JavascriptOperators::GetProperty(this->directHostObject, propertyId, value, requestContext, info)) ||
  1506. (this->hostObject && JavascriptOperators::GetProperty(this->hostObject, propertyId, value, requestContext, info)));
  1507. }
  1508. PropertyQueryFlags GlobalObject::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1509. {
  1510. PropertyRecord const* propertyRecord;
  1511. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  1512. return GlobalObject::GetPropertyQuery(originalInstance, propertyRecord->GetPropertyId(), value, info, requestContext);
  1513. }
  1514. BOOL GlobalObject::GetRootProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  1515. {
  1516. if (__super::GetRootProperty(originalInstance, propertyId, value, info, requestContext))
  1517. {
  1518. return TRUE;
  1519. }
  1520. return (this->directHostObject && JavascriptOperators::GetProperty(this->directHostObject, propertyId, value, requestContext, info)) ||
  1521. (this->hostObject && JavascriptOperators::GetProperty(this->hostObject, propertyId, value, requestContext, info));
  1522. }
  1523. BOOL GlobalObject::GetAccessors(PropertyId propertyId, Var* getter, Var* setter, ScriptContext * requestContext)
  1524. {
  1525. if (DynamicObject::GetAccessors(propertyId, getter, setter, requestContext))
  1526. {
  1527. return TRUE;
  1528. }
  1529. if (this->directHostObject)
  1530. {
  1531. return this->directHostObject->GetAccessors(propertyId, getter, setter, requestContext);
  1532. }
  1533. else if (this->hostObject)
  1534. {
  1535. return this->hostObject->GetAccessors(propertyId, getter, setter, requestContext);
  1536. }
  1537. return FALSE;
  1538. }
  1539. PropertyQueryFlags GlobalObject::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info,
  1540. ScriptContext* requestContext)
  1541. {
  1542. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyReferenceQuery(originalInstance, propertyId, value, info, requestContext)))
  1543. {
  1544. return PropertyQueryFlags::Property_Found;
  1545. }
  1546. return JavascriptConversion::BooleanToPropertyQueryFlags((this->directHostObject && JavascriptOperators::GetPropertyReference(this->directHostObject, propertyId, value, requestContext, info)) ||
  1547. (this->hostObject && JavascriptOperators::GetPropertyReference(this->hostObject, propertyId, value, requestContext, info)));
  1548. }
  1549. BOOL GlobalObject::GetRootPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info,
  1550. ScriptContext* requestContext)
  1551. {
  1552. if (__super::GetRootPropertyReference(originalInstance, propertyId, value, info, requestContext))
  1553. {
  1554. return true;
  1555. }
  1556. return (this->directHostObject && JavascriptOperators::GetPropertyReference(this->directHostObject, propertyId, value, requestContext, info)) ||
  1557. (this->hostObject && JavascriptOperators::GetPropertyReference(this->hostObject, propertyId, value, requestContext, info));
  1558. }
  1559. BOOL GlobalObject::InitProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1560. {
  1561. // var x = 10; variables declared with "var" at global scope
  1562. // These cannot be deleted
  1563. // In ES5 they are enumerable.
  1564. PropertyAttributes attributes = PropertyWritable | PropertyEnumerable | PropertyDeclaredGlobal;
  1565. flags = static_cast<PropertyOperationFlags>(flags | PropertyOperation_ThrowIfNotExtensible);
  1566. return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info, flags);
  1567. }
  1568. BOOL GlobalObject::InitPropertyScoped(PropertyId propertyId, Var value)
  1569. {
  1570. // var x = 10; variables declared with "var" inside "eval"
  1571. // These CAN be deleted
  1572. // in ES5 they are enumerable.
  1573. //
  1574. PropertyAttributes attributes = PropertyDynamicTypeDefaults | PropertyDeclaredGlobal;
  1575. return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, NULL, PropertyOperation_ThrowIfNotExtensible);
  1576. }
  1577. BOOL GlobalObject::InitFuncScoped(PropertyId propertyId, Var value)
  1578. {
  1579. // Var binding of functions declared in eval are elided when conflicting
  1580. // with global scope let/const variables, so do not actually set the
  1581. // property if it exists and is a let/const variable.
  1582. bool noRedecl = false;
  1583. if (!GetTypeHandler()->HasRootProperty(this, propertyId, &noRedecl) || !noRedecl)
  1584. {
  1585. //
  1586. // var x = 10; variables declared with "var" inside "eval"
  1587. // These CAN be deleted
  1588. // in ES5 they are enumerable.
  1589. PropertyAttributes attributes = PropertyDynamicTypeDefaults;
  1590. DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, NULL, PropertyOperation_ThrowIfNotExtensible);
  1591. }
  1592. return true;
  1593. }
  1594. BOOL GlobalObject::SetExistingProperty(PropertyId propertyId, Var value, PropertyValueInfo* info, BOOL *setAttempted)
  1595. {
  1596. BOOL hasOwnProperty = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId));
  1597. BOOL hasProperty = JavascriptOperators::HasProperty(this->GetPrototype(), propertyId);
  1598. *setAttempted = TRUE;
  1599. if (this->directHostObject &&
  1600. !hasOwnProperty &&
  1601. !hasProperty &&
  1602. this->directHostObject->HasProperty(propertyId))
  1603. {
  1604. // directHostObject->HasProperty returns true for things in global collections, however, they are not able to be set.
  1605. // When we call SetProperty we'll return FALSE which means fall back to GlobalObject::SetProperty and shadow our collection
  1606. // object rather than failing the set altogether. See bug Windows Out Of Band Releases 1144780 and linked bugs for details.
  1607. if (this->directHostObject->SetProperty(propertyId, value, PropertyOperation_None, info))
  1608. {
  1609. return TRUE;
  1610. }
  1611. }
  1612. else
  1613. if (this->hostObject &&
  1614. // Consider to revert to the commented line and ignore the prototype chain when direct host is on by default in IE9 mode
  1615. !hasOwnProperty &&
  1616. !hasProperty &&
  1617. this->hostObject->HasProperty(propertyId))
  1618. {
  1619. return this->hostObject->SetProperty(propertyId, value, PropertyOperation_None, NULL);
  1620. }
  1621. if (hasOwnProperty || hasProperty)
  1622. {
  1623. return DynamicObject::SetProperty(propertyId, value, PropertyOperation_None, info);
  1624. }
  1625. *setAttempted = FALSE;
  1626. return FALSE;
  1627. }
  1628. BOOL GlobalObject::SetExistingRootProperty(PropertyId propertyId, Var value, PropertyValueInfo* info, BOOL *setAttempted)
  1629. {
  1630. BOOL hasOwnProperty = __super::HasRootProperty(propertyId);
  1631. BOOL hasProperty = JavascriptOperators::HasProperty(this->GetPrototype(), propertyId);
  1632. *setAttempted = TRUE;
  1633. if (this->directHostObject &&
  1634. !hasOwnProperty &&
  1635. !hasProperty &&
  1636. this->directHostObject->HasProperty(propertyId))
  1637. {
  1638. // directHostObject->HasProperty returns true for things in global collections, however, they are not able to be set.
  1639. // When we call SetProperty we'll return FALSE which means fall back to GlobalObject::SetProperty and shadow our collection
  1640. // object rather than failing the set altogether. See bug Windows Out Of Band Releases 1144780 and linked bugs for details.
  1641. if (this->directHostObject->SetProperty(propertyId, value, PropertyOperation_None, info))
  1642. {
  1643. return TRUE;
  1644. }
  1645. }
  1646. else
  1647. if (this->hostObject &&
  1648. // Consider to revert to the commented line and ignore the prototype chain when direct host is on by default in IE9 mode
  1649. !hasOwnProperty &&
  1650. !hasProperty &&
  1651. this->hostObject->HasProperty(propertyId))
  1652. {
  1653. return this->hostObject->SetProperty(propertyId, value, PropertyOperation_None, NULL);
  1654. }
  1655. if (hasOwnProperty || hasProperty)
  1656. {
  1657. return __super::SetRootProperty(propertyId, value, PropertyOperation_None, info);
  1658. }
  1659. *setAttempted = FALSE;
  1660. return FALSE;
  1661. }
  1662. BOOL GlobalObject::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1663. {
  1664. Assert(!(flags & PropertyOperation_Root));
  1665. BOOL setAttempted = TRUE;
  1666. if (this->SetExistingProperty(propertyId, value, info, &setAttempted))
  1667. {
  1668. return TRUE;
  1669. }
  1670. //
  1671. // Set was attempted. But the set operation returned false.
  1672. // This happens, when the property is read only.
  1673. // In those scenarios, we should be setting the property with default attributes
  1674. //
  1675. if (setAttempted)
  1676. {
  1677. return FALSE;
  1678. }
  1679. // Windows 8 430092: When we set a new property on globalObject there may be stale inline caches holding onto directHostObject->prototype
  1680. // properties of the same name. So we need to clear proto caches in this scenario. But check for same property in directHostObject->prototype
  1681. // chain is expensive (call to DOM) compared to just invalidating the cache.
  1682. // If this blind invalidation is expensive in any scenario then we need to revisit this.
  1683. // Another solution proposed was not to cache any of the properties of window->directHostObject->prototype.
  1684. // if ((this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject->GetPrototype(), propertyId)) ||
  1685. // (this->hostObject && JavascriptOperators::HasProperty(this->hostObject->GetPrototype(), propertyId)))
  1686. this->GetScriptContext()->InvalidateProtoCaches(propertyId);
  1687. //
  1688. // x = 10; implicit/phantom variable at global scope
  1689. // These CAN be deleted
  1690. // In ES5 they are enumerable.
  1691. PropertyAttributes attributes = PropertyDynamicTypeDefaults;
  1692. return DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info);
  1693. }
  1694. BOOL GlobalObject::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1695. {
  1696. PropertyRecord const * propertyRecord;
  1697. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  1698. return GlobalObject::SetProperty(propertyRecord->GetPropertyId(), value, flags, info);
  1699. }
  1700. BOOL GlobalObject::SetRootProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  1701. {
  1702. Assert(flags & PropertyOperation_Root);
  1703. BOOL setAttempted = TRUE;
  1704. if (this->SetExistingRootProperty(propertyId, value, info, &setAttempted))
  1705. {
  1706. return TRUE;
  1707. }
  1708. //
  1709. // Set was attempted. But the set operation returned false.
  1710. // This happens, when the property is read only.
  1711. // In those scenarios, we should be setting the property with default attributes
  1712. //
  1713. if (setAttempted)
  1714. {
  1715. return FALSE;
  1716. }
  1717. if (flags & PropertyOperation_StrictMode)
  1718. {
  1719. if (!GetScriptContext()->GetThreadContext()->RecordImplicitException())
  1720. {
  1721. return FALSE;
  1722. }
  1723. JavascriptError::ThrowReferenceError(GetScriptContext(), JSERR_RefErrorUndefVariable);
  1724. }
  1725. // Windows 8 430092: When we set a new property on globalObject there may be stale inline caches holding onto directHostObject->prototype
  1726. // properties of the same name. So we need to clear proto caches in this scenario. But check for same property in directHostObject->prototype
  1727. // chain is expensive (call to DOM) compared to just invalidating the cache.
  1728. // If this blind invalidation is expensive in any scenario then we need to revisit this.
  1729. // Another solution proposed was not to cache any of the properties of window->directHostObject->prototype.
  1730. // if ((this->directHostObject && JavascriptOperators::HasProperty(this->directHostObject->GetPrototype(), propertyId)) ||
  1731. // (this->hostObject && JavascriptOperators::HasProperty(this->hostObject->GetPrototype(), propertyId)))
  1732. this->GetScriptContext()->InvalidateProtoCaches(propertyId);
  1733. return __super::SetRootProperty(propertyId, value, flags, info);
  1734. }
  1735. BOOL GlobalObject::SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
  1736. {
  1737. if (DynamicObject::SetAccessors(propertyId, getter, setter, flags))
  1738. {
  1739. return TRUE;
  1740. }
  1741. if (this->directHostObject)
  1742. {
  1743. return this->directHostObject->SetAccessors(propertyId, getter, setter, flags);
  1744. }
  1745. if (this->hostObject)
  1746. {
  1747. return this->hostObject->SetAccessors(propertyId, getter, setter, flags);
  1748. }
  1749. return TRUE;
  1750. }
  1751. DescriptorFlags GlobalObject::GetSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1752. {
  1753. DescriptorFlags flags = DynamicObject::GetSetter(propertyId, setterValue, info, requestContext);
  1754. if (flags == None)
  1755. {
  1756. if (this->directHostObject)
  1757. {
  1758. // We need to look up the prototype chain here.
  1759. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->directHostObject, propertyId, setterValue, &flags, info, requestContext);
  1760. }
  1761. else if (this->hostObject)
  1762. {
  1763. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->hostObject, propertyId, setterValue, &flags, info, requestContext);
  1764. }
  1765. }
  1766. return flags;
  1767. }
  1768. DescriptorFlags GlobalObject::GetSetter(JavascriptString* propertyNameString, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1769. {
  1770. PropertyRecord const* propertyRecord;
  1771. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  1772. return GlobalObject::GetSetter(propertyRecord->GetPropertyId(), setterValue, info, requestContext);
  1773. }
  1774. DescriptorFlags GlobalObject::GetRootSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  1775. {
  1776. DescriptorFlags flags = __super::GetRootSetter(propertyId, setterValue, info, requestContext);
  1777. if (flags == None)
  1778. {
  1779. if (this->directHostObject)
  1780. {
  1781. // We need to look up the prototype chain here.
  1782. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->directHostObject, propertyId, setterValue, &flags, info, requestContext);
  1783. }
  1784. else if (this->hostObject)
  1785. {
  1786. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty(this->hostObject, propertyId, setterValue, &flags, info, requestContext);
  1787. }
  1788. }
  1789. return flags;
  1790. }
  1791. DescriptorFlags GlobalObject::GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext)
  1792. {
  1793. DescriptorFlags flags = DynamicObject::GetItemSetter(index, setterValue, requestContext);
  1794. if (flags == None)
  1795. {
  1796. if (this->directHostObject)
  1797. {
  1798. // We need to look up the prototype chain here.
  1799. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableItem(this->directHostObject, index, setterValue, &flags, requestContext);
  1800. }
  1801. else if (this->hostObject)
  1802. {
  1803. JavascriptOperators::CheckPrototypesForAccessorOrNonWritableItem(this->hostObject, index, setterValue, &flags, requestContext);
  1804. }
  1805. }
  1806. return flags;
  1807. }
  1808. BOOL GlobalObject::DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags)
  1809. {
  1810. if (JavascriptConversion::PropertyQueryFlagsToBoolean(__super::HasPropertyQuery(propertyId)))
  1811. {
  1812. return __super::DeleteProperty(propertyId, flags);
  1813. }
  1814. else if (this->directHostObject && this->directHostObject->HasProperty(propertyId))
  1815. {
  1816. return this->directHostObject->DeleteProperty(propertyId, flags);
  1817. }
  1818. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  1819. {
  1820. return this->hostObject->DeleteProperty(propertyId, flags);
  1821. }
  1822. // Non-existent property
  1823. return TRUE;
  1824. }
  1825. BOOL GlobalObject::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
  1826. {
  1827. PropertyRecord const *propertyRecord = nullptr;
  1828. if (JavascriptOperators::ShouldTryDeleteProperty(this, propertyNameString, &propertyRecord))
  1829. {
  1830. Assert(propertyRecord);
  1831. return DeleteProperty(propertyRecord->GetPropertyId(), flags);
  1832. }
  1833. return TRUE;
  1834. }
  1835. BOOL GlobalObject::DeleteRootProperty(PropertyId propertyId, PropertyOperationFlags flags)
  1836. {
  1837. if (__super::HasRootProperty(propertyId))
  1838. {
  1839. return __super::DeleteRootProperty(propertyId, flags);
  1840. }
  1841. else if (this->directHostObject && this->directHostObject->HasProperty(propertyId))
  1842. {
  1843. return this->directHostObject->DeleteProperty(propertyId, flags);
  1844. }
  1845. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  1846. {
  1847. return this->hostObject->DeleteProperty(propertyId, flags);
  1848. }
  1849. // Non-existent property
  1850. return TRUE;
  1851. }
  1852. PropertyQueryFlags GlobalObject::HasItemQuery(uint32 index)
  1853. {
  1854. return JavascriptConversion::BooleanToPropertyQueryFlags(JavascriptConversion::PropertyQueryFlagsToBoolean((DynamicObject::HasItemQuery(index)))
  1855. || (this->directHostObject && JavascriptOperators::HasItem(this->directHostObject, index))
  1856. || (this->hostObject && JavascriptOperators::HasItem(this->hostObject, index)));
  1857. }
  1858. BOOL GlobalObject::HasOwnItem(uint32 index)
  1859. {
  1860. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasItemQuery(index))
  1861. || (this->directHostObject && this->directHostObject->HasItem(index));
  1862. }
  1863. PropertyQueryFlags GlobalObject::GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext* requestContext)
  1864. {
  1865. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemReferenceQuery(originalInstance, index, value, requestContext)))
  1866. {
  1867. return PropertyQueryFlags::Property_Found;
  1868. }
  1869. return JavascriptConversion::BooleanToPropertyQueryFlags(
  1870. (this->directHostObject && JavascriptConversion::PropertyQueryFlagsToBoolean(this->directHostObject->GetItemReferenceQuery(originalInstance, index, value, requestContext))) ||
  1871. (this->hostObject && JavascriptConversion::PropertyQueryFlagsToBoolean(this->hostObject->GetItemReferenceQuery(originalInstance, index, value, requestContext))));
  1872. }
  1873. BOOL GlobalObject::SetItem(uint32 index, Var value, PropertyOperationFlags flags)
  1874. {
  1875. BOOL result = DynamicObject::SetItem(index, value, flags);
  1876. return result;
  1877. }
  1878. PropertyQueryFlags GlobalObject::GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext* requestContext)
  1879. {
  1880. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemQuery(originalInstance, index, value, requestContext)))
  1881. {
  1882. return PropertyQueryFlags::Property_Found;
  1883. }
  1884. return JavascriptConversion::BooleanToPropertyQueryFlags((this->directHostObject && this->directHostObject->GetItem(originalInstance, index, value, requestContext)) ||
  1885. (this->hostObject && this->hostObject->GetItem(originalInstance, index, value, requestContext)));
  1886. }
  1887. BOOL GlobalObject::DeleteItem(uint32 index, PropertyOperationFlags flags)
  1888. {
  1889. if (DynamicObject::DeleteItem(index, flags))
  1890. {
  1891. return TRUE;
  1892. }
  1893. if (this->directHostObject)
  1894. {
  1895. return this->directHostObject->DeleteItem(index, flags);
  1896. }
  1897. if (this->hostObject)
  1898. {
  1899. return this->hostObject->DeleteItem(index, flags);
  1900. }
  1901. return FALSE;
  1902. }
  1903. BOOL GlobalObject::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1904. {
  1905. stringBuilder->AppendCppLiteral(_u("{...}"));
  1906. return TRUE;
  1907. }
  1908. BOOL GlobalObject::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  1909. {
  1910. stringBuilder->AppendCppLiteral(_u("Object, (Global)"));
  1911. return TRUE;
  1912. }
  1913. BOOL GlobalObject::StrictEquals(__in Js::Var other, __out BOOL* value, ScriptContext * requestContext)
  1914. {
  1915. if (this == other)
  1916. {
  1917. *value = TRUE;
  1918. return TRUE;
  1919. }
  1920. else if (this->directHostObject)
  1921. {
  1922. return this->directHostObject->StrictEquals(other, value, requestContext);
  1923. }
  1924. else if (this->hostObject)
  1925. {
  1926. return this->hostObject->StrictEquals(other, value, requestContext);
  1927. }
  1928. *value = FALSE;
  1929. return FALSE;
  1930. }
  1931. BOOL GlobalObject::Equals(__in Js::Var other, __out BOOL* value, ScriptContext * requestContext)
  1932. {
  1933. if (this == other)
  1934. {
  1935. *value = TRUE;
  1936. return TRUE;
  1937. }
  1938. else if (this->directHostObject)
  1939. {
  1940. return this->directHostObject->Equals(other, value, requestContext);
  1941. }
  1942. else if (this->hostObject)
  1943. {
  1944. return this->hostObject->Equals(other, value, requestContext);
  1945. }
  1946. *value = FALSE;
  1947. return TRUE;
  1948. }
  1949. #if ENABLE_TTD
  1950. TTD::NSSnapObjects::SnapObjectType GlobalObject::GetSnapTag_TTD() const
  1951. {
  1952. return TTD::NSSnapObjects::SnapObjectType::SnapWellKnownObject;
  1953. }
  1954. void GlobalObject::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  1955. {
  1956. //
  1957. //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
  1958. //
  1959. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<void*, TTD::NSSnapObjects::SnapObjectType::SnapWellKnownObject>(objData, nullptr);
  1960. }
  1961. #endif
  1962. }