2
0

ScriptFunction.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  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. this->ExtractSnapObjectDataIntoSnapScriptFunctionInfo(ssfi, alloc);
  525. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapScriptFunctionInfo*, TTD::NSSnapObjects::SnapObjectType::SnapScriptFunctionObject>(objData, ssfi);
  526. }
  527. // TODO: Fixup function definition - something funky w/ header file includes - cycles?
  528. void ScriptFunction::ExtractSnapObjectDataIntoSnapScriptFunctionInfo(/*TTD::NSSnapObjects::SnapScriptFunctionInfo* */ void* snapScriptFunctionInfo, TTD::SlabAllocator& alloc)
  529. {
  530. TTD::NSSnapObjects::SnapScriptFunctionInfo* ssfi = reinterpret_cast<TTD::NSSnapObjects::SnapScriptFunctionInfo*>(snapScriptFunctionInfo);
  531. Js::FunctionBody* fb = TTD::JsSupport::ForceAndGetFunctionBody(this->GetParseableFunctionInfo());
  532. alloc.CopyNullTermStringInto(fb->GetDisplayName(), ssfi->DebugFunctionName);
  533. ssfi->BodyRefId = TTD_CONVERT_FUNCTIONBODY_TO_PTR_ID(fb);
  534. Js::FrameDisplay* environment = this->GetEnvironment();
  535. ssfi->ScopeId = TTD_INVALID_PTR_ID;
  536. if (environment->GetLength() != 0)
  537. {
  538. ssfi->ScopeId = TTD_CONVERT_SCOPE_TO_PTR_ID(environment);
  539. }
  540. ssfi->CachedScopeObjId = TTD_INVALID_PTR_ID;
  541. if (this->cachedScopeObj != nullptr)
  542. {
  543. ssfi->CachedScopeObjId = TTD_CONVERT_VAR_TO_PTR_ID(this->cachedScopeObj);
  544. }
  545. ssfi->HomeObjId = TTD_INVALID_PTR_ID;
  546. if (this->homeObj != nullptr)
  547. {
  548. ssfi->HomeObjId = TTD_CONVERT_VAR_TO_PTR_ID(this->homeObj);
  549. }
  550. ssfi->ComputedNameInfo = TTD_CONVERT_JSVAR_TO_TTDVAR(this->computedNameVar);
  551. ssfi->HasSuperReference = this->hasSuperReference;
  552. }
  553. #endif
  554. AsmJsScriptFunction::AsmJsScriptFunction(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType) :
  555. ScriptFunction(proxy, deferredPrototypeType), m_moduleEnvironment(nullptr)
  556. {}
  557. AsmJsScriptFunction::AsmJsScriptFunction(DynamicType * type) :
  558. ScriptFunction(type), m_moduleEnvironment(nullptr)
  559. {}
  560. bool AsmJsScriptFunction::Is(Var func)
  561. {
  562. return ScriptFunction::Is(func) && ScriptFunction::UnsafeFromVar(func)->IsAsmJsFunction();
  563. }
  564. AsmJsScriptFunction* AsmJsScriptFunction::FromVar(Var func)
  565. {
  566. AssertOrFailFast(AsmJsScriptFunction::Is(func));
  567. return reinterpret_cast<AsmJsScriptFunction *>(func);
  568. }
  569. AsmJsScriptFunction* AsmJsScriptFunction::UnsafeFromVar(Var func)
  570. {
  571. Assert(AsmJsScriptFunction::Is(func));
  572. return reinterpret_cast<AsmJsScriptFunction *>(func);
  573. }
  574. AsmJsScriptFunction * AsmJsScriptFunction::OP_NewAsmJsFunc(FrameDisplay *environment, FunctionInfoPtrPtr infoRef)
  575. {
  576. AssertMsg(infoRef != nullptr, "BYTE-CODE VERIFY: Must specify a valid function to create");
  577. FunctionProxy* functionProxy = (*infoRef)->GetFunctionProxy();
  578. AssertMsg(functionProxy != nullptr, "BYTE-CODE VERIFY: Must specify a valid function to create");
  579. ScriptContext* scriptContext = functionProxy->GetScriptContext();
  580. bool hasSuperReference = functionProxy->HasSuperReference();
  581. AsmJsScriptFunction* asmJsFunc = scriptContext->GetLibrary()->CreateAsmJsScriptFunction(functionProxy);
  582. asmJsFunc->SetEnvironment(environment);
  583. Assert(!hasSuperReference);
  584. asmJsFunc->SetHasSuperReference(hasSuperReference);
  585. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(asmJsFunc, EtwTrace::GetFunctionId(functionProxy)));
  586. return asmJsFunc;
  587. }
  588. JavascriptArrayBuffer* AsmJsScriptFunction::GetAsmJsArrayBuffer() const
  589. {
  590. #ifdef ASMJS_PLAT
  591. return (JavascriptArrayBuffer*)PointerValue(
  592. *(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset));
  593. #else
  594. Assert(UNREACHED);
  595. return nullptr;
  596. #endif
  597. }
  598. #ifdef ENABLE_WASM
  599. WasmScriptFunction::WasmScriptFunction(DynamicType * type) :
  600. AsmJsScriptFunction(type), m_signature(nullptr)
  601. {}
  602. WasmScriptFunction::WasmScriptFunction(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType) :
  603. AsmJsScriptFunction(proxy, deferredPrototypeType), m_signature(nullptr)
  604. {}
  605. bool WasmScriptFunction::Is(Var func)
  606. {
  607. return ScriptFunction::Is(func) && ScriptFunction::UnsafeFromVar(func)->IsWasmFunction();
  608. }
  609. WasmScriptFunction* WasmScriptFunction::FromVar(Var func)
  610. {
  611. AssertOrFailFast(WasmScriptFunction::Is(func));
  612. return reinterpret_cast<WasmScriptFunction *>(func);
  613. }
  614. WasmScriptFunction* WasmScriptFunction::UnsafeFromVar(Var func)
  615. {
  616. Assert(WasmScriptFunction::Is(func));
  617. return reinterpret_cast<WasmScriptFunction *>(func);
  618. }
  619. WebAssemblyMemory* WasmScriptFunction::GetWebAssemblyMemory() const
  620. {
  621. return (WebAssemblyMemory*)PointerValue(
  622. *(this->GetModuleEnvironment() + AsmJsModuleMemory::MemoryTableBeginOffset));
  623. }
  624. #endif
  625. ScriptFunctionWithInlineCache::ScriptFunctionWithInlineCache(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType) :
  626. ScriptFunction(proxy, deferredPrototypeType), hasOwnInlineCaches(false)
  627. {}
  628. ScriptFunctionWithInlineCache::ScriptFunctionWithInlineCache(DynamicType * type) :
  629. ScriptFunction(type), hasOwnInlineCaches(false)
  630. {}
  631. bool ScriptFunctionWithInlineCache::Is(Var func)
  632. {
  633. return ScriptFunction::Is(func) && ScriptFunction::UnsafeFromVar(func)->GetHasInlineCaches();
  634. }
  635. ScriptFunctionWithInlineCache* ScriptFunctionWithInlineCache::FromVar(Var func)
  636. {
  637. AssertOrFailFast(ScriptFunctionWithInlineCache::Is(func));
  638. return reinterpret_cast<ScriptFunctionWithInlineCache *>(func);
  639. }
  640. ScriptFunctionWithInlineCache* ScriptFunctionWithInlineCache::UnsafeFromVar(Var func)
  641. {
  642. Assert(ScriptFunctionWithInlineCache::Is(func));
  643. return reinterpret_cast<ScriptFunctionWithInlineCache *>(func);
  644. }
  645. InlineCache * ScriptFunctionWithInlineCache::GetInlineCache(uint index)
  646. {
  647. void** inlineCaches = this->GetInlineCaches();
  648. AssertOrFailFast(inlineCaches != nullptr);
  649. AssertOrFailFast(index < this->GetInlineCacheCount());
  650. #if DBG
  651. Assert(this->m_inlineCacheTypes[index] == InlineCacheTypeNone ||
  652. this->m_inlineCacheTypes[index] == InlineCacheTypeInlineCache);
  653. this->m_inlineCacheTypes[index] = InlineCacheTypeInlineCache;
  654. #endif
  655. return reinterpret_cast<InlineCache *>(PointerValue(inlineCaches[index]));
  656. }
  657. Field(void**) ScriptFunctionWithInlineCache::GetInlineCaches()
  658. {
  659. // If script function have inline caches pointing to function body and function body got reparsed we need to reset cache
  660. if (this->GetHasInlineCaches() && !this->GetHasOwnInlineCaches())
  661. {
  662. // Script function have inline caches pointing to function body
  663. if (!this->HasFunctionBody())
  664. {
  665. // Function body got re-deferred and have not been re-parsed yet. Reset cache to null
  666. this->m_inlineCaches = nullptr;
  667. this->inlineCacheCount = 0;
  668. this->SetHasInlineCaches(false);
  669. }
  670. else if (this->m_inlineCaches != this->GetFunctionBody()->GetInlineCaches())
  671. {
  672. // Function body got reparsed we need to reset cache
  673. Assert(this->GetFunctionBody()->GetCompileCount() > 1);
  674. this->SetInlineCachesFromFunctionBody();
  675. }
  676. }
  677. return this->m_inlineCaches;
  678. }
  679. void ScriptFunctionWithInlineCache::SetInlineCachesFromFunctionBody()
  680. {
  681. SetHasInlineCaches(true);
  682. Js::FunctionBody* functionBody = this->GetFunctionBody();
  683. this->m_inlineCaches = functionBody->GetInlineCaches();
  684. #if DBG
  685. this->m_inlineCacheTypes = functionBody->GetInlineCacheTypes();
  686. #endif
  687. this->rootObjectLoadInlineCacheStart = functionBody->GetRootObjectLoadInlineCacheStart();
  688. this->rootObjectLoadMethodInlineCacheStart = functionBody->GetRootObjectLoadMethodInlineCacheStart();
  689. this->rootObjectStoreInlineCacheStart = functionBody->GetRootObjectStoreInlineCacheStart();
  690. this->inlineCacheCount = functionBody->GetInlineCacheCount();
  691. this->isInstInlineCacheCount = functionBody->GetIsInstInlineCacheCount();
  692. }
  693. void ScriptFunctionWithInlineCache::CreateInlineCache()
  694. {
  695. Js::FunctionBody *functionBody = this->GetFunctionBody();
  696. this->rootObjectLoadInlineCacheStart = functionBody->GetRootObjectLoadInlineCacheStart();
  697. this->rootObjectStoreInlineCacheStart = functionBody->GetRootObjectStoreInlineCacheStart();
  698. this->inlineCacheCount = functionBody->GetInlineCacheCount();
  699. this->isInstInlineCacheCount = functionBody->GetIsInstInlineCacheCount();
  700. SetHasInlineCaches(true);
  701. AllocateInlineCache();
  702. hasOwnInlineCaches = true;
  703. }
  704. void ScriptFunctionWithInlineCache::Finalize(bool isShutdown)
  705. {
  706. if (isShutdown)
  707. {
  708. FreeOwnInlineCaches<true>();
  709. }
  710. else
  711. {
  712. FreeOwnInlineCaches<false>();
  713. }
  714. }
  715. template<bool isShutdown>
  716. void ScriptFunctionWithInlineCache::FreeOwnInlineCaches()
  717. {
  718. uint isInstInlineCacheStart = this->GetInlineCacheCount();
  719. uint totalCacheCount = isInstInlineCacheStart + isInstInlineCacheCount;
  720. if (this->GetHasInlineCaches() && this->m_inlineCaches && this->hasOwnInlineCaches)
  721. {
  722. Js::ScriptContext* scriptContext = this->GetParseableFunctionInfo()->GetScriptContext();
  723. uint i = 0;
  724. uint unregisteredInlineCacheCount = 0;
  725. uint plainInlineCacheEnd = rootObjectLoadInlineCacheStart;
  726. __analysis_assume(plainInlineCacheEnd < totalCacheCount);
  727. for (; i < plainInlineCacheEnd; i++)
  728. {
  729. if (this->m_inlineCaches[i])
  730. {
  731. InlineCache* inlineCache = (InlineCache*)(void*)this->m_inlineCaches[i];
  732. if (isShutdown)
  733. {
  734. inlineCache->Clear();
  735. }
  736. else if(!scriptContext->IsClosed())
  737. {
  738. if (inlineCache->RemoveFromInvalidationList())
  739. {
  740. unregisteredInlineCacheCount++;
  741. }
  742. AllocatorDelete(InlineCacheAllocator, scriptContext->GetInlineCacheAllocator(), inlineCache);
  743. }
  744. this->m_inlineCaches[i] = nullptr;
  745. }
  746. }
  747. i = isInstInlineCacheStart;
  748. for (; i < totalCacheCount; i++)
  749. {
  750. if (this->m_inlineCaches[i])
  751. {
  752. if (isShutdown)
  753. {
  754. ((IsInstInlineCache*)this->m_inlineCaches[i])->Clear();
  755. }
  756. else if (!scriptContext->IsClosed())
  757. {
  758. AllocatorDelete(CacheAllocator, scriptContext->GetIsInstInlineCacheAllocator(), (IsInstInlineCache*)(void*)this->m_inlineCaches[i]);
  759. }
  760. this->m_inlineCaches[i] = nullptr;
  761. }
  762. }
  763. if (unregisteredInlineCacheCount > 0)
  764. {
  765. AssertMsg(!isShutdown && !scriptContext->IsClosed(), "Unregistration of inlineCache should only be done if this is not shutdown or scriptContext closing.");
  766. scriptContext->GetThreadContext()->NotifyInlineCacheBatchUnregistered(unregisteredInlineCacheCount);
  767. }
  768. }
  769. }
  770. void ScriptFunctionWithInlineCache::AllocateInlineCache()
  771. {
  772. Assert(this->m_inlineCaches == nullptr);
  773. uint isInstInlineCacheStart = this->GetInlineCacheCount();
  774. uint totalCacheCount = isInstInlineCacheStart + isInstInlineCacheCount;
  775. Js::FunctionBody* functionBody = this->GetFunctionBody();
  776. if (totalCacheCount != 0)
  777. {
  778. // Root object inline cache are not leaf
  779. Js::ScriptContext* scriptContext = this->GetFunctionBody()->GetScriptContext();
  780. void ** inlineCaches = RecyclerNewArrayZ(scriptContext->GetRecycler() ,
  781. void*, totalCacheCount);
  782. #if DBG
  783. this->m_inlineCacheTypes = RecyclerNewArrayLeafZ(scriptContext->GetRecycler(),
  784. byte, totalCacheCount);
  785. #endif
  786. uint i = 0;
  787. uint plainInlineCacheEnd = rootObjectLoadInlineCacheStart;
  788. __analysis_assume(plainInlineCacheEnd <= totalCacheCount);
  789. for (; i < plainInlineCacheEnd; i++)
  790. {
  791. inlineCaches[i] = AllocatorNewZ(InlineCacheAllocator,
  792. scriptContext->GetInlineCacheAllocator(), InlineCache);
  793. }
  794. Js::RootObjectBase * rootObject = functionBody->GetRootObject();
  795. ThreadContext * threadContext = scriptContext->GetThreadContext();
  796. uint rootObjectLoadInlineCacheEnd = rootObjectLoadMethodInlineCacheStart;
  797. __analysis_assume(rootObjectLoadInlineCacheEnd <= totalCacheCount);
  798. for (; i < rootObjectLoadInlineCacheEnd; i++)
  799. {
  800. inlineCaches[i] = rootObject->GetInlineCache(
  801. threadContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(i)), false, false);
  802. }
  803. uint rootObjectLoadMethodInlineCacheEnd = rootObjectStoreInlineCacheStart;
  804. __analysis_assume(rootObjectLoadMethodInlineCacheEnd <= totalCacheCount);
  805. for (; i < rootObjectLoadMethodInlineCacheEnd; i++)
  806. {
  807. inlineCaches[i] = rootObject->GetInlineCache(
  808. threadContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(i)), true, false);
  809. }
  810. uint rootObjectStoreInlineCacheEnd = isInstInlineCacheStart;
  811. __analysis_assume(rootObjectStoreInlineCacheEnd <= totalCacheCount);
  812. for (; i < rootObjectStoreInlineCacheEnd; i++)
  813. {
  814. #pragma prefast(suppress:6386, "The analysis assume didn't help prefast figure out this is in range")
  815. inlineCaches[i] = rootObject->GetInlineCache(
  816. threadContext->GetPropertyName(functionBody->GetPropertyIdFromCacheId(i)), false, true);
  817. }
  818. for (; i < totalCacheCount; i++)
  819. {
  820. inlineCaches[i] = AllocatorNewStructZ(CacheAllocator,
  821. functionBody->GetScriptContext()->GetIsInstInlineCacheAllocator(), IsInstInlineCache);
  822. }
  823. #if DBG
  824. this->m_inlineCacheTypes = RecyclerNewArrayLeafZ(functionBody->GetScriptContext()->GetRecycler(),
  825. byte, totalCacheCount);
  826. #endif
  827. this->m_inlineCaches = inlineCaches;
  828. }
  829. }
  830. bool ScriptFunction::GetSymbolName(const char16** symbolName, charcount_t* length) const
  831. {
  832. if (nullptr != this->computedNameVar && JavascriptSymbol::Is(this->computedNameVar))
  833. {
  834. const PropertyRecord* symbolRecord = JavascriptSymbol::FromVar(this->computedNameVar)->GetValue();
  835. *symbolName = symbolRecord->GetBuffer();
  836. *length = symbolRecord->GetLength();
  837. return true;
  838. }
  839. *symbolName = nullptr;
  840. *length = 0;
  841. return false;
  842. }
  843. JavascriptString* ScriptFunction::GetDisplayNameImpl() const
  844. {
  845. Assert(this->GetFunctionProxy() != nullptr); // The caller should guarantee a proxy exists
  846. ParseableFunctionInfo * func = this->GetFunctionProxy()->EnsureDeserialized();
  847. const char16* name = nullptr;
  848. charcount_t length = 0;
  849. JavascriptString* returnStr = nullptr;
  850. ENTER_PINNED_SCOPE(JavascriptString, computedName);
  851. if (computedNameVar != nullptr)
  852. {
  853. const char16* symbolName = nullptr;
  854. charcount_t symbolNameLength = 0;
  855. if (this->GetSymbolName(&symbolName, &symbolNameLength))
  856. {
  857. if (symbolNameLength == 0)
  858. {
  859. name = symbolName;
  860. }
  861. else
  862. {
  863. name = FunctionProxy::WrapWithBrackets(symbolName, symbolNameLength, this->GetScriptContext());
  864. length = symbolNameLength + 2; //adding 2 to length for brackets
  865. }
  866. }
  867. else
  868. {
  869. computedName = this->GetComputedName();
  870. if (!func->GetIsAccessor())
  871. {
  872. return computedName;
  873. }
  874. name = computedName->GetString();
  875. length = computedName->GetLength();
  876. }
  877. }
  878. else
  879. {
  880. name = Constants::Empty;
  881. if (func->GetIsNamedFunctionExpression()) // GetIsNamedFunctionExpression -> ex. var a = function foo() {} where name is foo
  882. {
  883. name = func->GetShortDisplayName(&length);
  884. }
  885. else if (func->GetIsNameIdentifierRef()) // GetIsNameIdentifierRef -> confirms a name is not attached like o.x = function() {}
  886. {
  887. if (this->GetScriptContext()->GetConfig()->IsES6FunctionNameFullEnabled())
  888. {
  889. name = func->GetShortDisplayName(&length);
  890. }
  891. else if (func->GetIsDeclaration() || // GetIsDeclaration -> ex. function foo () {}
  892. func->GetIsAccessor() || // GetIsAccessor -> ex. var a = { get f() {}} new enough syntax that we do not have to disable by default
  893. func->IsLambda() || // IsLambda -> ex. var y = { o : () => {}}
  894. GetHomeObj()) // GetHomeObj -> ex. var o = class {}, confirms this is a constructor or method on a class
  895. {
  896. name = func->GetShortDisplayName(&length);
  897. }
  898. }
  899. }
  900. AssertMsg(IsValidCharCount(length), "JavascriptString can't be larger than charcount_t");
  901. returnStr = DisplayNameHelper(name, static_cast<charcount_t>(length));
  902. LEAVE_PINNED_SCOPE();
  903. return returnStr;
  904. }
  905. bool ScriptFunction::IsAnonymousFunction() const
  906. {
  907. return this->GetFunctionProxy()->GetIsAnonymousFunction();
  908. }
  909. JavascriptString* ScriptFunction::GetComputedName() const
  910. {
  911. JavascriptString* computedName = nullptr;
  912. ScriptContext* scriptContext = this->GetScriptContext();
  913. if (computedNameVar != nullptr)
  914. {
  915. if (TaggedInt::Is(computedNameVar))
  916. {
  917. computedName = TaggedInt::ToString(computedNameVar, scriptContext);
  918. }
  919. else
  920. {
  921. computedName = JavascriptConversion::ToString(computedNameVar, scriptContext);
  922. }
  923. return computedName;
  924. }
  925. return nullptr;
  926. }
  927. void ScriptFunctionWithInlineCache::ClearInlineCacheOnFunctionObject()
  928. {
  929. if (NULL != this->m_inlineCaches)
  930. {
  931. FreeOwnInlineCaches<false>();
  932. this->m_inlineCaches = nullptr;
  933. this->inlineCacheCount = 0;
  934. this->rootObjectLoadInlineCacheStart = 0;
  935. this->rootObjectLoadMethodInlineCacheStart = 0;
  936. this->rootObjectStoreInlineCacheStart = 0;
  937. this->isInstInlineCacheCount = 0;
  938. }
  939. SetHasInlineCaches(false);
  940. }
  941. void ScriptFunctionWithInlineCache::ClearBorrowedInlineCacheOnFunctionObject()
  942. {
  943. if (this->hasOwnInlineCaches)
  944. {
  945. return;
  946. }
  947. ClearInlineCacheOnFunctionObject();
  948. }
  949. }