GlobalObject.cpp 94 KB

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