ScriptFunction.cpp 44 KB

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