ScriptFunction.cpp 42 KB

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