ScriptFunction.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  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. namespace Js
  7. {
  8. ScriptFunctionBase::ScriptFunctionBase(DynamicType * type) :
  9. JavascriptFunction(type)
  10. {}
  11. ScriptFunctionBase::ScriptFunctionBase(DynamicType * type, FunctionInfo * functionInfo) :
  12. JavascriptFunction(type, functionInfo)
  13. {}
  14. bool ScriptFunctionBase::Is(Var func)
  15. {
  16. if (JavascriptFunction::Is(func))
  17. {
  18. JavascriptFunction *function = JavascriptFunction::UnsafeFromVar(func);
  19. return ScriptFunction::Test(function) || JavascriptGeneratorFunction::Test(function)
  20. || JavascriptAsyncFunction::Test(function);
  21. }
  22. return false;
  23. }
  24. ScriptFunctionBase * ScriptFunctionBase::FromVar(Var func)
  25. {
  26. AssertOrFailFast(ScriptFunctionBase::Is(func));
  27. return reinterpret_cast<ScriptFunctionBase *>(func);
  28. }
  29. ScriptFunctionBase * ScriptFunctionBase::UnsafeFromVar(Var func)
  30. {
  31. Assert(ScriptFunctionBase::Is(func));
  32. return reinterpret_cast<ScriptFunctionBase *>(func);
  33. }
  34. ScriptFunction::ScriptFunction(DynamicType * type) :
  35. ScriptFunctionBase(type), environment((FrameDisplay*)&NullFrameDisplay),
  36. cachedScopeObj(nullptr), hasInlineCaches(false), hasSuperReference(false), homeObj(nullptr),
  37. computedNameVar(nullptr), isActiveScript(false)
  38. {}
  39. ScriptFunction::ScriptFunction(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType)
  40. : ScriptFunctionBase(deferredPrototypeType, proxy->GetFunctionInfo()),
  41. environment((FrameDisplay*)&NullFrameDisplay), cachedScopeObj(nullptr), homeObj(nullptr),
  42. hasInlineCaches(false), hasSuperReference(false), isActiveScript(false), computedNameVar(nullptr)
  43. {
  44. Assert(proxy->GetFunctionInfo()->GetFunctionProxy() == proxy);
  45. Assert(proxy->EnsureDeferredPrototypeType() == deferredPrototypeType);
  46. DebugOnly(VerifyEntryPoint());
  47. #if ENABLE_NATIVE_CODEGEN
  48. #ifdef BGJIT_STATS
  49. if (!proxy->IsDeferred())
  50. {
  51. FunctionBody* body = proxy->GetFunctionBody();
  52. if(!body->GetNativeEntryPointUsed() &&
  53. body->GetDefaultFunctionEntryPointInfo()->IsCodeGenDone())
  54. {
  55. MemoryBarrier();
  56. type->GetScriptContext()->jitCodeUsed += body->GetByteCodeCount();
  57. type->GetScriptContext()->funcJitCodeUsed++;
  58. body->SetNativeEntryPointUsed(true);
  59. }
  60. }
  61. #endif
  62. #endif
  63. }
  64. ScriptFunction * ScriptFunction::OP_NewScFunc(FrameDisplay *environment, FunctionInfoPtrPtr infoRef)
  65. {
  66. AssertMsg(infoRef!= nullptr, "BYTE-CODE VERIFY: Must specify a valid function to create");
  67. FunctionProxy* functionProxy = (*infoRef)->GetFunctionProxy();
  68. AssertMsg(functionProxy!= nullptr, "BYTE-CODE VERIFY: Must specify a valid function to create");
  69. ScriptContext* scriptContext = functionProxy->GetScriptContext();
  70. bool hasSuperReference = functionProxy->HasSuperReference();
  71. if (functionProxy->IsFunctionBody() && functionProxy->GetFunctionBody()->GetInlineCachesOnFunctionObject())
  72. {
  73. Js::FunctionBody * functionBody = functionProxy->GetFunctionBody();
  74. ScriptFunctionWithInlineCache* pfuncScriptWithInlineCache = scriptContext->GetLibrary()->CreateScriptFunctionWithInlineCache(functionProxy);
  75. pfuncScriptWithInlineCache->SetEnvironment(environment);
  76. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(pfuncScriptWithInlineCache, EtwTrace::GetFunctionId(functionProxy)));
  77. Assert(functionBody->GetInlineCacheCount() + functionBody->GetIsInstInlineCacheCount());
  78. if (functionBody->GetIsFirstFunctionObject())
  79. {
  80. // point the inline caches of the first function object to those on the function body.
  81. pfuncScriptWithInlineCache->SetInlineCachesFromFunctionBody();
  82. functionBody->SetIsNotFirstFunctionObject();
  83. }
  84. else
  85. {
  86. // allocate inline cache for this function object
  87. pfuncScriptWithInlineCache->CreateInlineCache();
  88. }
  89. pfuncScriptWithInlineCache->SetHasSuperReference(hasSuperReference);
  90. if (PHASE_TRACE1(Js::ScriptFunctionWithInlineCachePhase))
  91. {
  92. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  93. Output::Print(_u("Function object with inline cache: function number: (%s)\tfunction name: %s\n"),
  94. functionBody->GetDebugNumberSet(debugStringBuffer), functionBody->GetDisplayName());
  95. Output::Flush();
  96. }
  97. return pfuncScriptWithInlineCache;
  98. }
  99. else
  100. {
  101. ScriptFunction* pfuncScript = scriptContext->GetLibrary()->CreateScriptFunction(functionProxy);
  102. pfuncScript->SetEnvironment(environment);
  103. pfuncScript->SetHasSuperReference(hasSuperReference);
  104. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(pfuncScript, EtwTrace::GetFunctionId(functionProxy)));
  105. return pfuncScript;
  106. }
  107. }
  108. void ScriptFunction::SetEnvironment(FrameDisplay * environment)
  109. {
  110. //Assert(ThreadContext::IsOnStack(this) || !ThreadContext::IsOnStack(environment));
  111. this->environment = environment;
  112. }
  113. void ScriptFunction::InvalidateCachedScopeChain()
  114. {
  115. // Note: Currently this helper assumes that we're in an eval-class case
  116. // where all the contents of the closure environment are dynamic objects.
  117. // Invalidating scopes that are raw slot arrays, etc., will have to be done
  118. // directly in byte code.
  119. // A function nested within this one has escaped.
  120. // Invalidate our own cached scope object, and walk the closure environment
  121. // doing this same.
  122. if (this->cachedScopeObj)
  123. {
  124. this->cachedScopeObj->InvalidateCachedScope();
  125. }
  126. FrameDisplay *pDisplay = this->environment;
  127. uint length = (uint)pDisplay->GetLength();
  128. for (uint i = 0; i < length; i++)
  129. {
  130. Var scope = pDisplay->GetItem(i);
  131. RecyclableObject *scopeObj = RecyclableObject::FromVar(scope);
  132. scopeObj->InvalidateCachedScope();
  133. }
  134. }
  135. bool ScriptFunction::Is(Var func)
  136. {
  137. return JavascriptFunction::Is(func) && JavascriptFunction::UnsafeFromVar(func)->GetFunctionInfo()->HasBody();
  138. }
  139. ScriptFunction * ScriptFunction::FromVar(Var func)
  140. {
  141. AssertOrFailFast(ScriptFunction::Is(func));
  142. return reinterpret_cast<ScriptFunction *>(func);
  143. }
  144. ScriptFunction * ScriptFunction::UnsafeFromVar(Var func)
  145. {
  146. Assert(ScriptFunction::Is(func));
  147. return reinterpret_cast<ScriptFunction *>(func);
  148. }
  149. ProxyEntryPointInfo * ScriptFunction::GetEntryPointInfo() const
  150. {
  151. return this->GetScriptFunctionType()->GetEntryPointInfo();
  152. }
  153. ScriptFunctionType * ScriptFunction::GetScriptFunctionType() const
  154. {
  155. return (ScriptFunctionType *)GetDynamicType();
  156. }
  157. ScriptFunctionType * ScriptFunction::DuplicateType()
  158. {
  159. ScriptFunctionType* type = RecyclerNew(this->GetScriptContext()->GetRecycler(),
  160. ScriptFunctionType, this->GetScriptFunctionType());
  161. this->GetFunctionProxy()->RegisterFunctionObjectType(type);
  162. return type;
  163. }
  164. uint32 ScriptFunction::GetFrameHeight(FunctionEntryPointInfo* entryPointInfo) const
  165. {
  166. Assert(this->GetFunctionBody() != nullptr);
  167. return this->GetFunctionBody()->GetFrameHeight(entryPointInfo);
  168. }
  169. bool ScriptFunction::HasFunctionBody()
  170. {
  171. // for asmjs we want to first check if the FunctionObject has a function body. Check that the function is not deferred
  172. return !this->GetFunctionInfo()->IsDeferredParseFunction() && !this->GetFunctionInfo()->IsDeferredDeserializeFunction() && GetParseableFunctionInfo()->IsFunctionParsed();
  173. }
  174. void ScriptFunction::ChangeEntryPoint(ProxyEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint)
  175. {
  176. Assert(entryPoint != nullptr);
  177. Assert(this->GetTypeId() == TypeIds_Function);
  178. #if ENABLE_NATIVE_CODEGEN
  179. Assert(!IsCrossSiteObject() || entryPoint != (Js::JavascriptMethod)checkCodeGenThunk);
  180. #endif
  181. Assert((entryPointInfo != nullptr && this->GetFunctionProxy() != nullptr));
  182. if (this->GetEntryPoint() == entryPoint && this->GetScriptFunctionType()->GetEntryPointInfo() == entryPointInfo)
  183. {
  184. return;
  185. }
  186. bool isAsmJS = false;
  187. if (HasFunctionBody())
  188. {
  189. isAsmJS = this->GetFunctionBody()->GetIsAsmjsMode();
  190. }
  191. // ASMJS:- for asmjs we don't need to update the entry point here as it updates the types entry point
  192. if (!isAsmJS)
  193. {
  194. // We can't go from cross-site to non-cross-site. Update only in the non-cross site case
  195. if (!CrossSite::IsThunk(this->GetEntryPoint()))
  196. {
  197. this->SetEntryPoint(entryPoint);
  198. }
  199. }
  200. // instead update the address in the function entrypoint info
  201. else
  202. {
  203. entryPointInfo->jsMethod = entryPoint;
  204. }
  205. ProxyEntryPointInfo* oldEntryPointInfo = this->GetScriptFunctionType()->GetEntryPointInfo();
  206. if (oldEntryPointInfo
  207. && oldEntryPointInfo != entryPointInfo
  208. && oldEntryPointInfo->SupportsExpiration())
  209. {
  210. // The old entry point could be executing so we need root it to make sure
  211. // it isn't prematurely collected. The rooting is done by queuing it up on the threadContext
  212. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  213. threadContext->QueueFreeOldEntryPointInfoIfInScript((FunctionEntryPointInfo*)oldEntryPointInfo);
  214. }
  215. this->GetScriptFunctionType()->SetEntryPointInfo(entryPointInfo);
  216. }
  217. FunctionProxy * ScriptFunction::GetFunctionProxy() const
  218. {
  219. Assert(this->functionInfo->HasBody());
  220. return this->functionInfo->GetFunctionProxy();
  221. }
  222. JavascriptMethod ScriptFunction::UpdateUndeferredBody(FunctionBody* newFunctionInfo)
  223. {
  224. // Update deferred parsed/serialized function to the real function body
  225. Assert(this->functionInfo->HasBody());
  226. Assert(this->functionInfo->GetFunctionBody() == newFunctionInfo);
  227. Assert(!newFunctionInfo->IsDeferred());
  228. DynamicType * type = this->GetDynamicType();
  229. // If the type is shared, it must be the shared one in the old function proxy
  230. this->functionInfo = newFunctionInfo->GetFunctionInfo();
  231. if (type->GetIsShared())
  232. {
  233. // the type is still shared, we can't modify it, just migrate to the shared one in the function body
  234. this->ReplaceType(newFunctionInfo->EnsureDeferredPrototypeType());
  235. }
  236. // The type has change from the default, it is not share, just use that one.
  237. JavascriptMethod directEntryPoint = newFunctionInfo->GetDirectEntryPoint(newFunctionInfo->GetDefaultEntryPointInfo());
  238. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  239. Assert(directEntryPoint != DefaultDeferredParsingThunk
  240. && directEntryPoint != ProfileDeferredParsingThunk);
  241. #else
  242. Assert(directEntryPoint != DefaultDeferredParsingThunk);
  243. #endif
  244. Js::FunctionEntryPointInfo* defaultEntryPointInfo = newFunctionInfo->GetDefaultFunctionEntryPointInfo();
  245. JavascriptMethod thunkEntryPoint = this->UpdateThunkEntryPoint(defaultEntryPointInfo, directEntryPoint);
  246. this->GetScriptFunctionType()->SetEntryPointInfo(defaultEntryPointInfo);
  247. return thunkEntryPoint;
  248. }
  249. JavascriptMethod ScriptFunction::UpdateThunkEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint)
  250. {
  251. this->ChangeEntryPoint(entryPointInfo, entryPoint);
  252. if (!CrossSite::IsThunk(this->GetEntryPoint()))
  253. {
  254. return entryPoint;
  255. }
  256. // We already pass through the cross site thunk, which would have called the profile thunk already if necessary
  257. // So just call the original entry point if our direct entry is the profile entry thunk
  258. // Otherwise, call the directEntryPoint which may have additional processing to do (e.g. ensure dynamic profile)
  259. Assert(this->IsCrossSiteObject());
  260. if (entryPoint != ProfileEntryThunk)
  261. {
  262. return entryPoint;
  263. }
  264. // Based on the comment below, this shouldn't be a defer deserialization function as it would have a deferred thunk
  265. FunctionBody * functionBody = this->GetFunctionBody();
  266. // The original entry point should be an interpreter thunk or the native entry point;
  267. Assert(functionBody->IsInterpreterThunk() || functionBody->IsNativeOriginalEntryPoint());
  268. return functionBody->GetOriginalEntryPoint();
  269. }
  270. bool ScriptFunction::IsNewEntryPointAvailable()
  271. {
  272. Js::FunctionEntryPointInfo *const defaultEntryPointInfo = this->GetFunctionBody()->GetDefaultFunctionEntryPointInfo();
  273. JavascriptMethod defaultEntryPoint = this->GetFunctionBody()->GetDirectEntryPoint(defaultEntryPointInfo);
  274. return this->GetEntryPoint() != defaultEntryPoint;
  275. }
  276. Var ScriptFunction::GetSourceString() const
  277. {
  278. return this->GetFunctionProxy()->EnsureDeserialized()->GetCachedSourceString();
  279. }
  280. Var ScriptFunction::FormatToString(JavascriptString* inputString)
  281. {
  282. FunctionProxy* proxy = this->GetFunctionProxy();
  283. ParseableFunctionInfo * pFuncBody = proxy->EnsureDeserialized();
  284. Var returnStr = nullptr;
  285. EnterPinnedScope((volatile void**)& inputString);
  286. const char16 * inputStr = inputString->GetString();
  287. const char16 * paramStr = wcschr(inputStr, _u('('));
  288. if (paramStr == nullptr || wcscmp(pFuncBody->GetDisplayName(), Js::Constants::EvalCode) == 0)
  289. {
  290. Assert(pFuncBody->IsEval());
  291. return inputString;
  292. }
  293. ScriptContext* scriptContext = this->GetScriptContext();
  294. JavascriptLibrary* library = scriptContext->GetLibrary();
  295. bool isClassMethod = this->GetFunctionInfo()->IsClassMethod() || this->GetFunctionInfo()->IsClassConstructor();
  296. JavascriptString* prefixString = nullptr;
  297. uint prefixStringLength = 0;
  298. const char16* name = _u("");
  299. charcount_t nameLength = 0;
  300. if (!isClassMethod)
  301. {
  302. prefixString = library->GetFunctionPrefixString();
  303. if (pFuncBody->IsGenerator())
  304. {
  305. prefixString = library->GetGeneratorFunctionPrefixString();
  306. }
  307. else if (pFuncBody->IsAsync())
  308. {
  309. prefixString = library->GetAsyncFunctionPrefixString();
  310. }
  311. prefixStringLength = prefixString->GetLength();
  312. if (pFuncBody->GetIsAccessor())
  313. {
  314. name = pFuncBody->GetShortDisplayName(&nameLength);
  315. }
  316. else if (pFuncBody->GetIsDeclaration() || pFuncBody->GetIsNamedFunctionExpression())
  317. {
  318. name = pFuncBody->GetDisplayName();
  319. nameLength = pFuncBody->GetDisplayNameLength();
  320. if (name == Js::Constants::FunctionCode)
  321. {
  322. name = Js::Constants::Anonymous;
  323. nameLength = Js::Constants::AnonymousLength;
  324. }
  325. }
  326. }
  327. else
  328. {
  329. if (this->GetFunctionInfo()->IsClassConstructor())
  330. {
  331. name = _u("constructor");
  332. nameLength = _countof(_u("constructor")) -1; //subtract off \0
  333. }
  334. else
  335. {
  336. name = pFuncBody->GetShortDisplayName(&nameLength); //strip off prototype.
  337. }
  338. }
  339. ENTER_PINNED_SCOPE(JavascriptString, computedName);
  340. computedName = this->GetComputedName();
  341. if (computedName != nullptr)
  342. {
  343. prefixString = nullptr;
  344. prefixStringLength = 0;
  345. name = computedName->GetString();
  346. nameLength = computedName->GetLength();
  347. }
  348. uint functionBodyLength = inputString->GetLength() - ((uint)(paramStr - inputStr));
  349. size_t totalLength = prefixStringLength + functionBodyLength + nameLength;
  350. if (!IsValidCharCount(totalLength))
  351. {
  352. // We throw here because computed property names are evaluated at runtime and
  353. // thus are not a subset string of function body source (parameter inputString).
  354. // For all other cases totalLength <= inputString->GetLength().
  355. JavascriptExceptionOperators::ThrowOutOfMemory(this->GetScriptContext());
  356. }
  357. char16 * funcBodyStr = RecyclerNewArrayLeaf(this->GetScriptContext()->GetRecycler(), char16, totalLength);
  358. char16 * funcBodyStrStart = funcBodyStr;
  359. if (prefixString != nullptr)
  360. {
  361. js_wmemcpy_s(funcBodyStr, prefixStringLength, prefixString->GetString(), prefixStringLength);
  362. funcBodyStrStart += prefixStringLength;
  363. }
  364. js_wmemcpy_s(funcBodyStrStart, nameLength, name, nameLength);
  365. funcBodyStrStart = funcBodyStrStart + nameLength;
  366. js_wmemcpy_s(funcBodyStrStart, functionBodyLength, paramStr, functionBodyLength);
  367. returnStr = LiteralString::NewCopyBuffer(funcBodyStr, (charcount_t)totalLength, scriptContext);
  368. LEAVE_PINNED_SCOPE(); // computedName
  369. LeavePinnedScope(); // inputString
  370. return returnStr;
  371. }
  372. Var ScriptFunction::EnsureSourceString()
  373. {
  374. // The function may be defer serialize, need to be deserialized
  375. FunctionProxy* proxy = this->GetFunctionProxy();
  376. ParseableFunctionInfo * pFuncBody = proxy->EnsureDeserialized();
  377. Var cachedSourceString = pFuncBody->GetCachedSourceString();
  378. if (cachedSourceString != nullptr)
  379. {
  380. return cachedSourceString;
  381. }
  382. ScriptContext * scriptContext = this->GetScriptContext();
  383. //Library code should behave the same way as RuntimeFunctions
  384. Utf8SourceInfo* source = pFuncBody->GetUtf8SourceInfo();
  385. if ((source != nullptr && source->GetIsLibraryCode())
  386. #ifdef ENABLE_WASM
  387. || (pFuncBody->IsWasmFunction())
  388. #endif
  389. )
  390. {
  391. //Don't display if it is anonymous function
  392. charcount_t displayNameLength = 0;
  393. PCWSTR displayName = pFuncBody->GetShortDisplayName(&displayNameLength);
  394. cachedSourceString = JavascriptFunction::GetLibraryCodeDisplayString(scriptContext, displayName);
  395. }
  396. else if (!pFuncBody->GetUtf8SourceInfo()->GetIsXDomain()
  397. // To avoid backward compat issue, we will not give out sourceString for function if it is called from
  398. // window.onerror trying to retrieve arguments.callee.caller.
  399. && !(pFuncBody->GetUtf8SourceInfo()->GetIsXDomainString() && scriptContext->GetThreadContext()->HasUnhandledException())
  400. )
  401. {
  402. // Decode UTF8 into Unicode
  403. // Consider: Should we have a JavascriptUtf8Substring class which defers decoding
  404. // until it's needed?
  405. charcount_t cch = pFuncBody->LengthInChars();
  406. size_t cbLength = pFuncBody->LengthInBytes();
  407. LPCUTF8 pbStart = pFuncBody->GetSource(_u("ScriptFunction::EnsureSourceString"));
  408. BufferStringBuilder builder(cch, scriptContext);
  409. utf8::DecodeOptions options = pFuncBody->GetUtf8SourceInfo()->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
  410. size_t decodedCount = utf8::DecodeUnitsInto(builder.DangerousGetWritableBuffer(), pbStart, pbStart + cbLength, options);
  411. if (decodedCount != cch)
  412. {
  413. AssertMsg(false, "Decoded incorrect number of characters for function body");
  414. Js::Throw::FatalInternalError();
  415. }
  416. if (pFuncBody->IsLambda() || isActiveScript || this->GetFunctionInfo()->IsClassConstructor()
  417. #ifdef ENABLE_PROJECTION
  418. || scriptContext->GetConfig()->IsWinRTEnabled()
  419. #endif
  420. )
  421. {
  422. cachedSourceString = builder.ToString();
  423. }
  424. else
  425. {
  426. cachedSourceString = FormatToString(builder.ToString());
  427. }
  428. }
  429. else
  430. {
  431. cachedSourceString = scriptContext->GetLibrary()->GetXDomainFunctionDisplayString();
  432. }
  433. Assert(cachedSourceString != nullptr);
  434. pFuncBody->SetCachedSourceString(cachedSourceString);
  435. return cachedSourceString;
  436. }
  437. #if ENABLE_TTD
  438. void ScriptFunction::MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor)
  439. {
  440. Js::FunctionBody* fb = TTD::JsSupport::ForceAndGetFunctionBody(this->GetParseableFunctionInfo());
  441. extractor->MarkFunctionBody(fb);
  442. Js::FrameDisplay* environment = this->GetEnvironment();
  443. if(environment->GetLength() != 0)
  444. {
  445. extractor->MarkScriptFunctionScopeInfo(environment);
  446. }
  447. if(this->cachedScopeObj != nullptr)
  448. {
  449. extractor->MarkVisitVar(this->cachedScopeObj);
  450. }
  451. if(this->homeObj != nullptr)
  452. {
  453. extractor->MarkVisitVar(this->homeObj);
  454. }
  455. if(this->computedNameVar != nullptr)
  456. {
  457. extractor->MarkVisitVar(this->computedNameVar);
  458. }
  459. }
  460. void ScriptFunction::ProcessCorePaths()
  461. {
  462. TTD::RuntimeContextInfo* rctxInfo = this->GetScriptContext()->TTDWellKnownInfo;
  463. //do the body path mark
  464. Js::FunctionBody* fb = TTD::JsSupport::ForceAndGetFunctionBody(this->GetParseableFunctionInfo());
  465. rctxInfo->EnqueueNewFunctionBodyObject(this, fb, _u("!fbody"));
  466. Js::FrameDisplay* environment = this->GetEnvironment();
  467. uint32 scopeCount = environment->GetLength();
  468. for(uint32 i = 0; i < scopeCount; ++i)
  469. {
  470. TTD::UtilSupport::TTAutoString scopePathString;
  471. rctxInfo->BuildEnvironmentIndexBuffer(i, scopePathString);
  472. void* scope = environment->GetItem(i);
  473. switch(environment->GetScopeType(scope))
  474. {
  475. case Js::ScopeType::ScopeType_ActivationObject:
  476. case Js::ScopeType::ScopeType_WithScope:
  477. {
  478. rctxInfo->EnqueueNewPathVarAsNeeded(this, (Js::Var)scope, scopePathString.GetStrValue());
  479. break;
  480. }
  481. case Js::ScopeType::ScopeType_SlotArray:
  482. {
  483. Js::ScopeSlots slotArray = (Field(Js::Var)*)scope;
  484. uint slotArrayCount = static_cast<uint>(slotArray.GetCount());
  485. //get the function body associated with the scope
  486. if (slotArray.IsDebuggerScopeSlotArray())
  487. {
  488. rctxInfo->AddWellKnownDebuggerScopePath(this, slotArray.GetDebuggerScope(), i);
  489. }
  490. else
  491. {
  492. rctxInfo->EnqueueNewFunctionBodyObject(this, slotArray.GetFunctionInfo()->GetFunctionBody(), scopePathString.GetStrValue());
  493. }
  494. for(uint j = 0; j < slotArrayCount; j++)
  495. {
  496. Js::Var sval = slotArray.Get(j);
  497. TTD::UtilSupport::TTAutoString slotPathString;
  498. rctxInfo->BuildEnvironmentIndexAndSlotBuffer(i, j, slotPathString);
  499. rctxInfo->EnqueueNewPathVarAsNeeded(this, sval, slotPathString.GetStrValue());
  500. }
  501. break;
  502. }
  503. default:
  504. TTDAssert(false, "Unknown scope kind");
  505. }
  506. }
  507. if(this->cachedScopeObj != nullptr)
  508. {
  509. this->GetScriptContext()->TTDWellKnownInfo->EnqueueNewPathVarAsNeeded(this, this->cachedScopeObj, _u("_cachedScopeObj"));
  510. }
  511. if(this->homeObj != nullptr)
  512. {
  513. this->GetScriptContext()->TTDWellKnownInfo->EnqueueNewPathVarAsNeeded(this, this->homeObj, _u("_homeObj"));
  514. }
  515. }
  516. TTD::NSSnapObjects::SnapObjectType ScriptFunction::GetSnapTag_TTD() const
  517. {
  518. return TTD::NSSnapObjects::SnapObjectType::SnapScriptFunctionObject;
  519. }
  520. void ScriptFunction::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  521. {
  522. TTDAssert(this->GetFunctionInfo() != nullptr, "We are only doing this for functions with ParseableFunctionInfo.");
  523. TTD::NSSnapObjects::SnapScriptFunctionInfo* ssfi = alloc.SlabAllocateStruct<TTD::NSSnapObjects::SnapScriptFunctionInfo>();
  524. Js::FunctionBody* fb = TTD::JsSupport::ForceAndGetFunctionBody(this->GetParseableFunctionInfo());
  525. alloc.CopyNullTermStringInto(fb->GetDisplayName(), ssfi->DebugFunctionName);
  526. ssfi->BodyRefId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(fb);
  527. Js::FrameDisplay* environment = this->GetEnvironment();
  528. ssfi->ScopeId = TTD_INVALID_PTR_ID;
  529. if(environment->GetLength() != 0)
  530. {
  531. ssfi->ScopeId = TTD_CONVERT_SCOPE_TO_PTR_ID(environment);
  532. }
  533. ssfi->CachedScopeObjId = TTD_INVALID_PTR_ID;
  534. if(this->cachedScopeObj != nullptr)
  535. {
  536. ssfi->CachedScopeObjId = TTD_CONVERT_VAR_TO_PTR_ID(this->cachedScopeObj);
  537. }
  538. ssfi->HomeObjId = TTD_INVALID_PTR_ID;
  539. if(this->homeObj != nullptr)
  540. {
  541. ssfi->HomeObjId = TTD_CONVERT_VAR_TO_PTR_ID(this->homeObj);
  542. }
  543. ssfi->ComputedNameInfo = TTD_CONVERT_JSVAR_TO_TTDVAR(this->computedNameVar);
  544. ssfi->HasSuperReference = this->hasSuperReference;
  545. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapScriptFunctionInfo*, TTD::NSSnapObjects::SnapObjectType::SnapScriptFunctionObject>(objData, ssfi);
  546. }
  547. #endif
  548. AsmJsScriptFunction::AsmJsScriptFunction(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType) :
  549. ScriptFunction(proxy, deferredPrototypeType), m_moduleEnvironment(nullptr)
  550. {}
  551. AsmJsScriptFunction::AsmJsScriptFunction(DynamicType * type) :
  552. ScriptFunction(type), m_moduleEnvironment(nullptr)
  553. {}
  554. bool AsmJsScriptFunction::Is(Var func)
  555. {
  556. return ScriptFunction::Is(func) && ScriptFunction::UnsafeFromVar(func)->IsAsmJsFunction();
  557. }
  558. AsmJsScriptFunction* AsmJsScriptFunction::FromVar(Var func)
  559. {
  560. AssertOrFailFast(AsmJsScriptFunction::Is(func));
  561. return reinterpret_cast<AsmJsScriptFunction *>(func);
  562. }
  563. AsmJsScriptFunction* AsmJsScriptFunction::UnsafeFromVar(Var func)
  564. {
  565. Assert(AsmJsScriptFunction::Is(func));
  566. return reinterpret_cast<AsmJsScriptFunction *>(func);
  567. }
  568. AsmJsScriptFunction * AsmJsScriptFunction::OP_NewAsmJsFunc(FrameDisplay *environment, FunctionInfoPtrPtr infoRef)
  569. {
  570. AssertMsg(infoRef != nullptr, "BYTE-CODE VERIFY: Must specify a valid function to create");
  571. FunctionProxy* functionProxy = (*infoRef)->GetFunctionProxy();
  572. AssertMsg(functionProxy != nullptr, "BYTE-CODE VERIFY: Must specify a valid function to create");
  573. ScriptContext* scriptContext = functionProxy->GetScriptContext();
  574. bool hasSuperReference = functionProxy->HasSuperReference();
  575. AsmJsScriptFunction* asmJsFunc = scriptContext->GetLibrary()->CreateAsmJsScriptFunction(functionProxy);
  576. asmJsFunc->SetEnvironment(environment);
  577. Assert(!hasSuperReference);
  578. asmJsFunc->SetHasSuperReference(hasSuperReference);
  579. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(asmJsFunc, EtwTrace::GetFunctionId(functionProxy)));
  580. return asmJsFunc;
  581. }
  582. JavascriptArrayBuffer* AsmJsScriptFunction::GetAsmJsArrayBuffer() const
  583. {
  584. #ifdef ASMJS_PLAT
  585. return (JavascriptArrayBuffer*)PointerValue(
  586. *(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset));
  587. #else
  588. Assert(UNREACHED);
  589. return nullptr;
  590. #endif
  591. }
  592. #ifdef ENABLE_WASM
  593. WasmScriptFunction::WasmScriptFunction(DynamicType * type) :
  594. AsmJsScriptFunction(type), m_signature(nullptr)
  595. {}
  596. WasmScriptFunction::WasmScriptFunction(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType) :
  597. AsmJsScriptFunction(proxy, deferredPrototypeType), m_signature(nullptr)
  598. {}
  599. bool WasmScriptFunction::Is(Var func)
  600. {
  601. return ScriptFunction::Is(func) && ScriptFunction::UnsafeFromVar(func)->IsWasmFunction();
  602. }
  603. WasmScriptFunction* WasmScriptFunction::FromVar(Var func)
  604. {
  605. AssertOrFailFast(WasmScriptFunction::Is(func));
  606. return reinterpret_cast<WasmScriptFunction *>(func);
  607. }
  608. WasmScriptFunction* WasmScriptFunction::UnsafeFromVar(Var func)
  609. {
  610. Assert(WasmScriptFunction::Is(func));
  611. return reinterpret_cast<WasmScriptFunction *>(func);
  612. }
  613. WebAssemblyMemory* WasmScriptFunction::GetWebAssemblyMemory() const
  614. {
  615. return (WebAssemblyMemory*)PointerValue(
  616. *(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset));
  617. }
  618. #endif
  619. ScriptFunctionWithInlineCache::ScriptFunctionWithInlineCache(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType) :
  620. ScriptFunction(proxy, deferredPrototypeType), hasOwnInlineCaches(false)
  621. {}
  622. ScriptFunctionWithInlineCache::ScriptFunctionWithInlineCache(DynamicType * type) :
  623. ScriptFunction(type), hasOwnInlineCaches(false)
  624. {}
  625. bool ScriptFunctionWithInlineCache::Is(Var func)
  626. {
  627. return ScriptFunction::Is(func) && ScriptFunction::UnsafeFromVar(func)->GetHasInlineCaches();
  628. }
  629. ScriptFunctionWithInlineCache* ScriptFunctionWithInlineCache::FromVar(Var func)
  630. {
  631. AssertOrFailFast(ScriptFunctionWithInlineCache::Is(func));
  632. return reinterpret_cast<ScriptFunctionWithInlineCache *>(func);
  633. }
  634. ScriptFunctionWithInlineCache* ScriptFunctionWithInlineCache::UnsafeFromVar(Var func)
  635. {
  636. Assert(ScriptFunctionWithInlineCache::Is(func));
  637. return reinterpret_cast<ScriptFunctionWithInlineCache *>(func);
  638. }
  639. InlineCache * ScriptFunctionWithInlineCache::GetInlineCache(uint index)
  640. {
  641. void** inlineCaches = this->GetInlineCaches();
  642. AssertOrFailFast(inlineCaches != nullptr);
  643. AssertOrFailFast(index < this->GetInlineCacheCount());
  644. #if DBG
  645. Assert(this->m_inlineCacheTypes[index] == InlineCacheTypeNone ||
  646. this->m_inlineCacheTypes[index] == InlineCacheTypeInlineCache);
  647. this->m_inlineCacheTypes[index] = InlineCacheTypeInlineCache;
  648. #endif
  649. return reinterpret_cast<InlineCache *>(PointerValue(inlineCaches[index]));
  650. }
  651. Field(void**) ScriptFunctionWithInlineCache::GetInlineCaches()
  652. {
  653. // If script function have inline caches pointing to function body and function body got reparsed we need to reset cache
  654. if (this->GetHasInlineCaches() && !this->GetHasOwnInlineCaches())
  655. {
  656. // Script function have inline caches pointing to function body
  657. if (!this->HasFunctionBody())
  658. {
  659. // Function body got re-deferred and have not been re-parsed yet. Reset cache to null
  660. this->m_inlineCaches = nullptr;
  661. this->inlineCacheCount = 0;
  662. this->SetHasInlineCaches(false);
  663. }
  664. else if (this->m_inlineCaches != this->GetFunctionBody()->GetInlineCaches())
  665. {
  666. // Function body got reparsed we need to reset cache
  667. Assert(this->GetFunctionBody()->GetCompileCount() > 1);
  668. this->SetInlineCachesFromFunctionBody();
  669. }
  670. }
  671. return this->m_inlineCaches;
  672. }
  673. void ScriptFunctionWithInlineCache::SetInlineCachesFromFunctionBody()
  674. {
  675. SetHasInlineCaches(true);
  676. Js::FunctionBody* functionBody = this->GetFunctionBody();
  677. this->m_inlineCaches = functionBody->GetInlineCaches();
  678. #if DBG
  679. this->m_inlineCacheTypes = functionBody->GetInlineCacheTypes();
  680. #endif
  681. this->rootObjectLoadInlineCacheStart = functionBody->GetRootObjectLoadInlineCacheStart();
  682. this->rootObjectLoadMethodInlineCacheStart = functionBody->GetRootObjectLoadMethodInlineCacheStart();
  683. this->rootObjectStoreInlineCacheStart = functionBody->GetRootObjectStoreInlineCacheStart();
  684. this->inlineCacheCount = functionBody->GetInlineCacheCount();
  685. this->isInstInlineCacheCount = functionBody->GetIsInstInlineCacheCount();
  686. }
  687. void ScriptFunctionWithInlineCache::CreateInlineCache()
  688. {
  689. Js::FunctionBody *functionBody = this->GetFunctionBody();
  690. this->rootObjectLoadInlineCacheStart = functionBody->GetRootObjectLoadInlineCacheStart();
  691. this->rootObjectStoreInlineCacheStart = functionBody->GetRootObjectStoreInlineCacheStart();
  692. this->inlineCacheCount = functionBody->GetInlineCacheCount();
  693. this->isInstInlineCacheCount = functionBody->GetIsInstInlineCacheCount();
  694. SetHasInlineCaches(true);
  695. AllocateInlineCache();
  696. hasOwnInlineCaches = true;
  697. }
  698. void ScriptFunctionWithInlineCache::Finalize(bool isShutdown)
  699. {
  700. if (isShutdown)
  701. {
  702. FreeOwnInlineCaches<true>();
  703. }
  704. else
  705. {
  706. FreeOwnInlineCaches<false>();
  707. }
  708. }
  709. template<bool isShutdown>
  710. void ScriptFunctionWithInlineCache::FreeOwnInlineCaches()
  711. {
  712. uint isInstInlineCacheStart = this->GetInlineCacheCount();
  713. uint totalCacheCount = isInstInlineCacheStart + isInstInlineCacheCount;
  714. if (this->GetHasInlineCaches() && this->m_inlineCaches && this->hasOwnInlineCaches)
  715. {
  716. Js::ScriptContext* scriptContext = this->GetParseableFunctionInfo()->GetScriptContext();
  717. uint i = 0;
  718. uint unregisteredInlineCacheCount = 0;
  719. uint plainInlineCacheEnd = rootObjectLoadInlineCacheStart;
  720. __analysis_assume(plainInlineCacheEnd < totalCacheCount);
  721. for (; i < plainInlineCacheEnd; i++)
  722. {
  723. if (this->m_inlineCaches[i])
  724. {
  725. InlineCache* inlineCache = (InlineCache*)(void*)this->m_inlineCaches[i];
  726. if (isShutdown)
  727. {
  728. inlineCache->Clear();
  729. }
  730. else if(!scriptContext->IsClosed())
  731. {
  732. if (inlineCache->RemoveFromInvalidationList())
  733. {
  734. unregisteredInlineCacheCount++;
  735. }
  736. AllocatorDelete(InlineCacheAllocator, scriptContext->GetInlineCacheAllocator(), inlineCache);
  737. }
  738. this->m_inlineCaches[i] = nullptr;
  739. }
  740. }
  741. i = isInstInlineCacheStart;
  742. for (; i < totalCacheCount; i++)
  743. {
  744. if (this->m_inlineCaches[i])
  745. {
  746. if (isShutdown)
  747. {
  748. ((IsInstInlineCache*)this->m_inlineCaches[i])->Clear();
  749. }
  750. else if (!scriptContext->IsClosed())
  751. {
  752. AllocatorDelete(CacheAllocator, scriptContext->GetIsInstInlineCacheAllocator(), (IsInstInlineCache*)(void*)this->m_inlineCaches[i]);
  753. }
  754. this->m_inlineCaches[i] = nullptr;
  755. }
  756. }
  757. if (unregisteredInlineCacheCount > 0)
  758. {
  759. AssertMsg(!isShutdown && !scriptContext->IsClosed(), "Unregistration of inlineCache should only be done if this is not shutdown or scriptContext closing.");
  760. scriptContext->GetThreadContext()->NotifyInlineCacheBatchUnregistered(unregisteredInlineCacheCount);
  761. }
  762. }
  763. }
  764. void ScriptFunctionWithInlineCache::AllocateInlineCache()
  765. {
  766. Assert(this->m_inlineCaches == nullptr);
  767. uint isInstInlineCacheStart = this->GetInlineCacheCount();
  768. uint totalCacheCount = isInstInlineCacheStart + isInstInlineCacheCount;
  769. Js::FunctionBody* functionBody = this->GetFunctionBody();
  770. if (totalCacheCount != 0)
  771. {
  772. // Root object inline cache are not leaf
  773. Js::ScriptContext* scriptContext = this->GetFunctionBody()->GetScriptContext();
  774. void ** inlineCaches = RecyclerNewArrayZ(scriptContext->GetRecycler() ,
  775. void*, totalCacheCount);
  776. #if DBG
  777. this->m_inlineCacheTypes = RecyclerNewArrayLeafZ(scriptContext->GetRecycler(),
  778. byte, totalCacheCount);
  779. #endif
  780. uint i = 0;
  781. uint plainInlineCacheEnd = rootObjectLoadInlineCacheStart;
  782. __analysis_assume(plainInlineCacheEnd <= totalCacheCount);
  783. for (; i < plainInlineCacheEnd; i++)
  784. {
  785. inlineCaches[i] = AllocatorNewZ(InlineCacheAllocator,
  786. scriptContext->GetInlineCacheAllocator(), InlineCache);
  787. }
  788. Js::RootObjectBase * rootObject = functionBody->GetRootObject();
  789. ThreadContext * threadContext = scriptContext->GetThreadContext();
  790. uint rootObjectLoadInlineCacheEnd = rootObjectLoadMethodInlineCacheStart;
  791. __analysis_assume(rootObjectLoadInlineCacheEnd <= totalCacheCount);
  792. for (; i < rootObjectLoadInlineCacheEnd; i++)
  793. {
  794. inlineCaches[i] = rootObject->GetInlineCache(
  795. threadContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(i)), false, false);
  796. }
  797. uint rootObjectLoadMethodInlineCacheEnd = rootObjectStoreInlineCacheStart;
  798. __analysis_assume(rootObjectLoadMethodInlineCacheEnd <= totalCacheCount);
  799. for (; i < rootObjectLoadMethodInlineCacheEnd; i++)
  800. {
  801. inlineCaches[i] = rootObject->GetInlineCache(
  802. threadContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(i)), true, false);
  803. }
  804. uint rootObjectStoreInlineCacheEnd = isInstInlineCacheStart;
  805. __analysis_assume(rootObjectStoreInlineCacheEnd <= totalCacheCount);
  806. for (; i < rootObjectStoreInlineCacheEnd; i++)
  807. {
  808. #pragma prefast(suppress:6386, "The analysis assume didn't help prefast figure out this is in range")
  809. inlineCaches[i] = rootObject->GetInlineCache(
  810. threadContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(i)), false, true);
  811. }
  812. for (; i < totalCacheCount; i++)
  813. {
  814. inlineCaches[i] = AllocatorNewStructZ(CacheAllocator,
  815. functionBody->GetScriptContext()->GetIsInstInlineCacheAllocator(), IsInstInlineCache);
  816. }
  817. #if DBG
  818. this->m_inlineCacheTypes = RecyclerNewArrayLeafZ(functionBody->GetScriptContext()->GetRecycler(),
  819. byte, totalCacheCount);
  820. #endif
  821. this->m_inlineCaches = inlineCaches;
  822. }
  823. }
  824. bool ScriptFunction::GetSymbolName(const char16** symbolName, charcount_t* length) const
  825. {
  826. if (nullptr != this->computedNameVar && JavascriptSymbol::Is(this->computedNameVar))
  827. {
  828. const PropertyRecord* symbolRecord = JavascriptSymbol::FromVar(this->computedNameVar)->GetValue();
  829. *symbolName = symbolRecord->GetBuffer();
  830. *length = symbolRecord->GetLength();
  831. return true;
  832. }
  833. *symbolName = nullptr;
  834. *length = 0;
  835. return false;
  836. }
  837. JavascriptString* ScriptFunction::GetDisplayNameImpl() const
  838. {
  839. Assert(this->GetFunctionProxy() != nullptr); // The caller should guarantee a proxy exists
  840. ParseableFunctionInfo * func = this->GetFunctionProxy()->EnsureDeserialized();
  841. const char16* name = nullptr;
  842. charcount_t length = 0;
  843. JavascriptString* returnStr = nullptr;
  844. ENTER_PINNED_SCOPE(JavascriptString, computedName);
  845. if (computedNameVar != nullptr)
  846. {
  847. const char16* symbolName = nullptr;
  848. charcount_t symbolNameLength = 0;
  849. if (this->GetSymbolName(&symbolName, &symbolNameLength))
  850. {
  851. if (symbolNameLength == 0)
  852. {
  853. name = symbolName;
  854. }
  855. else
  856. {
  857. name = FunctionProxy::WrapWithBrackets(symbolName, symbolNameLength, this->GetScriptContext());
  858. length = symbolNameLength + 2; //adding 2 to length for brackets
  859. }
  860. }
  861. else
  862. {
  863. computedName = this->GetComputedName();
  864. if (!func->GetIsAccessor())
  865. {
  866. return computedName;
  867. }
  868. name = computedName->GetString();
  869. length = computedName->GetLength();
  870. }
  871. }
  872. else
  873. {
  874. name = Constants::Empty;
  875. if (func->GetIsNamedFunctionExpression()) // GetIsNamedFunctionExpression -> ex. var a = function foo() {} where name is foo
  876. {
  877. name = func->GetShortDisplayName(&length);
  878. }
  879. else if (func->GetIsNameIdentifierRef()) // GetIsNameIdentifierRef -> confirms a name is not attached like o.x = function() {}
  880. {
  881. if (this->GetScriptContext()->GetConfig()->IsES6FunctionNameFullEnabled())
  882. {
  883. name = func->GetShortDisplayName(&length);
  884. }
  885. else if (func->GetIsDeclaration() || // GetIsDeclaration -> ex. function foo () {}
  886. func->GetIsAccessor() || // GetIsAccessor -> ex. var a = { get f() {}} new enough syntax that we do not have to disable by default
  887. func->IsLambda() || // IsLambda -> ex. var y = { o : () => {}}
  888. GetHomeObj()) // GetHomeObj -> ex. var o = class {}, confirms this is a constructor or method on a class
  889. {
  890. name = func->GetShortDisplayName(&length);
  891. }
  892. }
  893. }
  894. AssertMsg(IsValidCharCount(length), "JavascriptString can't be larger than charcount_t");
  895. returnStr = DisplayNameHelper(name, static_cast<charcount_t>(length));
  896. LEAVE_PINNED_SCOPE();
  897. return returnStr;
  898. }
  899. bool ScriptFunction::IsAnonymousFunction() const
  900. {
  901. return this->GetFunctionProxy()->GetIsAnonymousFunction();
  902. }
  903. JavascriptString* ScriptFunction::GetComputedName() const
  904. {
  905. JavascriptString* computedName = nullptr;
  906. ScriptContext* scriptContext = this->GetScriptContext();
  907. if (computedNameVar != nullptr)
  908. {
  909. if (TaggedInt::Is(computedNameVar))
  910. {
  911. computedName = TaggedInt::ToString(computedNameVar, scriptContext);
  912. }
  913. else
  914. {
  915. computedName = JavascriptConversion::ToString(computedNameVar, scriptContext);
  916. }
  917. return computedName;
  918. }
  919. return nullptr;
  920. }
  921. void ScriptFunctionWithInlineCache::ClearInlineCacheOnFunctionObject()
  922. {
  923. if (NULL != this->m_inlineCaches)
  924. {
  925. FreeOwnInlineCaches<false>();
  926. this->m_inlineCaches = nullptr;
  927. this->inlineCacheCount = 0;
  928. this->rootObjectLoadInlineCacheStart = 0;
  929. this->rootObjectLoadMethodInlineCacheStart = 0;
  930. this->rootObjectStoreInlineCacheStart = 0;
  931. this->isInstInlineCacheCount = 0;
  932. }
  933. SetHasInlineCaches(false);
  934. }
  935. void ScriptFunctionWithInlineCache::ClearBorrowedInlineCacheOnFunctionObject()
  936. {
  937. if (this->hasOwnInlineCaches)
  938. {
  939. return;
  940. }
  941. ClearInlineCacheOnFunctionObject();
  942. }
  943. }