GlobalObject.cpp 91 KB

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