JavascriptFunction.cpp 136 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542
  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. #include "Library/StackScriptFunction.h"
  7. #include "Types/SpreadArgument.h"
  8. #include "Language/AsmJsTypes.h"
  9. #ifdef _M_X64
  10. #include "ByteCode/PropertyIdArray.h"
  11. #include "Language/AsmJsModule.h"
  12. #endif
  13. #ifdef _M_IX86
  14. #ifdef _CONTROL_FLOW_GUARD
  15. extern "C" PVOID __guard_check_icall_fptr;
  16. #endif
  17. extern "C" void __cdecl _alloca_probe_16();
  18. #endif
  19. using namespace Js;
  20. // The VS2013 linker treats this as a redefinition of an already
  21. // defined constant and complains. So skip the declaration if we're compiling
  22. // with VS2013 or below.
  23. #if !defined(_MSC_VER) || _MSC_VER >= 1900
  24. const charcount_t JavascriptFunction::DIAG_MAX_FUNCTION_STRING;
  25. #endif
  26. DEFINE_RECYCLER_TRACKER_PERF_COUNTER(JavascriptFunction);
  27. JavascriptFunction::JavascriptFunction(DynamicType * type)
  28. : DynamicObject(type), functionInfo(nullptr), constructorCache(&ConstructorCache::DefaultInstance)
  29. {
  30. Assert(this->constructorCache != nullptr);
  31. }
  32. JavascriptFunction::JavascriptFunction(DynamicType * type, FunctionInfo * functionInfo)
  33. : DynamicObject(type), functionInfo(functionInfo), constructorCache(&ConstructorCache::DefaultInstance)
  34. {
  35. Assert(this->constructorCache != nullptr);
  36. this->GetTypeHandler()->ClearHasOnlyWritableDataProperties(); // length is non-writable
  37. if (GetTypeHandler()->GetFlags() & DynamicTypeHandler::IsPrototypeFlag)
  38. {
  39. // No need to invalidate store field caches for non-writable properties here. Since this type is just being created, it cannot represent
  40. // an object that is already a prototype. If it becomes a prototype and then we attempt to add a property to an object derived from this
  41. // object, then we will check if this property is writable, and only if it is will we do the fast path for add property.
  42. // GetScriptContext()->InvalidateStoreFieldCaches(PropertyIds::length);
  43. GetLibrary()->GetTypesWithOnlyWritablePropertyProtoChainCache()->Clear();
  44. }
  45. }
  46. JavascriptFunction::JavascriptFunction(DynamicType * type, FunctionInfo * functionInfo, ConstructorCache* cache)
  47. : DynamicObject(type), functionInfo(functionInfo), constructorCache(cache)
  48. {
  49. Assert(this->constructorCache != nullptr);
  50. this->GetTypeHandler()->ClearHasOnlyWritableDataProperties(); // length is non-writable
  51. if (GetTypeHandler()->GetFlags() & DynamicTypeHandler::IsPrototypeFlag)
  52. {
  53. // No need to invalidate store field caches for non-writable properties here. Since this type is just being created, it cannot represent
  54. // an object that is already a prototype. If it becomes a prototype and then we attempt to add a property to an object derived from this
  55. // object, then we will check if this property is writable, and only if it is will we do the fast path for add property.
  56. // GetScriptContext()->InvalidateStoreFieldCaches(PropertyIds::length);
  57. GetLibrary()->GetTypesWithOnlyWritablePropertyProtoChainCache()->Clear();
  58. }
  59. }
  60. FunctionProxy *JavascriptFunction::GetFunctionProxy() const
  61. {
  62. Assert(functionInfo != nullptr);
  63. return functionInfo->GetFunctionProxy();
  64. }
  65. ParseableFunctionInfo *JavascriptFunction::GetParseableFunctionInfo() const
  66. {
  67. Assert(functionInfo != nullptr);
  68. return functionInfo->GetParseableFunctionInfo();
  69. }
  70. DeferDeserializeFunctionInfo *JavascriptFunction::GetDeferDeserializeFunctionInfo() const
  71. {
  72. Assert(functionInfo != nullptr);
  73. return functionInfo->GetDeferDeserializeFunctionInfo();
  74. }
  75. FunctionBody *JavascriptFunction::GetFunctionBody() const
  76. {
  77. Assert(functionInfo != nullptr);
  78. return functionInfo->GetFunctionBody();
  79. }
  80. BOOL JavascriptFunction::IsScriptFunction() const
  81. {
  82. Assert(functionInfo != nullptr);
  83. return functionInfo->HasBody();
  84. }
  85. bool JavascriptFunction::Is(Var aValue)
  86. {
  87. if (JavascriptOperators::GetTypeId(aValue) == TypeIds_Function)
  88. {
  89. return true;
  90. }
  91. return false;
  92. }
  93. JavascriptFunction* JavascriptFunction::FromVar(Var aValue)
  94. {
  95. AssertOrFailFastMsg(Is(aValue), "Ensure var is actually a 'JavascriptFunction'");
  96. return static_cast<JavascriptFunction *>(aValue);
  97. }
  98. JavascriptFunction* JavascriptFunction::UnsafeFromVar(Var aValue)
  99. {
  100. AssertMsg(Is(aValue), "Ensure var is actually a 'JavascriptFunction'");
  101. return static_cast<JavascriptFunction *>(aValue);
  102. }
  103. BOOL JavascriptFunction::IsStrictMode() const
  104. {
  105. FunctionProxy * proxy = this->GetFunctionProxy();
  106. return proxy && proxy->EnsureDeserialized()->GetIsStrictMode();
  107. }
  108. BOOL JavascriptFunction::IsLambda() const
  109. {
  110. return this->GetFunctionInfo()->IsLambda();
  111. }
  112. BOOL JavascriptFunction::IsConstructor() const
  113. {
  114. return this->GetFunctionInfo()->IsConstructor();
  115. }
  116. #if DBG
  117. /* static */
  118. bool JavascriptFunction::IsBuiltinProperty(Var objectWithProperty, PropertyIds propertyId)
  119. {
  120. return ScriptFunctionBase::Is(objectWithProperty)
  121. && (propertyId == PropertyIds::length || (JavascriptFunction::FromVar(objectWithProperty)->HasRestrictedProperties() && (propertyId == PropertyIds::arguments || propertyId == PropertyIds::caller)));
  122. }
  123. #endif
  124. static char16 const funcName[] = _u("function anonymous");
  125. static char16 const genFuncName[] = _u("function* anonymous");
  126. static char16 const asyncFuncName[] = _u("async function anonymous");
  127. static char16 const openFormals[] = _u("(");
  128. static char16 const closeFormals[] = _u("\n)");
  129. static char16 const openFuncBody[] = _u(" {");
  130. static char16 const closeFuncBody[] = _u("\n}");
  131. Var JavascriptFunction::NewInstanceHelper(ScriptContext *scriptContext, RecyclableObject* function, CallInfo callInfo, Js::ArgumentReader& args, FunctionKind functionKind /* = FunctionKind::Normal */)
  132. {
  133. JavascriptLibrary* library = function->GetLibrary();
  134. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  135. // SkipDefaultNewObject function flag should have prevented the default object from
  136. // being created, except when call true a host dispatch.
  137. Var newTarget = args.GetNewTarget();
  138. bool isCtorSuperCall = JavascriptOperators::GetAndAssertIsConstructorSuperCall(args);
  139. JavascriptString* separator = library->GetCommaDisplayString();
  140. // Gather all the formals into a string like (fml1, fml2, fml3)
  141. JavascriptString *formals = library->GetOpenRBracketString();
  142. for (uint i = 1; i < args.Info.Count - 1; ++i)
  143. {
  144. if (i != 1)
  145. {
  146. formals = JavascriptString::Concat(formals, separator);
  147. }
  148. formals = JavascriptString::Concat(formals, JavascriptConversion::ToString(args.Values[i], scriptContext));
  149. }
  150. formals = JavascriptString::Concat(formals, library->GetNewLineCloseRBracketString());
  151. // Function body, last argument to Function(...)
  152. JavascriptString *fnBody = NULL;
  153. if (args.Info.Count > 1)
  154. {
  155. fnBody = JavascriptConversion::ToString(args.Values[args.Info.Count - 1], scriptContext);
  156. }
  157. // Create a string representing the anonymous function
  158. Assert(
  159. 0 + // "function anonymous" GetFunctionAnonymousString
  160. 0 + // "(" GetOpenRBracketString
  161. 1 + // "\n)" GetNewLineCloseRBracketString
  162. 0 // " {" GetSpaceOpenBracketString
  163. == numberLinesPrependedToAnonymousFunction); // Be sure to add exactly one line to anonymous function
  164. JavascriptString *bs = functionKind == FunctionKind::Async ?
  165. library->GetAsyncFunctionAnonymouseString() :
  166. functionKind == FunctionKind::Generator ?
  167. library->GetFunctionPTRAnonymousString() :
  168. library->GetFunctionAnonymousString();
  169. bs = JavascriptString::Concat(bs, formals);
  170. bs = JavascriptString::Concat(bs, library->GetSpaceOpenBracketString());
  171. if (fnBody != NULL)
  172. {
  173. bs = JavascriptString::Concat(bs, fnBody);
  174. }
  175. bs = JavascriptString::Concat(bs, library->GetNewLineCloseBracketString());
  176. // Bug 1105479. Get the module id from the caller
  177. ModuleID moduleID = kmodGlobal;
  178. BOOL strictMode = FALSE;
  179. JavascriptFunction* pfuncScript;
  180. FunctionInfo *pfuncInfoCache = NULL;
  181. char16 const * sourceString = bs->GetSz();
  182. charcount_t sourceLen = bs->GetLength();
  183. EvalMapString key(sourceString, sourceLen, moduleID, strictMode, /* isLibraryCode = */ false);
  184. if (!scriptContext->IsInNewFunctionMap(key, &pfuncInfoCache))
  185. {
  186. // Validate formals here
  187. scriptContext->GetGlobalObject()->ValidateSyntax(
  188. scriptContext, formals->GetSz(), formals->GetLength(),
  189. functionKind == FunctionKind::Generator, functionKind == FunctionKind::Async,
  190. &Parser::ValidateFormals);
  191. if (fnBody != NULL)
  192. {
  193. // Validate function body
  194. scriptContext->GetGlobalObject()->ValidateSyntax(
  195. scriptContext, fnBody->GetSz(), fnBody->GetLength(),
  196. functionKind == FunctionKind::Generator, functionKind == FunctionKind::Async,
  197. &Parser::ValidateSourceElementList);
  198. }
  199. pfuncScript = scriptContext->GetGlobalObject()->EvalHelper(scriptContext, sourceString, sourceLen, moduleID, fscrCanDeferFncParse, Constants::FunctionCode, TRUE, TRUE, strictMode);
  200. // Indicate that this is a top-level function. We don't pass the fscrGlobalCode flag to the eval helper,
  201. // or it will return the global function that wraps the declared function body, as though it were an eval.
  202. // But we want, for instance, to be able to verify that we did the right amount of deferred parsing.
  203. ParseableFunctionInfo *functionInfo = pfuncScript->GetParseableFunctionInfo();
  204. Assert(functionInfo);
  205. functionInfo->SetGrfscr(functionInfo->GetGrfscr() | fscrGlobalCode);
  206. #if ENABLE_TTD
  207. if(!scriptContext->IsTTDRecordOrReplayModeEnabled())
  208. {
  209. scriptContext->AddToNewFunctionMap(key, functionInfo->GetFunctionInfo());
  210. }
  211. #else
  212. scriptContext->AddToNewFunctionMap(key, functionInfo->GetFunctionInfo());
  213. #endif
  214. }
  215. else if (pfuncInfoCache->IsCoroutine())
  216. {
  217. pfuncScript = scriptContext->GetLibrary()->CreateGeneratorVirtualScriptFunction(pfuncInfoCache->GetFunctionProxy());
  218. }
  219. else
  220. {
  221. pfuncScript = scriptContext->GetLibrary()->CreateScriptFunction(pfuncInfoCache->GetFunctionProxy());
  222. }
  223. #if ENABLE_TTD
  224. //
  225. //TODO: We may (probably?) want to use the debugger source rundown functionality here instead
  226. //
  227. if(pfuncScript != nullptr && (scriptContext->IsTTDRecordModeEnabled() || scriptContext->ShouldPerformReplayAction()))
  228. {
  229. //Make sure we have the body and text information available
  230. FunctionBody* globalBody = TTD::JsSupport::ForceAndGetFunctionBody(pfuncScript->GetParseableFunctionInfo());
  231. if(!scriptContext->TTDContextInfo->IsBodyAlreadyLoadedAtTopLevel(globalBody))
  232. {
  233. uint32 bodyIdCtr = 0;
  234. if(scriptContext->IsTTDRecordModeEnabled())
  235. {
  236. const TTD::NSSnapValues::TopLevelNewFunctionBodyResolveInfo* tbfi = scriptContext->GetThreadContext()->TTDLog->AddNewFunction(globalBody, moduleID, sourceString, sourceLen);
  237. //We always want to register the top-level load but we don't always need to log the event
  238. if(scriptContext->ShouldPerformRecordAction())
  239. {
  240. scriptContext->GetThreadContext()->TTDLog->RecordTopLevelCodeAction(tbfi->TopLevelBase.TopLevelBodyCtr);
  241. }
  242. bodyIdCtr = tbfi->TopLevelBase.TopLevelBodyCtr;
  243. }
  244. if(scriptContext->ShouldPerformReplayAction())
  245. {
  246. bodyIdCtr = scriptContext->GetThreadContext()->TTDLog->ReplayTopLevelCodeAction();
  247. }
  248. //walk global body to (1) add functions to pin set (2) build parent map
  249. scriptContext->TTDContextInfo->ProcessFunctionBodyOnLoad(globalBody, nullptr);
  250. scriptContext->TTDContextInfo->RegisterNewScript(globalBody, bodyIdCtr);
  251. if(scriptContext->ShouldPerformRecordOrReplayAction())
  252. {
  253. globalBody->GetUtf8SourceInfo()->SetSourceInfoForDebugReplay_TTD(bodyIdCtr);
  254. }
  255. if(scriptContext->ShouldPerformReplayDebuggerAction())
  256. {
  257. scriptContext->GetThreadContext()->TTDExecutionInfo->ProcessScriptLoad(scriptContext, bodyIdCtr, globalBody, globalBody->GetUtf8SourceInfo(), nullptr);
  258. }
  259. }
  260. }
  261. #endif
  262. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(pfuncScript, EtwTrace::GetFunctionId(pfuncScript->GetFunctionProxy())));
  263. if (functionKind == FunctionKind::Generator || functionKind == FunctionKind::Async)
  264. {
  265. Assert(pfuncScript->GetFunctionInfo()->IsCoroutine());
  266. auto pfuncVirt = static_cast<GeneratorVirtualScriptFunction*>(pfuncScript);
  267. auto pfuncGen = functionKind == FunctionKind::Async ?
  268. scriptContext->GetLibrary()->CreateAsyncFunction(JavascriptAsyncFunction::EntryAsyncFunctionImplementation, pfuncVirt) :
  269. scriptContext->GetLibrary()->CreateGeneratorFunction(JavascriptGeneratorFunction::EntryGeneratorFunctionImplementation, pfuncVirt);
  270. pfuncVirt->SetRealGeneratorFunction(pfuncGen);
  271. pfuncScript = pfuncGen;
  272. }
  273. return isCtorSuperCall ?
  274. JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), pfuncScript, nullptr, scriptContext) :
  275. pfuncScript;
  276. }
  277. Var JavascriptFunction::NewInstanceRestrictedMode(RecyclableObject* function, CallInfo callInfo, ...)
  278. {
  279. ScriptContext* scriptContext = function->GetScriptContext();
  280. scriptContext->CheckEvalRestriction();
  281. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  282. ARGUMENTS(args, callInfo);
  283. return NewInstanceHelper(scriptContext, function, callInfo, args);
  284. }
  285. Var JavascriptFunction::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
  286. {
  287. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  288. ARGUMENTS(args, callInfo);
  289. ScriptContext* scriptContext = function->GetScriptContext();
  290. return NewInstanceHelper(scriptContext, function, callInfo, args);
  291. }
  292. Var JavascriptFunction::NewAsyncFunctionInstance(RecyclableObject* function, CallInfo callInfo, ...)
  293. {
  294. // Get called when creating a new async function through the constructor (e.g. af.__proto__.constructor)
  295. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  296. ARGUMENTS(args, callInfo);
  297. return JavascriptFunction::NewInstanceHelper(function->GetScriptContext(), function, callInfo, args, JavascriptFunction::FunctionKind::Async);
  298. }
  299. Var JavascriptFunction::NewAsyncFunctionInstanceRestrictedMode(RecyclableObject* function, CallInfo callInfo, ...)
  300. {
  301. ScriptContext* scriptContext = function->GetScriptContext();
  302. scriptContext->CheckEvalRestriction();
  303. PROBE_STACK(scriptContext, Js::Constants::MinStackDefault);
  304. ARGUMENTS(args, callInfo);
  305. return JavascriptFunction::NewInstanceHelper(scriptContext, function, callInfo, args, JavascriptFunction::FunctionKind::Async);
  306. }
  307. //
  308. // Dummy EntryPoint for Function.prototype
  309. //
  310. Var JavascriptFunction::PrototypeEntryPoint(RecyclableObject* function, CallInfo callInfo, ...)
  311. {
  312. ARGUMENTS(args, callInfo);
  313. ScriptContext* scriptContext = function->GetScriptContext();
  314. JavascriptLibrary* library = function->GetLibrary();
  315. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  316. if (callInfo.Flags & CallFlags_New)
  317. {
  318. JavascriptError::ThrowTypeError(scriptContext, VBSERR_ActionNotSupported);
  319. }
  320. return library->GetUndefined();
  321. }
  322. enum : unsigned { STACK_ARGS_ALLOCA_THRESHOLD = 8 }; // Number of stack args we allow before using _alloca
  323. // ES5 15.3.4.3
  324. //When the apply method is called on an object func with arguments thisArg and argArray the following steps are taken:
  325. // 1. If IsCallable(func) is false, then throw a TypeError exception.
  326. // 2. If argArray is null or undefined, then
  327. // a. Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and an empty list of arguments.
  328. // 3. If Type(argArray) is not Object, then throw a TypeError exception.
  329. // 4. Let len be the result of calling the [[Get]] internal method of argArray with argument "length".
  330. //
  331. // Steps 5 and 7 deleted from July 19 Errata of ES5 spec
  332. //
  333. // 5. If len is null or undefined, then throw a TypeError exception.
  334. // 6. Len n be ToUint32(len).
  335. // 7. If n is not equal to ToNumber(len), then throw a TypeError exception.
  336. // 8. Let argList be an empty List.
  337. // 9. Let index be 0.
  338. // 10. Repeat while index < n
  339. // a. Let indexName be ToString(index).
  340. // b. Let nextArg be the result of calling the [[Get]] internal method of argArray with indexName as the argument.
  341. // c. Append nextArg as the last element of argList.
  342. // d. Set index to index + 1.
  343. // 11. Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.
  344. // The length property of the apply method is 2.
  345. Var JavascriptFunction::EntryApply(RecyclableObject* function, CallInfo callInfo, ...)
  346. {
  347. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  348. // Ideally, we want to maintain CallFlags_Eval behavior and pass along the extra FrameDisplay parameter
  349. // but that we would be a bigger change than what we want to do in this ship cycle. See WIN8: 915315.
  350. // If eval is executed using apply it will not get the frame display and always execute in global scope.
  351. ARGUMENTS(args, callInfo);
  352. ScriptContext* scriptContext = function->GetScriptContext();
  353. Assert(!(callInfo.Flags & CallFlags_New));
  354. ///
  355. /// Check Argument[0] has internal [[Call]] property
  356. /// If not, throw TypeError
  357. ///
  358. if (args.Info.Count == 0 || !JavascriptConversion::IsCallable(args[0]))
  359. {
  360. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedFunction, _u("Function.prototype.apply"));
  361. }
  362. Var thisVar = NULL;
  363. Var argArray = NULL;
  364. RecyclableObject* pFunc = RecyclableObject::FromVar(args[0]);
  365. if (args.Info.Count == 1)
  366. {
  367. thisVar = scriptContext->GetLibrary()->GetUndefined();
  368. }
  369. else if (args.Info.Count == 2)
  370. {
  371. thisVar = args.Values[1];
  372. }
  373. else if (args.Info.Count > 2)
  374. {
  375. thisVar = args.Values[1];
  376. argArray = args.Values[2];
  377. }
  378. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  379. {
  380. return CalloutHelper<false>(pFunc, thisVar, /* overridingNewTarget = */nullptr, argArray, scriptContext);
  381. }
  382. END_SAFE_REENTRANT_CALL
  383. }
  384. template <bool isConstruct>
  385. Var JavascriptFunction::CalloutHelper(RecyclableObject* pFunc, Var thisVar, Var overridingNewTarget, Var argArray, ScriptContext* scriptContext)
  386. {
  387. CallFlags callFlag;
  388. if (isConstruct)
  389. {
  390. callFlag = CallFlags_New;
  391. }
  392. else
  393. {
  394. callFlag = CallFlags_Value;
  395. }
  396. Arguments outArgs(CallInfo(callFlag, 0), nullptr);
  397. Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
  398. if (nullptr == argArray)
  399. {
  400. outArgs.Info.Count = 1;
  401. outArgs.Values = &thisVar;
  402. }
  403. else
  404. {
  405. bool isArray = JavascriptArray::Is(argArray);
  406. TypeId typeId = JavascriptOperators::GetTypeId(argArray);
  407. bool isNullOrUndefined = typeId <= TypeIds_UndefinedOrNull;
  408. if (!isNullOrUndefined && !JavascriptOperators::IsObject(argArray)) // ES5: throw if Type(argArray) is not Object
  409. {
  410. JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedObject, _u("Function.prototype.apply"));
  411. }
  412. int64 len;
  413. JavascriptArray* arr = NULL;
  414. RecyclableObject* dynamicObject = RecyclableObject::FromVar(argArray);
  415. if (isNullOrUndefined)
  416. {
  417. len = 0;
  418. }
  419. else if (isArray)
  420. {
  421. #if ENABLE_COPYONACCESS_ARRAY
  422. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(argArray);
  423. #endif
  424. arr = JavascriptArray::FromVar(argArray);
  425. len = arr->GetLength();
  426. }
  427. else
  428. {
  429. Var lenProp = JavascriptOperators::OP_GetLength(dynamicObject, scriptContext);
  430. len = JavascriptConversion::ToLength(lenProp, scriptContext);
  431. }
  432. if (len >= CallInfo::kMaxCountArgs)
  433. {
  434. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgListTooLarge);
  435. }
  436. outArgs.Info.Count = (uint)len + 1;
  437. if (len == 0)
  438. {
  439. outArgs.Values = &thisVar;
  440. }
  441. else
  442. {
  443. if (outArgs.Info.Count > STACK_ARGS_ALLOCA_THRESHOLD)
  444. {
  445. PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var)+Js::Constants::MinStackDefault); // args + function call
  446. outArgs.Values = (Var*)_alloca(outArgs.Info.Count * sizeof(Var));
  447. }
  448. else
  449. {
  450. outArgs.Values = stackArgs;
  451. }
  452. outArgs.Values[0] = thisVar;
  453. Var undefined = pFunc->GetLibrary()->GetUndefined();
  454. if (isArray && arr->GetScriptContext() == scriptContext)
  455. {
  456. arr->ForEachItemInRange<false>(0, (uint)len, undefined, scriptContext,
  457. [&outArgs](uint index, Var element)
  458. {
  459. outArgs.Values[index + 1] = element;
  460. });
  461. }
  462. else
  463. {
  464. for (uint i = 0; i < len; i++)
  465. {
  466. Var element = nullptr;
  467. if (!JavascriptOperators::GetItem(dynamicObject, i, &element, scriptContext))
  468. {
  469. element = undefined;
  470. }
  471. outArgs.Values[i + 1] = element;
  472. }
  473. }
  474. }
  475. }
  476. if (isConstruct)
  477. {
  478. return JavascriptFunction::CallAsConstructor(pFunc, overridingNewTarget, outArgs, scriptContext);
  479. }
  480. else
  481. {
  482. // Apply scenarios can have more than Constants::MaxAllowedArgs number of args. Need to use the large argCount logic here.
  483. return JavascriptFunction::CallFunction<true>(pFunc, pFunc->GetEntryPoint(), outArgs, /* useLargeArgCount */true);
  484. }
  485. }
  486. Var JavascriptFunction::ApplyHelper(RecyclableObject* function, Var thisArg, Var argArray, ScriptContext* scriptContext)
  487. {
  488. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  489. {
  490. return CalloutHelper<false>(function, thisArg, /* overridingNewTarget = */nullptr, argArray, scriptContext);
  491. }
  492. END_SAFE_REENTRANT_CALL
  493. }
  494. Var JavascriptFunction::ConstructHelper(RecyclableObject* function, Var thisArg, Var overridingNewTarget, Var argArray, ScriptContext* scriptContext)
  495. {
  496. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  497. {
  498. return CalloutHelper<true>(function, thisArg, overridingNewTarget, argArray, scriptContext);
  499. }
  500. END_SAFE_REENTRANT_CALL
  501. }
  502. Var JavascriptFunction::EntryBind(RecyclableObject* function, CallInfo callInfo, ...)
  503. {
  504. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  505. ARGUMENTS(args, callInfo);
  506. ScriptContext* scriptContext = function->GetScriptContext();
  507. CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(Function_Prototype_bind);
  508. Assert(!(callInfo.Flags & CallFlags_New));
  509. ///
  510. /// Check Argument[0] has internal [[Call]] property
  511. /// If not, throw TypeError
  512. ///
  513. if (args.Info.Count == 0 || !JavascriptConversion::IsCallable(args[0]))
  514. {
  515. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedFunction, _u("Function.prototype.bind"));
  516. }
  517. BoundFunction* boundFunc = BoundFunction::New(scriptContext, args);
  518. return boundFunc;
  519. }
  520. // ES5 15.3.4.4
  521. // Function.prototype.call (thisArg [ , arg1 [ , arg2, ... ] ] )
  522. // When the call method is called on an object func with argument thisArg and optional arguments arg1, arg2 etc, the following steps are taken:
  523. // 1. If IsCallable(func) is false, then throw a TypeError exception.
  524. // 2. Let argList be an empty List.
  525. // 3. If this method was called with more than one argument then in left to right order starting with arg1 append each argument as the last element of argList
  526. // 4. Return the result of calling the [[Call]] internal method of func, providing thisArg as the this value and argList as the list of arguments.
  527. // The length property of the call method is 1.
  528. Var JavascriptFunction::EntryCall(RecyclableObject* function, CallInfo callInfo, ...)
  529. {
  530. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  531. RUNTIME_ARGUMENTS(args, callInfo);
  532. ScriptContext* scriptContext = function->GetScriptContext();
  533. Assert(!(callInfo.Flags & CallFlags_New));
  534. ///
  535. /// Check Argument[0] has internal [[Call]] property
  536. /// If not, throw TypeError
  537. ///
  538. uint argCount = args.Info.Count;
  539. if (argCount == 0 || !JavascriptConversion::IsCallable(args[0]))
  540. {
  541. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedFunction, _u("Function.prototype.call"));
  542. }
  543. RecyclableObject *pFunc = RecyclableObject::FromVar(args[0]);
  544. if (argCount == 1)
  545. {
  546. args.Values[0] = scriptContext->GetLibrary()->GetUndefined();
  547. }
  548. else
  549. {
  550. ///
  551. /// Remove function object from the arguments and pass the rest
  552. ///
  553. for (uint i = 0; i < args.Info.Count - 1; ++i)
  554. {
  555. args.Values[i] = args.Values[i + 1];
  556. }
  557. args.Info.Count = args.Info.Count - 1;
  558. }
  559. ///
  560. /// Call the [[Call]] method on the function object
  561. ///
  562. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  563. {
  564. return JavascriptFunction::CallFunction<true>(pFunc, pFunc->GetEntryPoint(), args, true /*useLargeArgCount*/);
  565. }
  566. END_SAFE_REENTRANT_CALL
  567. }
  568. Var JavascriptFunction::CallRootFunctionInScript(JavascriptFunction* func, Arguments args)
  569. {
  570. ScriptContext* scriptContext = func->GetScriptContext();
  571. if (scriptContext->GetThreadContext()->HasPreviousHostScriptContext())
  572. {
  573. ScriptContext* requestContext = scriptContext->GetThreadContext()->
  574. GetPreviousHostScriptContext()->GetScriptContext();
  575. func = JavascriptFunction::FromVar(CrossSite::MarshalVar(requestContext,
  576. func, scriptContext));
  577. }
  578. return func->CallRootFunction(args, scriptContext, true);
  579. }
  580. Var JavascriptFunction::CallRootFunction(RecyclableObject* obj, Arguments args, ScriptContext * scriptContext, bool inScript)
  581. {
  582. Var ret = nullptr;
  583. #ifdef FAULT_INJECTION
  584. if (Js::Configuration::Global.flags.FaultInjection >= 0)
  585. {
  586. Js::FaultInjection::pfnHandleAV = JavascriptFunction::CallRootEventFilter;
  587. __try
  588. {
  589. ret = JavascriptFunction::CallRootFunctionInternal(obj, args, scriptContext, inScript);
  590. }
  591. __finally
  592. {
  593. Js::FaultInjection::pfnHandleAV = nullptr;
  594. }
  595. //ret should never be null here
  596. Assert(ret);
  597. return ret;
  598. }
  599. #endif
  600. #ifdef DISABLE_SEH
  601. // xplat: JavascriptArrayBuffer::AllocWrapper is disabled on cross-platform
  602. // (IsValidVirtualBufferLength always returns false).
  603. // SEH and ResumeForOutOfBoundsArrayRefs are not needed.
  604. ret = JavascriptFunction::CallRootFunctionInternal(obj, args, scriptContext, inScript);
  605. #else
  606. if (scriptContext->GetThreadContext()->GetAbnormalExceptionCode() != 0)
  607. {
  608. // ensure that hosts are not doing SEH across Chakra frames, as that can lead to bad state (e.g. destructors not being called)
  609. UnexpectedExceptionHandling_fatal_error();
  610. }
  611. // mark volatile, because otherwise VC will incorrectly optimize away load in the finally block
  612. volatile uint32 exceptionCode = 0;
  613. EXCEPTION_POINTERS exceptionInfo = { 0 };
  614. __try
  615. {
  616. __try
  617. {
  618. ret = JavascriptFunction::CallRootFunctionInternal(obj, args, scriptContext, inScript);
  619. }
  620. __except (
  621. exceptionInfo = *GetExceptionInformation(),
  622. exceptionCode = GetExceptionCode(),
  623. CallRootEventFilter(exceptionCode, GetExceptionInformation()))
  624. {
  625. Assert(UNREACHED);
  626. }
  627. }
  628. __finally
  629. {
  630. // 0xE06D7363 is C++ exception code
  631. if (exceptionCode != 0 && exceptionCode != 0xE06D7363 && AbnormalTermination() && !IsDebuggerPresent())
  632. {
  633. scriptContext->GetThreadContext()->SetAbnormalExceptionCode(exceptionCode);
  634. scriptContext->GetThreadContext()->SetAbnormalExceptionRecord(&exceptionInfo);
  635. }
  636. }
  637. #endif
  638. //ret should never be null here
  639. Assert(ret);
  640. return ret;
  641. }
  642. Var JavascriptFunction::CallRootFunctionInternal(RecyclableObject* obj, Arguments args, ScriptContext * scriptContext, bool inScript)
  643. {
  644. #if DBG
  645. if (IsInAssert != 0)
  646. {
  647. // Just don't execute anything if we are in an assert
  648. Js::Throw::FatalInternalError();
  649. }
  650. #endif
  651. if (inScript)
  652. {
  653. Assert(!(args.Info.Flags & CallFlags_New));
  654. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  655. {
  656. return JavascriptFunction::CallFunction<true>(obj, obj->GetEntryPoint(), args);
  657. }
  658. END_SAFE_REENTRANT_CALL
  659. }
  660. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  661. Js::Var varThis;
  662. if (PHASE_FORCE1(Js::EvalCompilePhase) && args.Info.Count == 0)
  663. {
  664. varThis = JavascriptOperators::OP_GetThis(scriptContext->GetLibrary()->GetUndefined(), kmodGlobal, scriptContext);
  665. args.Info.Flags = (Js::CallFlags)(args.Info.Flags | CallFlags_Eval);
  666. args.Info.Count = 1;
  667. args.Values = &varThis;
  668. }
  669. #endif
  670. Var varResult = nullptr;
  671. ThreadContext *threadContext;
  672. threadContext = scriptContext->GetThreadContext();
  673. JavascriptExceptionObject* pExceptionObject = NULL;
  674. bool hasCaller = scriptContext->GetHostScriptContext() ? !!scriptContext->GetHostScriptContext()->HasCaller() : false;
  675. Assert(scriptContext == obj->GetScriptContext());
  676. BEGIN_JS_RUNTIME_CALLROOT_EX(scriptContext, hasCaller)
  677. {
  678. scriptContext->VerifyAlive(true);
  679. try
  680. {
  681. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  682. {
  683. varResult = args.Info.Flags & CallFlags_New ?
  684. JavascriptFunction::CallAsConstructor(obj, /* overridingNewTarget = */nullptr, args, scriptContext) :
  685. JavascriptFunction::CallFunction<true>(obj, obj->GetEntryPoint(), args);
  686. }
  687. END_SAFE_REENTRANT_CALL
  688. // A recent compiler bug 150148 can incorrectly eliminate catch block, temporary workaround
  689. if (threadContext == NULL)
  690. {
  691. throw JavascriptException(nullptr);
  692. }
  693. }
  694. catch (const JavascriptException& err)
  695. {
  696. pExceptionObject = err.GetAndClear();
  697. }
  698. if (pExceptionObject)
  699. {
  700. JavascriptExceptionOperators::DoThrowCheckClone(pExceptionObject, scriptContext);
  701. }
  702. }
  703. END_JS_RUNTIME_CALL(scriptContext);
  704. Assert(varResult != nullptr);
  705. return varResult;
  706. }
  707. Var JavascriptFunction::CallRootFunction(Arguments args, ScriptContext * scriptContext, bool inScript)
  708. {
  709. return JavascriptFunction::CallRootFunction(this, args, scriptContext, inScript);
  710. }
  711. #if DBG
  712. /*static*/
  713. void JavascriptFunction::CheckValidDebugThunk(ScriptContext* scriptContext, RecyclableObject *function)
  714. {
  715. Assert(scriptContext != nullptr);
  716. Assert(function != nullptr);
  717. if (scriptContext->IsScriptContextInDebugMode()
  718. && !scriptContext->IsInterpreted() && !CONFIG_FLAG(ForceDiagnosticsMode) // Does not work nicely if we change the default settings.
  719. && function->GetEntryPoint() != scriptContext->CurrentThunk
  720. && !CrossSite::IsThunk(function->GetEntryPoint())
  721. && JavascriptFunction::Is(function))
  722. {
  723. JavascriptFunction *jsFunction = JavascriptFunction::FromVar(function);
  724. if (!jsFunction->IsBoundFunction()
  725. && !jsFunction->GetFunctionInfo()->IsDeferred()
  726. && (jsFunction->GetFunctionInfo()->GetAttributes() & FunctionInfo::DoNotProfile) != FunctionInfo::DoNotProfile
  727. && jsFunction->GetFunctionInfo() != &JavascriptExternalFunction::EntryInfo::WrappedFunctionThunk)
  728. {
  729. Js::FunctionProxy *proxy = jsFunction->GetFunctionProxy();
  730. if (proxy)
  731. {
  732. AssertMsg(proxy->HasValidEntryPoint(), "Function does not have valid entrypoint");
  733. }
  734. }
  735. }
  736. }
  737. #endif
  738. Var JavascriptFunction::CallAsConstructor(Var v, Var overridingNewTarget, Arguments args, ScriptContext* scriptContext, const Js::AuxArray<uint32> *spreadIndices)
  739. {
  740. Assert(v);
  741. Assert(args.Info.Flags & CallFlags_New);
  742. Assert(scriptContext);
  743. // newCount is ushort.
  744. if (args.Info.Count >= USHORT_MAX)
  745. {
  746. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgListTooLarge);
  747. }
  748. AnalysisAssert(args.Info.Count < USHORT_MAX);
  749. // Create the empty object if necessary:
  750. // - Built-in constructor functions will return a new object of a specific type, so a new empty object does not need to
  751. // be created
  752. // - If the newTarget is specified and the function is base kind then the this object will be already created. So we can
  753. // just use it instead of creating a new one.
  754. // - For user-defined constructor functions, an empty object is created with the function's prototype
  755. Var resultObject = nullptr;
  756. if (overridingNewTarget != nullptr && args.Info.Count > 0)
  757. {
  758. resultObject = args.Values[0];
  759. }
  760. else
  761. {
  762. resultObject = JavascriptOperators::NewScObjectNoCtor(v, scriptContext);
  763. }
  764. // JavascriptOperators::NewScObjectNoCtor should have thrown if 'v' is not a constructor
  765. RecyclableObject* functionObj = RecyclableObject::UnsafeFromVar(v);
  766. const unsigned STACK_ARGS_ALLOCA_THRESHOLD = 8; // Number of stack args we allow before using _alloca
  767. Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
  768. Var* newValues = args.Values;
  769. CallFlags newFlags = args.Info.Flags;
  770. bool thisAlreadySpecified = false;
  771. if (overridingNewTarget != nullptr)
  772. {
  773. ScriptFunction * scriptFunctionObj = JavascriptOperators::TryFromVar<ScriptFunction>(functionObj);
  774. uint newCount = args.Info.Count;
  775. if (scriptFunctionObj && scriptFunctionObj->GetFunctionInfo()->IsClassConstructor())
  776. {
  777. thisAlreadySpecified = true;
  778. args.Values[0] = overridingNewTarget;
  779. }
  780. else
  781. {
  782. newCount++;
  783. newFlags = (CallFlags)(newFlags | CallFlags_NewTarget | CallFlags_ExtraArg);
  784. if (newCount > STACK_ARGS_ALLOCA_THRESHOLD)
  785. {
  786. PROBE_STACK(scriptContext, newCount * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
  787. newValues = (Var*)_alloca(newCount * sizeof(Var));
  788. }
  789. else
  790. {
  791. newValues = stackArgs;
  792. }
  793. for (unsigned int i = 0; i < args.Info.Count; i++)
  794. {
  795. newValues[i] = args.Values[i];
  796. }
  797. #pragma prefast(suppress:6386, "The index is within the bounds")
  798. newValues[args.Info.Count] = overridingNewTarget;
  799. }
  800. }
  801. // Call the constructor function:
  802. // - If this is not already specified as the overriding new target in Reflect.construct a class case, then
  803. // - Pass in the new empty object as the 'this' parameter. This can be null if an empty object was not created.
  804. if (!thisAlreadySpecified)
  805. {
  806. newValues[0] = resultObject;
  807. }
  808. CallInfo newCallInfo(newFlags, args.Info.Count);
  809. Arguments newArgs(newCallInfo, newValues);
  810. if (JavascriptProxy::Is(v))
  811. {
  812. JavascriptProxy* proxy = JavascriptProxy::FromVar(v);
  813. return proxy->ConstructorTrap(newArgs, scriptContext, spreadIndices);
  814. }
  815. #if DBG
  816. if (scriptContext->IsScriptContextInDebugMode())
  817. {
  818. CheckValidDebugThunk(scriptContext, functionObj);
  819. }
  820. #endif
  821. Var functionResult;
  822. if (spreadIndices != nullptr)
  823. {
  824. functionResult = CallSpreadFunction(functionObj, newArgs, spreadIndices);
  825. }
  826. else
  827. {
  828. functionResult = CallFunction<true>(functionObj, functionObj->GetEntryPoint(), newArgs, true /*useLargeArgCount*/);
  829. }
  830. return
  831. FinishConstructor(
  832. functionResult,
  833. resultObject,
  834. JavascriptFunction::Is(functionObj) && functionObj->GetScriptContext() == scriptContext ?
  835. JavascriptFunction::FromVar(functionObj) :
  836. nullptr,
  837. overridingNewTarget != nullptr);
  838. }
  839. Var JavascriptFunction::FinishConstructor(
  840. const Var constructorReturnValue,
  841. Var newObject,
  842. JavascriptFunction *const function,
  843. bool hasOverridingNewTarget)
  844. {
  845. Assert(constructorReturnValue);
  846. // CONSIDER: Using constructorCache->ctorHasNoExplicitReturnValue to speed up this interpreter code path.
  847. if (JavascriptOperators::IsObject(constructorReturnValue))
  848. {
  849. newObject = constructorReturnValue;
  850. }
  851. // #3217: Cases with overriding newTarget are not what constructor cache is intended for;
  852. // Bypass constructor cache to avoid prototype mismatch/confusion.
  853. if (function && function->GetConstructorCache()->NeedsUpdateAfterCtor() && !hasOverridingNewTarget)
  854. {
  855. JavascriptOperators::UpdateNewScObjectCache(function, newObject, function->GetScriptContext());
  856. }
  857. return newObject;
  858. }
  859. Var JavascriptFunction::EntrySpreadCall(const Js::AuxArray<uint32> *spreadIndices, RecyclableObject* function, CallInfo callInfo, ...)
  860. {
  861. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  862. RUNTIME_ARGUMENTS(args, spreadIndices, function, callInfo);
  863. BEGIN_SAFE_REENTRANT_CALL(function->GetScriptContext()->GetThreadContext())
  864. {
  865. return JavascriptFunction::CallSpreadFunction(function, args, spreadIndices);
  866. }
  867. END_SAFE_REENTRANT_CALL
  868. }
  869. uint JavascriptFunction::GetSpreadSize(const Arguments args, const Js::AuxArray<uint32> *spreadIndices, ScriptContext *scriptContext)
  870. {
  871. // Work out the expanded number of arguments.
  872. AssertOrFailFast(args.Info.Count < CallInfo::kMaxCountArgs && args.Info.Count >= spreadIndices->count);
  873. uint spreadArgsCount = spreadIndices->count;
  874. uint32 totalLength = args.Info.Count - spreadArgsCount;
  875. for (unsigned i = 0; i < spreadArgsCount; ++i)
  876. {
  877. uint32 elementLength = JavascriptArray::GetSpreadArgLen(args[spreadIndices->elements[i]], scriptContext);
  878. if (elementLength >= CallInfo::kMaxCountArgs)
  879. {
  880. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgListTooLarge);
  881. }
  882. totalLength = UInt32Math::Add(totalLength, elementLength);
  883. }
  884. if (totalLength >= CallInfo::kMaxCountArgs)
  885. {
  886. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgListTooLarge);
  887. }
  888. return totalLength;
  889. }
  890. void JavascriptFunction::SpreadArgs(const Arguments args, Arguments& destArgs, const Js::AuxArray<uint32> *spreadIndices, ScriptContext *scriptContext)
  891. {
  892. Assert(args.Values != nullptr);
  893. Assert(destArgs.Values != nullptr);
  894. CallInfo callInfo = args.Info;
  895. uint argCount = args.GetArgCountWithExtraArgs();
  896. unsigned destArgCount = destArgs.GetLargeArgCountWithExtraArgs(); // Result can be bigger than Constants::MaxAllowedArgs
  897. size_t destArgsByteSize = destArgCount * sizeof(Var);
  898. destArgs.Values[0] = args[0];
  899. // Iterate over the arguments, spreading inline. We skip 'this'.
  900. uint32 argsIndex = 1;
  901. for (unsigned i = 1, spreadArgIndex = 0; i < argCount; ++i)
  902. {
  903. uint32 spreadIndex = spreadIndices->elements[spreadArgIndex]; // Next index to be spread.
  904. if (i < spreadIndex)
  905. {
  906. // Copy everything until the next spread index.
  907. js_memcpy_s(destArgs.Values + argsIndex,
  908. destArgsByteSize - (argsIndex * sizeof(Var)),
  909. args.Values + i,
  910. (spreadIndex - i) * sizeof(Var));
  911. argsIndex += spreadIndex - i;
  912. i = spreadIndex - 1;
  913. continue;
  914. }
  915. else if (i > spreadIndex)
  916. {
  917. // Copy everything after the last spread index.
  918. js_memcpy_s(destArgs.Values + argsIndex,
  919. destArgsByteSize - (argsIndex * sizeof(Var)),
  920. args.Values + i,
  921. (argCount - i) * sizeof(Var));
  922. break;
  923. }
  924. else
  925. {
  926. // Expand the spread element.
  927. Var instance = args[spreadIndex];
  928. if (SpreadArgument::Is(instance))
  929. {
  930. SpreadArgument* spreadedArgs = SpreadArgument::FromVar(instance);
  931. uint size = spreadedArgs->GetArgumentSpreadCount();
  932. if (size > 0)
  933. {
  934. const Var * spreadBuffer = spreadedArgs->GetArgumentSpread();
  935. js_memcpy_s(destArgs.Values + argsIndex,
  936. size * sizeof(Var),
  937. spreadBuffer,
  938. size * sizeof(Var));
  939. argsIndex += size;
  940. }
  941. }
  942. else
  943. {
  944. Assert(JavascriptOperators::IsUndefinedObject(instance));
  945. destArgs.Values[argsIndex++] = instance;
  946. }
  947. if (spreadArgIndex < spreadIndices->count - 1)
  948. {
  949. spreadArgIndex++;
  950. }
  951. }
  952. }
  953. if (argsIndex > destArgCount)
  954. {
  955. AssertMsg(false, "The array length has changed since we allocated the destArgs buffer?");
  956. Throw::FatalInternalError();
  957. }
  958. }
  959. Var JavascriptFunction::CallSpreadFunction(RecyclableObject* function, Arguments args, const Js::AuxArray<uint32> *spreadIndices)
  960. {
  961. ScriptContext* scriptContext = function->GetScriptContext();
  962. // Work out the expanded number of arguments.
  963. uint spreadSize = GetSpreadSize(args, spreadIndices, scriptContext);
  964. uint32 actualLength = CallInfo::GetLargeArgCountWithExtraArgs(args.Info.Flags, spreadSize);
  965. // Allocate (if needed) space for the expanded arguments.
  966. Arguments outArgs(CallInfo(args.Info.Flags, spreadSize), nullptr);
  967. Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
  968. size_t outArgsSize = 0;
  969. if (actualLength > STACK_ARGS_ALLOCA_THRESHOLD)
  970. {
  971. PROBE_STACK(scriptContext, actualLength * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
  972. outArgsSize = actualLength * sizeof(Var);
  973. outArgs.Values = (Var*)_alloca(outArgsSize);
  974. ZeroMemory(outArgs.Values, outArgsSize);
  975. }
  976. else
  977. {
  978. outArgs.Values = stackArgs;
  979. outArgsSize = STACK_ARGS_ALLOCA_THRESHOLD * sizeof(Var);
  980. ZeroMemory(outArgs.Values, outArgsSize); // We may not use all of the elements
  981. }
  982. SpreadArgs(args, outArgs, spreadIndices, scriptContext);
  983. // Number of arguments are allowed to be more than Constants::MaxAllowedArgs in runtime. Need to use the large argcount logic in this case.
  984. return JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), outArgs, true);
  985. }
  986. Var JavascriptFunction::CallFunction(Arguments args)
  987. {
  988. return JavascriptFunction::CallFunction<true>(this, this->GetEntryPoint(), args);
  989. }
  990. template Var JavascriptFunction::CallFunction<true>(RecyclableObject* function, JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount);
  991. template Var JavascriptFunction::CallFunction<false>(RecyclableObject* function, JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount);
  992. #if _M_IX86
  993. extern "C" Var BreakSpeculation(Var passthrough)
  994. {
  995. Var result = nullptr;
  996. __asm
  997. {
  998. mov ecx, passthrough;
  999. cmp ecx, ecx;
  1000. cmove eax, ecx;
  1001. mov result, eax;
  1002. }
  1003. return result;
  1004. }
  1005. #ifdef ASMJS_PLAT
  1006. template <> int JavascriptFunction::CallAsmJsFunction<int>(RecyclableObject * function, JavascriptMethod entryPoint, Var * argv, uint argsSize, byte* reg)
  1007. {
  1008. return CallAsmJsFunctionX86Thunk(function, entryPoint, argv, argsSize, reg).i32;
  1009. }
  1010. template <> int64 JavascriptFunction::CallAsmJsFunction<int64>(RecyclableObject * function, JavascriptMethod entryPoint, Var * argv, uint argsSize, byte* reg)
  1011. {
  1012. return CallAsmJsFunctionX86Thunk(function, entryPoint, argv, argsSize, reg).i64;
  1013. }
  1014. template <> float JavascriptFunction::CallAsmJsFunction<float>(RecyclableObject * function, JavascriptMethod entryPoint, Var * argv, uint argsSize, byte* reg)
  1015. {
  1016. return CallAsmJsFunctionX86Thunk(function, entryPoint, argv, argsSize, reg).f32;
  1017. }
  1018. template <> double JavascriptFunction::CallAsmJsFunction<double>(RecyclableObject * function, JavascriptMethod entryPoint, Var * argv, uint argsSize, byte* reg)
  1019. {
  1020. return CallAsmJsFunctionX86Thunk(function, entryPoint, argv, argsSize, reg).f64;
  1021. }
  1022. template <> AsmJsSIMDValue JavascriptFunction::CallAsmJsFunction<AsmJsSIMDValue>(RecyclableObject * function, JavascriptMethod entryPoint, Var * argv, uint argsSize, byte* reg)
  1023. {
  1024. return CallAsmJsFunctionX86Thunk(function, entryPoint, argv, argsSize, reg).simd;
  1025. }
  1026. PossibleAsmJsReturnValues JavascriptFunction::CallAsmJsFunctionX86Thunk(RecyclableObject * function, JavascriptMethod entryPoint, Var * argv, uint argsSize, byte*)
  1027. {
  1028. void* savedEsp;
  1029. _declspec(align(16)) PossibleAsmJsReturnValues retVals;
  1030. CompileAssert(sizeof(PossibleAsmJsReturnValues) == sizeof(int64) + sizeof(AsmJsSIMDValue));
  1031. CompileAssert(offsetof(PossibleAsmJsReturnValues, low) == offsetof(PossibleAsmJsReturnValues, i32));
  1032. CompileAssert(offsetof(PossibleAsmJsReturnValues, high) == offsetof(PossibleAsmJsReturnValues, i32) + sizeof(int32));
  1033. // call variable argument function provided in entryPoint
  1034. __asm
  1035. {
  1036. mov savedEsp, esp;
  1037. mov ecx, argsSize;
  1038. cmp ecx, 0x1000;
  1039. jl allocate_stack;
  1040. // Use _chkstk to probe each page when using more then a page size
  1041. mov eax, ecx;
  1042. call _chkstk; // _chkstk saves/restores ecx
  1043. allocate_stack:
  1044. sub esp, ecx;
  1045. mov edi, esp;
  1046. mov esi, argv;
  1047. add esi, 4; // Skip function
  1048. mov ecx, argsSize;
  1049. rep movs byte ptr[edi], byte ptr[esi];
  1050. mov ecx, entryPoint
  1051. #ifdef _CONTROL_FLOW_GUARD
  1052. // verify that the call target is valid
  1053. call[__guard_check_icall_fptr]
  1054. #endif
  1055. push function;
  1056. call ecx;
  1057. mov retVals.low, eax;
  1058. mov retVals.high, edx;
  1059. movaps retVals.xmm, xmm0;
  1060. // Restore ESP
  1061. mov esp, savedEsp;
  1062. }
  1063. return retVals;
  1064. }
  1065. #endif
  1066. #ifdef __clang__
  1067. void __cdecl _alloca_probe_16()
  1068. {
  1069. // todo: fix this!!!
  1070. abort();
  1071. __asm
  1072. {
  1073. push ecx
  1074. lea ecx, [esp + 8]
  1075. sub ecx, eax
  1076. and ecx, (16 - 1)
  1077. add eax, ecx
  1078. ret
  1079. }
  1080. }
  1081. #endif
  1082. static Var LocalCallFunction(RecyclableObject* function,
  1083. JavascriptMethod entryPoint, Arguments args, bool doStackProbe, bool useLargeArgCount = false)
  1084. {
  1085. Js::Var varResult;
  1086. #if DBG && ENABLE_NATIVE_CODEGEN
  1087. CheckIsExecutable(function, entryPoint);
  1088. #endif
  1089. // compute size of stack to reserve
  1090. CallInfo callInfo = args.Info;
  1091. uint argCount = useLargeArgCount ? args.GetLargeArgCountWithExtraArgs() : args.GetArgCountWithExtraArgs();
  1092. uint argsSize = argCount * sizeof(Var);
  1093. ScriptContext * scriptContext = function->GetScriptContext();
  1094. if (doStackProbe)
  1095. {
  1096. PROBE_STACK_CALL(scriptContext, function, argsSize);
  1097. }
  1098. JS_REENTRANCY_CHECK(scriptContext->GetThreadContext());
  1099. void *data;
  1100. void *savedEsp;
  1101. __asm {
  1102. // Save ESP
  1103. mov savedEsp, esp
  1104. mov eax, argsSize
  1105. // Make sure we don't go beyond guard page
  1106. cmp eax, 0x1000
  1107. jge alloca_probe
  1108. sub esp, eax
  1109. jmp dbl_align
  1110. alloca_probe:
  1111. // Use alloca to allocate more then a page size
  1112. // Alloca assumes eax, contains size, and adjust ESP while
  1113. // probing each page.
  1114. call _alloca_probe_16
  1115. dbl_align:
  1116. // 8-byte align frame to improve floating point perf of our JIT'd code.
  1117. and esp, -8
  1118. mov data, esp
  1119. }
  1120. {
  1121. Var* dest = (Var*)data;
  1122. Var* src = args.Values;
  1123. for(unsigned int i =0; i < argCount; i++)
  1124. {
  1125. dest[i] = src[i];
  1126. }
  1127. }
  1128. // call variable argument function provided in entryPoint
  1129. __asm
  1130. {
  1131. mov ecx, entryPoint
  1132. #ifdef _CONTROL_FLOW_GUARD
  1133. // verify that the call target is valid
  1134. call [__guard_check_icall_fptr]
  1135. #endif
  1136. push callInfo
  1137. push function
  1138. call ecx
  1139. // Restore ESP
  1140. mov esp, savedEsp
  1141. // save the return value from realsum.
  1142. mov varResult, eax;
  1143. }
  1144. return varResult;
  1145. }
  1146. // clang fails to create the labels,
  1147. // when __asm op is under a template function
  1148. template <bool doStackProbe>
  1149. Var JavascriptFunction::CallFunction(RecyclableObject* function,
  1150. JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount)
  1151. {
  1152. return LocalCallFunction(function, entryPoint, args, doStackProbe, useLargeArgCount);
  1153. }
  1154. #elif _M_X64
  1155. template <bool doStackProbe>
  1156. Var JavascriptFunction::CallFunction(RecyclableObject *function, JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount)
  1157. {
  1158. // compute size of stack to reserve and make sure we have enough stack.
  1159. uint argCount = useLargeArgCount ? args.GetLargeArgCountWithExtraArgs() : args.GetArgCountWithExtraArgs();
  1160. uint argsSize = argCount * sizeof(Var);
  1161. if (doStackProbe == true)
  1162. {
  1163. PROBE_STACK_CALL(function->GetScriptContext(), function, argsSize);
  1164. }
  1165. #if DBG && ENABLE_NATIVE_CODEGEN
  1166. CheckIsExecutable(function, entryPoint);
  1167. #endif
  1168. return JS_REENTRANCY_CHECK(function->GetScriptContext()->GetThreadContext(),
  1169. amd64_CallFunction(function, entryPoint, args.Info, argCount, &args.Values[0]));
  1170. }
  1171. #elif defined(_M_ARM)
  1172. extern "C"
  1173. {
  1174. extern Var arm_CallFunction(JavascriptFunction* function, CallInfo info, uint argCount, Var* values, JavascriptMethod entryPoint);
  1175. }
  1176. extern "C" Var BreakSpeculation(Var passthrough)
  1177. {
  1178. return passthrough;
  1179. }
  1180. template <bool doStackProbe>
  1181. Var JavascriptFunction::CallFunction(RecyclableObject* function, JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount)
  1182. {
  1183. // compute size of stack to reserve and make sure we have enough stack.
  1184. uint argCount = useLargeArgCount ? args.GetLargeArgCountWithExtraArgs() : args.GetArgCountWithExtraArgs();
  1185. uint argsSize = argCount * sizeof(Var);
  1186. if (doStackProbe)
  1187. {
  1188. PROBE_STACK_CALL(function->GetScriptContext(), function, argsSize);
  1189. }
  1190. #if DBG && ENABLE_NATIVE_CODEGEN
  1191. CheckIsExecutable(function, entryPoint);
  1192. #endif
  1193. Js::Var varResult;
  1194. //The ARM can pass 4 arguments via registers so handle the cases for 0 or 1 values without resorting to asm code
  1195. //(so that the asm code can assume 0 or more values will go on the stack: putting -1 values on the stack is unhealthy).
  1196. if (argCount == 0)
  1197. {
  1198. varResult = CALL_ENTRYPOINT(function->GetScriptContext()->GetThreadContext(), entryPoint, (JavascriptFunction*)function, args.Info);
  1199. }
  1200. else if (argCount == 1)
  1201. {
  1202. varResult = CALL_ENTRYPOINT(function->GetScriptContext()->GetThreadContext(), entryPoint, (JavascriptFunction*)function, args.Info, args.Values[0]);
  1203. }
  1204. else
  1205. {
  1206. varResult = JS_REENTRANCY_CHECK(function->GetScriptContext()->GetThreadContext(),
  1207. arm_CallFunction((JavascriptFunction*)function, args.Info, argCount, args.Values, entryPoint));
  1208. }
  1209. return varResult;
  1210. }
  1211. #elif defined(_M_ARM64)
  1212. extern "C"
  1213. {
  1214. extern Var arm64_CallFunction(JavascriptFunction* function, CallInfo info, uint argCount, Var* values, JavascriptMethod entryPoint);
  1215. }
  1216. template <bool doStackProbe>
  1217. Var JavascriptFunction::CallFunction(RecyclableObject* function, JavascriptMethod entryPoint, Arguments args, bool useLargeArgCount)
  1218. {
  1219. // compute size of stack to reserve and make sure we have enough stack.
  1220. uint argCount = useLargeArgCount ? args.GetLargeArgCountWithExtraArgs() : args.GetArgCountWithExtraArgs();
  1221. uint argsSize = argCount * sizeof(Var);
  1222. if (doStackProbe)
  1223. {
  1224. PROBE_STACK_CALL(function->GetScriptContext(), function, argsSize);
  1225. }
  1226. #if DBG && ENABLE_NATIVE_CODEGEN
  1227. CheckIsExecutable(function, entryPoint);
  1228. #endif
  1229. Js::Var varResult;
  1230. varResult = JS_REENTRANCY_CHECK(function->GetScriptContext()->GetThreadContext(),
  1231. arm64_CallFunction((JavascriptFunction*)function, args.Info, argCount, args.Values, entryPoint));
  1232. return varResult;
  1233. }
  1234. #else
  1235. Var JavascriptFunction::CallFunction(RecyclableObject *function, JavascriptMethod entryPoint, Arguments args)
  1236. {
  1237. #if DBG && ENABLE_NATIVE_CODEGEN
  1238. CheckIsExecutable(function, entryPoint);
  1239. #endif
  1240. #if 1
  1241. Js::Throw::NotImplemented();
  1242. return nullptr;
  1243. #else
  1244. Var varResult;
  1245. switch (info.Count)
  1246. {
  1247. case 0:
  1248. {
  1249. varResult=entryPoint((JavascriptFunction*)function, args.Info);
  1250. break;
  1251. }
  1252. case 1: {
  1253. varResult=entryPoint(
  1254. (JavascriptFunction*)function,
  1255. args.Info,
  1256. args.Values[0]);
  1257. break;
  1258. }
  1259. case 2: {
  1260. varResult=entryPoint(
  1261. (JavascriptFunction*)function,
  1262. args.Info,
  1263. args.Values[0],
  1264. args.Values[1]);
  1265. break;
  1266. }
  1267. case 3: {
  1268. varResult=entryPoint(
  1269. (JavascriptFunction*)function,
  1270. args.Info,
  1271. args.Values[0],
  1272. args.Values[1],
  1273. args.Values[2]);
  1274. break;
  1275. }
  1276. case 4: {
  1277. varResult=entryPoint(
  1278. (JavascriptFunction*)function,
  1279. args.Info,
  1280. args.Values[0],
  1281. args.Values[1],
  1282. args.Values[2],
  1283. args.Values[3]);
  1284. break;
  1285. }
  1286. case 5: {
  1287. varResult=entryPoint(
  1288. (JavascriptFunction*)function,
  1289. args.Info,
  1290. args.Values[0],
  1291. args.Values[1],
  1292. args.Values[2],
  1293. args.Values[3],
  1294. args.Values[4]);
  1295. break;
  1296. }
  1297. case 6: {
  1298. varResult=entryPoint(
  1299. (JavascriptFunction*)function,
  1300. args.Info,
  1301. args.Values[0],
  1302. args.Values[1],
  1303. args.Values[2],
  1304. args.Values[3],
  1305. args.Values[4],
  1306. args.Values[5]);
  1307. break;
  1308. }
  1309. case 7: {
  1310. varResult=entryPoint(
  1311. (JavascriptFunction*)function,
  1312. args.Info,
  1313. args.Values[0],
  1314. args.Values[1],
  1315. args.Values[2],
  1316. args.Values[3],
  1317. args.Values[4],
  1318. args.Values[5],
  1319. args.Values[6]);
  1320. break;
  1321. }
  1322. case 8: {
  1323. varResult=entryPoint(
  1324. (JavascriptFunction*)function,
  1325. args.Info,
  1326. args.Values[0],
  1327. args.Values[1],
  1328. args.Values[2],
  1329. args.Values[3],
  1330. args.Values[4],
  1331. args.Values[5],
  1332. args.Values[6],
  1333. args.Values[7]);
  1334. break;
  1335. }
  1336. case 9: {
  1337. varResult=entryPoint(
  1338. (JavascriptFunction*)function,
  1339. args.Info,
  1340. args.Values[0],
  1341. args.Values[1],
  1342. args.Values[2],
  1343. args.Values[3],
  1344. args.Values[4],
  1345. args.Values[5],
  1346. args.Values[6],
  1347. args.Values[7],
  1348. args.Values[8]);
  1349. break;
  1350. }
  1351. default:
  1352. ScriptContext* scriptContext = function->type->GetScriptContext();
  1353. varResult = scriptContext->GetLibrary()->GetUndefined();
  1354. AssertMsg(false, "CallFunction call with unsupported number of arguments");
  1355. break;
  1356. }
  1357. #endif
  1358. return varResult;
  1359. }
  1360. #endif
  1361. Var JavascriptFunction::EntryToString(RecyclableObject* function, CallInfo callInfo, ...)
  1362. {
  1363. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  1364. ARGUMENTS(args, callInfo);
  1365. ScriptContext* scriptContext = function->GetScriptContext();
  1366. Assert(!(callInfo.Flags & CallFlags_New));
  1367. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  1368. if (args.Info.Count == 0 || !JavascriptFunction::Is(args[0]))
  1369. {
  1370. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedFunction, _u("Function.prototype.toString"));
  1371. }
  1372. JavascriptFunction *pFunc = JavascriptFunction::FromVar(args[0]);
  1373. // pFunc can be from a different script context if Function.prototype.toString is invoked via .call/.apply.
  1374. // Marshal the resulting string to the current script context (that of the toString)
  1375. return CrossSite::MarshalVar(scriptContext, pFunc->EnsureSourceString());
  1376. }
  1377. JavascriptString* JavascriptFunction::GetNativeFunctionDisplayString(ScriptContext *scriptContext, JavascriptString *name)
  1378. {
  1379. return GetNativeFunctionDisplayStringCommon<JavascriptString>(scriptContext, name);
  1380. }
  1381. JavascriptString* JavascriptFunction::GetLibraryCodeDisplayString(ScriptContext *scriptContext, PCWSTR displayName)
  1382. {
  1383. return GetLibraryCodeDisplayStringCommon<JavascriptString, JavascriptString*>(scriptContext, displayName);
  1384. }
  1385. #ifdef _M_IX86
  1386. // This code is enabled by the -checkAlignment switch.
  1387. // It verifies that all of our JS frames are 8 byte aligned.
  1388. // Our alignments is based on aligning the return address of the function.
  1389. // Note that this test can fail when Javascript functions are called directly
  1390. // from helper functions. This could be fixed by making these calls through
  1391. // CallFunction(), or by having the helper 8 byte align the frame itself before
  1392. // the call. A lot of these though are not dealing with floats, so the cost
  1393. // of doing the 8 byte alignment would outweigh the benefit...
  1394. __declspec (naked)
  1395. void JavascriptFunction::CheckAlignment()
  1396. {
  1397. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrFunc_CheckAlignment);
  1398. _asm
  1399. {
  1400. test esp, 0x4
  1401. je LABEL1
  1402. ret
  1403. LABEL1:
  1404. call Throw::InternalError
  1405. }
  1406. JIT_HELPER_END(ScrFunc_CheckAlignment);
  1407. }
  1408. #else
  1409. void JavascriptFunction::CheckAlignment()
  1410. {
  1411. JIT_HELPER_NOT_REENTRANT_NOLOCK_HEADER(ScrFunc_CheckAlignment);
  1412. // Note: in order to enable this on ARM, uncomment/fix code in LowerMD.cpp (LowerEntryInstr).
  1413. JIT_HELPER_END(ScrFunc_CheckAlignment);
  1414. }
  1415. #endif
  1416. BOOL JavascriptFunction::IsNativeAddress(ScriptContext * scriptContext, void * codeAddr)
  1417. {
  1418. #if ENABLE_NATIVE_CODEGEN
  1419. return scriptContext->IsNativeAddress(codeAddr);
  1420. #else
  1421. return false;
  1422. #endif
  1423. }
  1424. Js::JavascriptMethod JavascriptFunction::DeferredParse(ScriptFunction** functionRef)
  1425. {
  1426. BOOL fParsed;
  1427. return Js::ScriptFunction::DeferredParseCore(functionRef, fParsed);
  1428. }
  1429. Js::JavascriptMethod JavascriptFunction::DeferredParseCore(ScriptFunction** functionRef, BOOL &fParsed)
  1430. {
  1431. // Do the actual deferred parsing and byte code generation, passing the new entry point to the caller.
  1432. ParseableFunctionInfo* functionInfo = (*functionRef)->GetParseableFunctionInfo();
  1433. FunctionBody* funcBody = nullptr;
  1434. Assert(functionInfo);
  1435. if (functionInfo->IsDeferredParseFunction())
  1436. {
  1437. funcBody = functionInfo->Parse(functionRef);
  1438. fParsed = funcBody->IsFunctionParsed() ? TRUE : FALSE;
  1439. #if ENABLE_PROFILE_INFO
  1440. // This is the first call to the function, ensure dynamic profile info
  1441. funcBody->EnsureDynamicProfileInfo();
  1442. #endif
  1443. }
  1444. else
  1445. {
  1446. funcBody = functionInfo->GetFunctionBody();
  1447. Assert(funcBody != nullptr);
  1448. Assert(!funcBody->IsDeferredParseFunction());
  1449. }
  1450. DebugOnly(JavascriptMethod directEntryPoint = funcBody->GetDirectEntryPoint(funcBody->GetDefaultEntryPointInfo()));
  1451. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  1452. Assert(directEntryPoint != DefaultDeferredParsingThunk
  1453. && directEntryPoint != ProfileDeferredParsingThunk);
  1454. #else // !ENABLE_SCRIPT_PROFILING && !ENABLE_SCRIPT_DEBUGGING
  1455. Assert(directEntryPoint != DefaultDeferredParsingThunk);
  1456. #endif
  1457. JavascriptMethod thunkEntryPoint = (*functionRef)->UpdateUndeferredBody(funcBody);
  1458. return thunkEntryPoint;
  1459. }
  1460. void JavascriptFunction::ReparseAsmJsModule(ScriptFunction** functionRef)
  1461. {
  1462. ParseableFunctionInfo* functionInfo = (*functionRef)->GetParseableFunctionInfo();
  1463. Assert(functionInfo);
  1464. try
  1465. {
  1466. functionInfo->GetFunctionBody()->AddDeferParseAttribute();
  1467. functionInfo->GetFunctionBody()->ResetEntryPoint();
  1468. functionInfo->GetFunctionBody()->ResetInParams();
  1469. FunctionBody * funcBody = functionInfo->Parse(functionRef);
  1470. #if ENABLE_PROFILE_INFO
  1471. // This is the first call to the function, ensure dynamic profile info
  1472. funcBody->EnsureDynamicProfileInfo();
  1473. #endif
  1474. (*functionRef)->UpdateUndeferredBody(funcBody);
  1475. }
  1476. catch (JavascriptException&)
  1477. {
  1478. Js::Throw::FatalInternalError();
  1479. }
  1480. }
  1481. // Thunk for handling calls to functions that have not had byte code generated for them.
  1482. #if _M_IX86
  1483. __declspec(naked)
  1484. Var JavascriptFunction::DeferredParsingThunk(RecyclableObject* function, CallInfo callInfo, ...)
  1485. {
  1486. __asm
  1487. {
  1488. push ebp
  1489. mov ebp, esp
  1490. lea eax, [esp+8] // load the address of the function os that if we need to box, we can patch it up
  1491. push eax
  1492. call JavascriptFunction::DeferredParse
  1493. #ifdef _CONTROL_FLOW_GUARD
  1494. // verify that the call target is valid
  1495. mov ecx, eax
  1496. call[__guard_check_icall_fptr]
  1497. mov eax, ecx
  1498. #endif
  1499. pop ebp
  1500. jmp eax
  1501. }
  1502. }
  1503. #elif defined(_M_X64) || defined(_M_ARM32_OR_ARM64)
  1504. //Do nothing: the implementation of JavascriptFunction::DeferredParsingThunk is declared (appropriately decorated) in
  1505. // Library\amd64\javascriptfunctiona.asm
  1506. // Library\arm\arm_DeferredParsingThunk.asm
  1507. // Library\arm64\arm64_DeferredParsingThunk.asm
  1508. #else
  1509. Var JavascriptFunction::DeferredParsingThunk(RecyclableObject* function, CallInfo callInfo, ...)
  1510. {
  1511. Js::Throw::NotImplemented();
  1512. return nullptr;
  1513. }
  1514. #endif
  1515. ConstructorCache* JavascriptFunction::EnsureValidConstructorCache()
  1516. {
  1517. Assert(this->constructorCache != nullptr);
  1518. this->constructorCache = ConstructorCache::EnsureValidInstance(this->constructorCache, this->GetScriptContext());
  1519. return this->constructorCache;
  1520. }
  1521. void JavascriptFunction::ResetConstructorCacheToDefault()
  1522. {
  1523. Assert(this->constructorCache != nullptr);
  1524. if (!this->constructorCache->IsDefault())
  1525. {
  1526. this->constructorCache = &ConstructorCache::DefaultInstance;
  1527. }
  1528. }
  1529. // Thunk for handling calls to functions that have not had byte code generated for them.
  1530. #if _M_IX86
  1531. __declspec(naked)
  1532. Var JavascriptFunction::DeferredDeserializeThunk(RecyclableObject* function, CallInfo callInfo, ...)
  1533. {
  1534. __asm
  1535. {
  1536. push ebp
  1537. mov ebp, esp
  1538. push [esp+8]
  1539. call JavascriptFunction::DeferredDeserialize
  1540. #ifdef _CONTROL_FLOW_GUARD
  1541. // verify that the call target is valid
  1542. mov ecx, eax
  1543. call[__guard_check_icall_fptr]
  1544. mov eax, ecx
  1545. #endif
  1546. pop ebp
  1547. jmp eax
  1548. }
  1549. }
  1550. #elif (defined(_M_X64) || defined(_M_ARM32_OR_ARM64)) && defined(_MSC_VER)
  1551. //Do nothing: the implementation of JavascriptFunction::DeferredParsingThunk is declared (appropriately decorated) in
  1552. // Library\amd64\javascriptfunctiona.asm
  1553. // Library\arm\arm_DeferredParsingThunk.asm
  1554. // Library\arm64\arm64_DeferredParsingThunk.asm
  1555. #else
  1556. // xplat implement in
  1557. // Library/amd64/JavascriptFunctionA.S
  1558. #endif
  1559. Js::JavascriptMethod JavascriptFunction::DeferredDeserialize(ScriptFunction* function)
  1560. {
  1561. FunctionInfo* funcInfo = function->GetFunctionInfo();
  1562. Assert(funcInfo);
  1563. FunctionBody* funcBody = nullptr;
  1564. // If we haven't already deserialized this function, do so now
  1565. // FunctionProxies could have gotten deserialized during the interpreter when
  1566. // we tried to record the callsite info for the function which meant that it was a
  1567. // target of a call. Or we could have deserialized the function info in another JavascriptFunctionInstance
  1568. // In any case, fix up the function info if it's already been deserialized so that
  1569. // we don't hold on to the proxy for too long, and rethunk it so that it directly
  1570. // calls the default entry point the next time around
  1571. if (funcInfo->IsDeferredDeserializeFunction())
  1572. {
  1573. DeferDeserializeFunctionInfo* deferDeserializeFunction = funcInfo->GetDeferDeserializeFunctionInfo();
  1574. // This is the first call to the function, ensure dynamic profile info
  1575. // Deserialize is a no-op if the function has already been deserialized
  1576. funcBody = deferDeserializeFunction->Deserialize();
  1577. #if ENABLE_PROFILE_INFO
  1578. funcBody->EnsureDynamicProfileInfo();
  1579. #endif
  1580. }
  1581. else
  1582. {
  1583. funcBody = funcInfo->GetFunctionBody();
  1584. Assert(funcBody != nullptr);
  1585. Assert(!funcBody->IsDeferredDeserializeFunction());
  1586. }
  1587. return function->UpdateUndeferredBody(funcBody);
  1588. }
  1589. void JavascriptFunction::SetEntryPoint(JavascriptMethod method)
  1590. {
  1591. this->GetDynamicType()->SetEntryPoint(method);
  1592. }
  1593. JavascriptString * JavascriptFunction::EnsureSourceString()
  1594. {
  1595. return this->GetLibrary()->GetFunctionDisplayString();
  1596. }
  1597. /*
  1598. *****************************************************************************************************************
  1599. Conditions checked by instruction decoder (In sequential order)
  1600. ******************************************************************************************************************
  1601. 1) Exception Code is AV i.e STATUS_ACCESS_VIOLATION
  1602. 2) Check if Rip is Native address
  1603. 3) Get the function object from RBP (a fixed offset from RBP) and check for the following
  1604. a. Not Null
  1605. b. Ensure that the function object is heap allocated
  1606. c. Ensure that the entrypointInfo is heap allocated
  1607. d. Ensure that the functionbody is heap allocated
  1608. e. Is a function
  1609. f. Is AsmJs Function object for asmjs
  1610. 4) Check if Array BufferLength > 0x10000 (64K), power of 2 if length is less than 2^24 or multiple of 2^24 and multiple of 0x1000(4K) for asmjs
  1611. 5) Check If the instruction is valid
  1612. a. Is one of the move instructions , i.e. mov, movsx, movzx, movsxd, movss or movsd
  1613. b. Get the array buffer register and its value for asmjs
  1614. c. Get the dst register(in case of load)
  1615. d. Calculate the number of bytes read in order to get the length of the instruction , ensure that the length should never be greater than 15 bytes
  1616. 6) Check that the Array buffer value is same as the one we passed in EntryPointInfo in asmjs
  1617. 7) Set the dst reg if the instr type is load
  1618. 8) Add the bytes read to Rip and set it as new Rip
  1619. 9) Return EXCEPTION_CONTINUE_EXECUTION
  1620. */
  1621. #if ENABLE_NATIVE_CODEGEN
  1622. #if defined(_M_IX86) || defined(_M_X64)
  1623. class ExceptionFilterHelper
  1624. {
  1625. Js::ScriptFunction* m_func = nullptr;
  1626. bool m_checkedForFunc = false;
  1627. PEXCEPTION_POINTERS exceptionInfo;
  1628. public:
  1629. ExceptionFilterHelper(PEXCEPTION_POINTERS exceptionInfo) : exceptionInfo(exceptionInfo) {}
  1630. PEXCEPTION_POINTERS GetExceptionInfo() const
  1631. {
  1632. return exceptionInfo;
  1633. }
  1634. uintptr_t GetFaultingAddress() const
  1635. {
  1636. // For AVs, the second element of ExceptionInformation array is address of inaccessible data
  1637. // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx
  1638. Assert(this->exceptionInfo->ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION);
  1639. Assert(this->exceptionInfo->ExceptionRecord->NumberParameters >= 2);
  1640. return exceptionInfo->ExceptionRecord->ExceptionInformation[1];
  1641. }
  1642. Var GetIPAddress() const
  1643. {
  1644. #if _M_IX86
  1645. return (Var)exceptionInfo->ContextRecord->Eip;
  1646. #elif _M_X64
  1647. return (Var)exceptionInfo->ContextRecord->Rip;
  1648. #else
  1649. #error Not yet Implemented
  1650. #endif
  1651. }
  1652. Var* GetAddressOfFuncObj() const
  1653. {
  1654. #if _M_IX86
  1655. return (Var*)(exceptionInfo->ContextRecord->Ebp + 2 * sizeof(Var));
  1656. #elif _M_X64
  1657. return (Var*)(exceptionInfo->ContextRecord->Rbp + 2 * sizeof(Var));
  1658. #else
  1659. #error Not yet Implemented
  1660. #endif
  1661. }
  1662. Js::ScriptFunction* GetScriptFunction()
  1663. {
  1664. if (m_checkedForFunc)
  1665. {
  1666. return m_func;
  1667. }
  1668. m_checkedForFunc = true;
  1669. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  1670. // AV should come from JITed code, since we don't eliminate bound checks in interpreter
  1671. if (!threadContext->IsNativeAddress(GetIPAddress()))
  1672. {
  1673. return nullptr;
  1674. }
  1675. Var* addressOfFuncObj = GetAddressOfFuncObj();
  1676. if (!addressOfFuncObj || *addressOfFuncObj == nullptr || !ScriptFunction::Is(*addressOfFuncObj))
  1677. {
  1678. return nullptr;
  1679. }
  1680. Js::ScriptFunction* func = (Js::ScriptFunction*)(*addressOfFuncObj);
  1681. RecyclerHeapObjectInfo heapObject;
  1682. Recycler* recycler = threadContext->GetRecycler();
  1683. bool isEntryPointHeapAllocated = recycler->FindHeapObject(func->GetEntryPointInfo(), FindHeapObjectFlags_NoFlags, heapObject);
  1684. bool isFunctionBodyHeapAllocated = recycler->FindHeapObject(func->GetFunctionBody(), FindHeapObjectFlags_NoFlags, heapObject);
  1685. // ensure that all our objects are heap allocated
  1686. if (!(isEntryPointHeapAllocated && isFunctionBodyHeapAllocated))
  1687. {
  1688. return nullptr;
  1689. }
  1690. m_func = func;
  1691. return m_func;
  1692. }
  1693. };
  1694. void CheckWasmMathException(int exceptionCode, ExceptionFilterHelper& helper)
  1695. {
  1696. if (CONFIG_FLAG(WasmMathExFilter) && (exceptionCode == STATUS_INTEGER_DIVIDE_BY_ZERO || exceptionCode == STATUS_INTEGER_OVERFLOW))
  1697. {
  1698. Js::ScriptFunction* func = helper.GetScriptFunction();
  1699. if (func)
  1700. {
  1701. Js::FunctionBody* funcBody = func->GetFunctionBody();
  1702. if (funcBody && funcBody->IsWasmFunction())
  1703. {
  1704. int32 code = exceptionCode == STATUS_INTEGER_DIVIDE_BY_ZERO ? WASMERR_DivideByZero : VBSERR_Overflow;
  1705. JavascriptError::ThrowWebAssemblyRuntimeError(func->GetScriptContext(), code);
  1706. }
  1707. }
  1708. }
  1709. }
  1710. // x64 specific exception filters
  1711. #ifdef _M_X64
  1712. ArrayAccessDecoder::InstructionData ArrayAccessDecoder::CheckValidInstr(BYTE* &pc, PEXCEPTION_POINTERS exceptionInfo) // get the reg operand and isLoad and
  1713. {
  1714. InstructionData instrData;
  1715. uint prefixValue = 0;
  1716. ArrayAccessDecoder::RexByteValue rexByteValue;
  1717. bool isFloat = false;
  1718. uint immBytes = 0;
  1719. uint dispBytes = 0;
  1720. bool isImmediate = false;
  1721. bool isSIB = false;
  1722. // Read first byte - check for prefix
  1723. BYTE* beginPc = pc;
  1724. if (((*pc) == 0x0F2) || ((*pc) == 0x0F3))
  1725. {
  1726. //MOVSD or MOVSS
  1727. prefixValue = *pc;
  1728. isFloat = true;
  1729. pc++;
  1730. }
  1731. else if (*pc == 0x66)
  1732. {
  1733. prefixValue = *pc;
  1734. pc++;
  1735. }
  1736. // Check for Rex Byte - After prefix we should have a rexByte if there is one
  1737. if (*pc >= 0x40 && *pc <= 0x4F)
  1738. {
  1739. rexByteValue.rexValue = *pc;
  1740. uint rexByte = *pc - 0x40;
  1741. if (rexByte & 0x8)
  1742. {
  1743. rexByteValue.isW = true;
  1744. }
  1745. if (rexByte & 0x4)
  1746. {
  1747. rexByteValue.isR = true;
  1748. }
  1749. if (rexByte & 0x2)
  1750. {
  1751. rexByteValue.isX = true;
  1752. }
  1753. if (rexByte & 0x1)
  1754. {
  1755. rexByteValue.isB = true;
  1756. }
  1757. pc++;
  1758. }
  1759. // read opcode
  1760. // Is one of the move instructions , i.e. mov, movsx, movzx, movsxd, movss or movsd
  1761. switch (*pc)
  1762. {
  1763. //MOV - Store
  1764. case 0x89:
  1765. case 0x88:
  1766. {
  1767. pc++;
  1768. instrData.isLoad = false;
  1769. break;
  1770. }
  1771. //MOVSXD
  1772. case 0x63:
  1773. //MOV - Load
  1774. case 0x8A:
  1775. case 0x8B:
  1776. {
  1777. pc++;
  1778. instrData.isLoad = true;
  1779. break;
  1780. }
  1781. case 0x0F:
  1782. {
  1783. // more than one byte opcode and hence we will read pc multiple times
  1784. pc++;
  1785. //MOVSX
  1786. if (*pc == 0xBE || *pc == 0xBF)
  1787. {
  1788. instrData.isLoad = true;
  1789. }
  1790. //MOVZX
  1791. else if (*pc == 0xB6 || *pc == 0xB7)
  1792. {
  1793. instrData.isLoad = true;
  1794. }
  1795. //MOVSS - Load
  1796. else if (*pc == 0x10 && prefixValue == 0xF3)
  1797. {
  1798. Assert(isFloat);
  1799. instrData.isLoad = true;
  1800. instrData.isFloat32 = true;
  1801. }
  1802. //MOVSS - Store
  1803. else if (*pc == 0x11 && prefixValue == 0xF3)
  1804. {
  1805. Assert(isFloat);
  1806. instrData.isLoad = false;
  1807. instrData.isFloat32 = true;
  1808. }
  1809. //MOVSD - Load
  1810. else if (*pc == 0x10 && prefixValue == 0xF2)
  1811. {
  1812. Assert(isFloat);
  1813. instrData.isLoad = true;
  1814. instrData.isFloat64 = true;
  1815. }
  1816. //MOVSD - Store
  1817. else if (*pc == 0x11 && prefixValue == 0xF2)
  1818. {
  1819. Assert(isFloat);
  1820. instrData.isLoad = false;
  1821. instrData.isFloat64 = true;
  1822. }
  1823. //MOVUPS - Load
  1824. else if (*pc == 0x10 && prefixValue == 0)
  1825. {
  1826. instrData.isLoad = true;
  1827. instrData.isSimd = true;
  1828. }
  1829. //MOVUPS - Store
  1830. else if (*pc == 0x11 && prefixValue == 0)
  1831. {
  1832. instrData.isLoad = false;
  1833. instrData.isSimd = true;
  1834. }
  1835. else
  1836. {
  1837. instrData.isInvalidInstr = true;
  1838. }
  1839. pc++;
  1840. break;
  1841. }
  1842. // Support Mov Immediates
  1843. // MOV
  1844. case 0xC6:
  1845. case 0xC7:
  1846. {
  1847. instrData.isLoad = false;
  1848. instrData.isFloat64 = false;
  1849. isImmediate = true;
  1850. if (*pc == 0xC6)
  1851. {
  1852. immBytes = 1;
  1853. }
  1854. else if (rexByteValue.isW) // For MOV, REX.W set means we have a 32 bit immediate value, which gets extended to 64 bit.
  1855. {
  1856. immBytes = 4;
  1857. }
  1858. else
  1859. {
  1860. if (prefixValue == 0x66)
  1861. {
  1862. immBytes = 2;
  1863. }
  1864. else
  1865. {
  1866. immBytes = 4;
  1867. }
  1868. }
  1869. pc++;
  1870. break;
  1871. }
  1872. default:
  1873. instrData.isInvalidInstr = true;
  1874. break;
  1875. }
  1876. // if the opcode is not a move return
  1877. if (instrData.isInvalidInstr)
  1878. {
  1879. return instrData;
  1880. }
  1881. //Read ModR/M
  1882. // Read the Src Reg and also check for SIB
  1883. // Add the isR bit to SrcReg and get the actual SRCReg
  1884. // Get the number of bytes for displacement
  1885. //get mod bits
  1886. BYTE modVal = *pc & 0xC0; // first two bits(7th and 6th bits)
  1887. modVal >>= 6;
  1888. //get the R/M bits
  1889. BYTE rmVal = (*pc) & 0x07; // last 3 bits ( 0,1 and 2nd bits)
  1890. //get the reg value
  1891. BYTE dstReg = (*pc) & 0x38; // mask reg bits (3rd 4th and 5th bits)
  1892. dstReg >>= 3;
  1893. Assert(dstReg <= 0x07);
  1894. Assert(modVal <= 0x03);
  1895. Assert(rmVal <= 0x07);
  1896. switch (modVal)
  1897. {
  1898. case 0x00:
  1899. dispBytes = 0;
  1900. break;
  1901. case 0x01:
  1902. dispBytes = 1;
  1903. break;
  1904. case 0x02:
  1905. dispBytes = 4;
  1906. break;
  1907. default:
  1908. instrData.isInvalidInstr = true;
  1909. break;
  1910. }
  1911. if (instrData.isInvalidInstr)
  1912. {
  1913. return instrData;
  1914. }
  1915. // Get the R/M value and see if SIB is present , else get the buffer reg
  1916. if (rmVal == 0x04)
  1917. {
  1918. isSIB = true;
  1919. }
  1920. else
  1921. {
  1922. instrData.bufferReg = rmVal;
  1923. }
  1924. // Get the RegByes from ModRM
  1925. instrData.dstReg = dstReg;
  1926. // increment the modrm byte
  1927. pc++;
  1928. // Check if we have SIB and in that case bufferReg should not be set
  1929. if (isSIB)
  1930. {
  1931. Assert(!instrData.bufferReg);
  1932. // Get the Base and Index Reg from SIB and ensure that Scale is zero
  1933. // We don't care about the Index reg
  1934. // Add the isB value from Rex and get the actual Base Reg
  1935. // Get the base register
  1936. // 6f. Get the array buffer register and its value
  1937. instrData.bufferReg = (*pc % 8);
  1938. pc++;
  1939. }
  1940. // check for the Rex.B value and append it to the base register
  1941. if (rexByteValue.isB)
  1942. {
  1943. instrData.bufferReg |= 1 << 3;
  1944. }
  1945. // check for the Rex.R value and append it to the dst register
  1946. if (rexByteValue.isR)
  1947. {
  1948. instrData.dstReg |= 1 << 3;
  1949. }
  1950. // Get the buffer address - this is always 64 bit GPR
  1951. switch (instrData.bufferReg)
  1952. {
  1953. case 0x0:
  1954. instrData.bufferValue = exceptionInfo->ContextRecord->Rax;
  1955. break;
  1956. case 0x1:
  1957. instrData.bufferValue = exceptionInfo->ContextRecord->Rcx;
  1958. break;
  1959. case 0x2:
  1960. instrData.bufferValue = exceptionInfo->ContextRecord->Rdx;
  1961. break;
  1962. case 0x3:
  1963. instrData.bufferValue = exceptionInfo->ContextRecord->Rbx;
  1964. break;
  1965. case 0x4:
  1966. instrData.bufferValue = exceptionInfo->ContextRecord->Rsp;
  1967. break;
  1968. case 0x5:
  1969. // RBP wouldn't point to an array buffer
  1970. instrData.bufferValue = NULL;
  1971. break;
  1972. case 0x6:
  1973. instrData.bufferValue = exceptionInfo->ContextRecord->Rsi;
  1974. break;
  1975. case 0x7:
  1976. instrData.bufferValue = exceptionInfo->ContextRecord->Rdi;
  1977. break;
  1978. case 0x8:
  1979. instrData.bufferValue = exceptionInfo->ContextRecord->R8;
  1980. break;
  1981. case 0x9:
  1982. instrData.bufferValue = exceptionInfo->ContextRecord->R9;
  1983. break;
  1984. case 0xA:
  1985. instrData.bufferValue = exceptionInfo->ContextRecord->R10;
  1986. break;
  1987. case 0xB:
  1988. instrData.bufferValue = exceptionInfo->ContextRecord->R11;
  1989. break;
  1990. case 0xC:
  1991. instrData.bufferValue = exceptionInfo->ContextRecord->R12;
  1992. break;
  1993. case 0xD:
  1994. instrData.bufferValue = exceptionInfo->ContextRecord->R13;
  1995. break;
  1996. case 0xE:
  1997. instrData.bufferValue = exceptionInfo->ContextRecord->R14;
  1998. break;
  1999. case 0xF:
  2000. instrData.bufferValue = exceptionInfo->ContextRecord->R15;
  2001. break;
  2002. default:
  2003. instrData.isInvalidInstr = true;
  2004. Assert(false);// should never reach here as validation is done before itself
  2005. return instrData;
  2006. }
  2007. // add the pc for displacement , we don't need the displacement Byte value
  2008. if (dispBytes > 0)
  2009. {
  2010. pc = pc + dispBytes;
  2011. }
  2012. instrData.instrSizeInByte = (uint)(pc - beginPc);
  2013. if (isImmediate)
  2014. {
  2015. Assert(immBytes > 0);
  2016. instrData.instrSizeInByte += immBytes;
  2017. }
  2018. // Calculate the number of bytes read in order to get the length of the instruction , ensure that the length should never be greater than 15 bytes
  2019. if (instrData.instrSizeInByte > 15)
  2020. {
  2021. // no instr size can be greater than 15
  2022. instrData.isInvalidInstr = true;
  2023. }
  2024. return instrData;
  2025. }
  2026. #if ENABLE_FAST_ARRAYBUFFER
  2027. bool ResumeForOutOfBoundsArrayRefs(int exceptionCode, ExceptionFilterHelper& helper)
  2028. {
  2029. if (exceptionCode != STATUS_ACCESS_VIOLATION)
  2030. {
  2031. return false;
  2032. }
  2033. Js::ScriptFunction* func = helper.GetScriptFunction();
  2034. if (!func)
  2035. {
  2036. return false;
  2037. }
  2038. bool isAsmJs = AsmJsScriptFunction::Is(func);
  2039. bool isWasmOnly = WasmScriptFunction::Is(func);
  2040. uintptr_t faultingAddr = helper.GetFaultingAddress();
  2041. if (isAsmJs)
  2042. {
  2043. AsmJsScriptFunction* asmFunc = AsmJsScriptFunction::FromVar(func);
  2044. // some extra checks for asm.js because we have slightly more information that we can validate
  2045. if (!asmFunc->GetModuleEnvironment())
  2046. {
  2047. return false;
  2048. }
  2049. ArrayBufferBase* arrayBuffer = nullptr;
  2050. size_t reservationSize = 0;
  2051. #ifdef ENABLE_WASM
  2052. if (isWasmOnly)
  2053. {
  2054. WebAssemblyMemory* mem = WasmScriptFunction::FromVar(func)->GetWebAssemblyMemory();
  2055. arrayBuffer = mem->GetBuffer();
  2056. reservationSize = MAX_WASM__ARRAYBUFFER_LENGTH;
  2057. }
  2058. else
  2059. #endif
  2060. {
  2061. arrayBuffer = asmFunc->GetAsmJsArrayBuffer();
  2062. reservationSize = MAX_ASMJS_ARRAYBUFFER_LENGTH;
  2063. }
  2064. if (!arrayBuffer || !arrayBuffer->GetBuffer())
  2065. {
  2066. // don't have a heap buffer for asm.js... so this shouldn't be an asm.js heap access
  2067. return false;
  2068. }
  2069. uintptr_t bufferAddr = (uintptr_t)arrayBuffer->GetBuffer();
  2070. uint bufferLength = arrayBuffer->GetByteLength();
  2071. if (!isWasmOnly && !((ArrayBuffer*)arrayBuffer)->IsValidAsmJsBufferLength(bufferLength))
  2072. {
  2073. return false;
  2074. }
  2075. if (faultingAddr < bufferAddr)
  2076. {
  2077. return false;
  2078. }
  2079. if (faultingAddr >= bufferAddr + reservationSize)
  2080. {
  2081. return false;
  2082. }
  2083. if (isWasmOnly)
  2084. {
  2085. // It is possible to have an A/V on other instructions then load/store (ie: xchg for atomics)
  2086. // Which we don't decode at this time
  2087. // We've confirmed the A/V occurred in the Virtual Memory, so just throw now
  2088. JavascriptError::ThrowWebAssemblyRuntimeError(func->GetScriptContext(), WASMERR_ArrayIndexOutOfRange);
  2089. }
  2090. }
  2091. else
  2092. {
  2093. MEMORY_BASIC_INFORMATION info = { 0 };
  2094. size_t size = VirtualQuery((LPCVOID)faultingAddr, &info, sizeof(info));
  2095. if (size == 0)
  2096. {
  2097. return false;
  2098. }
  2099. size_t allocationSize = info.RegionSize + ((uintptr_t)info.BaseAddress - (uintptr_t)info.AllocationBase);
  2100. if (allocationSize != MAX_WASM__ARRAYBUFFER_LENGTH && allocationSize != MAX_ASMJS_ARRAYBUFFER_LENGTH)
  2101. {
  2102. return false;
  2103. }
  2104. if (info.State != MEM_RESERVE)
  2105. {
  2106. return false;
  2107. }
  2108. if (info.Type != MEM_PRIVATE)
  2109. {
  2110. return false;
  2111. }
  2112. }
  2113. PEXCEPTION_POINTERS exceptionInfo = helper.GetExceptionInfo();
  2114. BYTE* pc = (BYTE*)exceptionInfo->ExceptionRecord->ExceptionAddress;
  2115. ArrayAccessDecoder::InstructionData instrData = ArrayAccessDecoder::CheckValidInstr(pc, exceptionInfo);
  2116. // Check If the instruction is valid
  2117. if (instrData.isInvalidInstr)
  2118. {
  2119. return false;
  2120. }
  2121. // If we didn't find the array buffer, ignore
  2122. if (!instrData.bufferValue)
  2123. {
  2124. return false;
  2125. }
  2126. // SIMD loads/stores do bounds checks.
  2127. if (instrData.isSimd)
  2128. {
  2129. return false;
  2130. }
  2131. // Set the dst reg if the instr type is load
  2132. if (instrData.isLoad)
  2133. {
  2134. Var exceptionInfoReg = exceptionInfo->ContextRecord;
  2135. Var* exceptionInfoIntReg = (Var*)((uint64)exceptionInfoReg + offsetof(CONTEXT, Rax)); // offset in the contextRecord for RAX , the assert below checks for any change in the exceptionInfo struct
  2136. Var* exceptionInfoFloatReg = (Var*)((uint64)exceptionInfoReg + offsetof(CONTEXT, Xmm0));// offset in the contextRecord for XMM0 , the assert below checks for any change in the exceptionInfo struct
  2137. Assert((DWORD64)*exceptionInfoIntReg == exceptionInfo->ContextRecord->Rax);
  2138. Assert((uint64)*exceptionInfoFloatReg == exceptionInfo->ContextRecord->Xmm0.Low);
  2139. if (instrData.isLoad)
  2140. {
  2141. double nanVal = JavascriptNumber::NaN;
  2142. if (instrData.isFloat64)
  2143. {
  2144. double* destRegLocation = (double*)((uint64)exceptionInfoFloatReg + 16 * (instrData.dstReg));
  2145. *destRegLocation = nanVal;
  2146. }
  2147. else if (instrData.isFloat32)
  2148. {
  2149. float* destRegLocation = (float*)((uint64)exceptionInfoFloatReg + 16 * (instrData.dstReg));
  2150. *destRegLocation = (float)nanVal;
  2151. }
  2152. else
  2153. {
  2154. uint64* destRegLocation = (uint64*)((uint64)exceptionInfoIntReg + 8 * (instrData.dstReg));
  2155. *destRegLocation = 0;
  2156. }
  2157. }
  2158. }
  2159. // Add the bytes read to Rip and set it as new Rip
  2160. exceptionInfo->ContextRecord->Rip = exceptionInfo->ContextRecord->Rip + instrData.instrSizeInByte;
  2161. return true;
  2162. }
  2163. #endif
  2164. #endif
  2165. #endif
  2166. #endif
  2167. int JavascriptFunction::CallRootEventFilter(int exceptionCode, PEXCEPTION_POINTERS exceptionInfo)
  2168. {
  2169. #if ENABLE_NATIVE_CODEGEN
  2170. #if defined(_M_IX86) || defined(_M_X64)
  2171. ExceptionFilterHelper helper(exceptionInfo);
  2172. CheckWasmMathException(exceptionCode, helper);
  2173. #if ENABLE_FAST_ARRAYBUFFER
  2174. if (ResumeForOutOfBoundsArrayRefs(exceptionCode, helper))
  2175. {
  2176. return EXCEPTION_CONTINUE_EXECUTION;
  2177. }
  2178. #endif
  2179. #endif
  2180. #endif
  2181. return EXCEPTION_CONTINUE_SEARCH;
  2182. }
  2183. #if DBG
  2184. void JavascriptFunction::VerifyEntryPoint()
  2185. {
  2186. JavascriptMethod callEntryPoint = this->GetType()->GetEntryPoint();
  2187. if (this->IsCrossSiteObject())
  2188. {
  2189. Assert(CrossSite::IsThunk(callEntryPoint));
  2190. }
  2191. else if (ScriptFunction::Is(this))
  2192. {
  2193. }
  2194. else
  2195. {
  2196. JavascriptMethod originalEntryPoint = this->GetFunctionInfo()->GetOriginalEntryPoint();
  2197. Assert(callEntryPoint == originalEntryPoint || callEntryPoint == ProfileEntryThunk
  2198. || (this->GetScriptContext()->GetHostScriptContext()
  2199. && this->GetScriptContext()->GetHostScriptContext()->IsHostCrossSiteThunk(callEntryPoint))
  2200. );
  2201. }
  2202. }
  2203. #endif
  2204. /*static*/
  2205. PropertyId const JavascriptFunction::specialPropertyIds[] =
  2206. {
  2207. PropertyIds::caller,
  2208. PropertyIds::arguments
  2209. };
  2210. bool JavascriptFunction::HasRestrictedProperties() const
  2211. {
  2212. return !(
  2213. this->functionInfo->IsClassMethod() ||
  2214. this->functionInfo->IsClassConstructor() ||
  2215. this->functionInfo->IsMethod() ||
  2216. this->functionInfo->IsLambda() ||
  2217. this->functionInfo->IsAsync() ||
  2218. this->IsGeneratorFunction() ||
  2219. this->IsStrictMode() ||
  2220. !this->IsScriptFunction() || // -> (BoundFunction || RuntimeFunction) // (RuntimeFunction = Native-defined built-in library functions)
  2221. this->IsLibraryCode() || // JS-defined built-in library functions
  2222. this == this->GetLibrary()->GetFunctionPrototype() // the intrinsic %FunctionPrototype% (original value of Function.prototype)
  2223. );
  2224. }
  2225. PropertyQueryFlags JavascriptFunction::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
  2226. {
  2227. switch (propertyId)
  2228. {
  2229. case PropertyIds::caller:
  2230. case PropertyIds::arguments:
  2231. if (this->HasRestrictedProperties())
  2232. {
  2233. return PropertyQueryFlags::Property_Found;
  2234. }
  2235. break;
  2236. case PropertyIds::length:
  2237. if (this->IsScriptFunction())
  2238. {
  2239. return PropertyQueryFlags::Property_Found;
  2240. }
  2241. break;
  2242. }
  2243. return DynamicObject::HasPropertyQuery(propertyId, info);
  2244. }
  2245. _Check_return_ _Success_(return) BOOL JavascriptFunction::GetAccessors(PropertyId propertyId, _Outptr_result_maybenull_ Var* getter, _Outptr_result_maybenull_ Var* setter, ScriptContext* requestContext)
  2246. {
  2247. Assert(!this->IsBoundFunction());
  2248. Assert(propertyId != Constants::NoProperty);
  2249. Assert(getter);
  2250. Assert(setter);
  2251. Assert(requestContext);
  2252. if (this->HasRestrictedProperties())
  2253. {
  2254. switch (propertyId)
  2255. {
  2256. case PropertyIds::caller:
  2257. case PropertyIds::arguments:
  2258. if (this->GetEntryPoint() == JavascriptFunction::PrototypeEntryPoint)
  2259. {
  2260. *setter = *getter = requestContext->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction();
  2261. return true;
  2262. }
  2263. break;
  2264. }
  2265. }
  2266. return __super::GetAccessors(propertyId, getter, setter, requestContext);
  2267. }
  2268. DescriptorFlags JavascriptFunction::GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  2269. {
  2270. DescriptorFlags flags;
  2271. if (GetSetterBuiltIns(propertyId, setterValue, info, requestContext, &flags))
  2272. {
  2273. return flags;
  2274. }
  2275. return __super::GetSetter(propertyId, setterValue, info, requestContext);
  2276. }
  2277. DescriptorFlags JavascriptFunction::GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  2278. {
  2279. DescriptorFlags flags;
  2280. PropertyRecord const* propertyRecord;
  2281. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  2282. if (propertyRecord != nullptr && GetSetterBuiltIns(propertyRecord->GetPropertyId(), setterValue, info, requestContext, &flags))
  2283. {
  2284. return flags;
  2285. }
  2286. return __super::GetSetter(propertyNameString, setterValue, info, requestContext);
  2287. }
  2288. bool JavascriptFunction::GetSetterBuiltIns(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext, DescriptorFlags* descriptorFlags)
  2289. {
  2290. Assert(propertyId != Constants::NoProperty);
  2291. Assert(setterValue);
  2292. Assert(requestContext);
  2293. switch (propertyId)
  2294. {
  2295. case PropertyIds::caller:
  2296. case PropertyIds::arguments:
  2297. if (this->HasRestrictedProperties()) {
  2298. PropertyValueInfo::SetNoCache(info, this);
  2299. if (this->GetEntryPoint() == JavascriptFunction::PrototypeEntryPoint)
  2300. {
  2301. *setterValue = requestContext->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction();
  2302. *descriptorFlags = Accessor;
  2303. }
  2304. else
  2305. {
  2306. *descriptorFlags = Data;
  2307. }
  2308. return true;
  2309. }
  2310. break;
  2311. }
  2312. return false;
  2313. }
  2314. BOOL JavascriptFunction::IsConfigurable(PropertyId propertyId)
  2315. {
  2316. if (DynamicObject::GetPropertyIndex(propertyId) == Constants::NoSlot)
  2317. {
  2318. switch (propertyId)
  2319. {
  2320. case PropertyIds::caller:
  2321. case PropertyIds::arguments:
  2322. if (this->HasRestrictedProperties())
  2323. {
  2324. return false;
  2325. }
  2326. break;
  2327. case PropertyIds::length:
  2328. if (this->IsScriptFunction() || this->IsBoundFunction())
  2329. {
  2330. return true;
  2331. }
  2332. break;
  2333. }
  2334. }
  2335. return DynamicObject::IsConfigurable(propertyId);
  2336. }
  2337. BOOL JavascriptFunction::IsEnumerable(PropertyId propertyId)
  2338. {
  2339. if (DynamicObject::GetPropertyIndex(propertyId) == Constants::NoSlot)
  2340. {
  2341. switch (propertyId)
  2342. {
  2343. case PropertyIds::caller:
  2344. case PropertyIds::arguments:
  2345. if (this->HasRestrictedProperties())
  2346. {
  2347. return false;
  2348. }
  2349. break;
  2350. case PropertyIds::length:
  2351. if (this->IsScriptFunction())
  2352. {
  2353. return false;
  2354. }
  2355. break;
  2356. }
  2357. }
  2358. return DynamicObject::IsEnumerable(propertyId);
  2359. }
  2360. BOOL JavascriptFunction::IsWritable(PropertyId propertyId)
  2361. {
  2362. if (DynamicObject::GetPropertyIndex(propertyId) == Constants::NoSlot)
  2363. {
  2364. switch (propertyId)
  2365. {
  2366. case PropertyIds::caller:
  2367. case PropertyIds::arguments:
  2368. if (this->HasRestrictedProperties())
  2369. {
  2370. return false;
  2371. }
  2372. break;
  2373. case PropertyIds::length:
  2374. if (this->IsScriptFunction())
  2375. {
  2376. return false;
  2377. }
  2378. break;
  2379. }
  2380. }
  2381. return DynamicObject::IsWritable(propertyId);
  2382. }
  2383. BOOL JavascriptFunction::GetSpecialPropertyName(uint32 index, JavascriptString ** propertyName, ScriptContext * requestContext)
  2384. {
  2385. uint length = GetSpecialPropertyCount();
  2386. if (index < length)
  2387. {
  2388. Assert(DynamicObject::GetPropertyIndex(specialPropertyIds[index]) == Constants::NoSlot);
  2389. *propertyName = requestContext->GetPropertyString(specialPropertyIds[index]);
  2390. return true;
  2391. }
  2392. if (index == length)
  2393. {
  2394. if (this->IsScriptFunction() || this->IsBoundFunction())
  2395. {
  2396. if (DynamicObject::GetPropertyIndex(PropertyIds::length) == Constants::NoSlot)
  2397. {
  2398. //Only for user defined functions length is a special property.
  2399. *propertyName = requestContext->GetPropertyString(PropertyIds::length);
  2400. return true;
  2401. }
  2402. }
  2403. }
  2404. return false;
  2405. }
  2406. // Returns the number of special non-enumerable properties this type has.
  2407. uint JavascriptFunction::GetSpecialPropertyCount() const
  2408. {
  2409. return this->HasRestrictedProperties() ? _countof(specialPropertyIds) : 0;
  2410. }
  2411. // Returns the list of special non-enumerable properties for the type.
  2412. PropertyId const * JavascriptFunction::GetSpecialPropertyIds() const
  2413. {
  2414. return specialPropertyIds;
  2415. }
  2416. PropertyQueryFlags JavascriptFunction::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  2417. {
  2418. return JavascriptFunction::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
  2419. }
  2420. JavascriptFunction* JavascriptFunction::FindCaller(BOOL* foundThis, JavascriptFunction* nullValue, ScriptContext* requestContext)
  2421. {
  2422. ScriptContext* scriptContext = this->GetScriptContext();
  2423. JavascriptFunction* funcCaller = nullValue;
  2424. JavascriptStackWalker walker(scriptContext);
  2425. if (walker.WalkToTarget(this))
  2426. {
  2427. *foundThis = TRUE;
  2428. while (walker.GetCaller(&funcCaller))
  2429. {
  2430. if (walker.IsCallerGlobalFunction())
  2431. {
  2432. // Caller is global/eval. If it's eval, keep looking.
  2433. // Otherwise, return null.
  2434. if (walker.IsEvalCaller())
  2435. {
  2436. continue;
  2437. }
  2438. funcCaller = nullValue;
  2439. }
  2440. break;
  2441. }
  2442. if (funcCaller == nullptr)
  2443. {
  2444. // We no longer return Null objects as JavascriptFunctions, so we don't have to worry about
  2445. // cross-context null objects. We do want to clean up null pointers though, since some call
  2446. // later in this function may depend on non-nullptr calls.
  2447. funcCaller = nullValue;
  2448. }
  2449. if (ScriptFunction::Is(funcCaller))
  2450. {
  2451. // If this is the internal function of a generator function then return the original generator function
  2452. funcCaller = ScriptFunction::FromVar(funcCaller)->GetRealFunctionObject();
  2453. // This function is escaping, so make sure there isn't some nested parent that has a cached scope.
  2454. if (ScriptFunction::Is(funcCaller))
  2455. {
  2456. FrameDisplay * pFrameDisplay = Js::ScriptFunction::FromVar(funcCaller)->GetEnvironment();
  2457. uint length = (uint)pFrameDisplay->GetLength();
  2458. for (uint i = 0; i < length; i++)
  2459. {
  2460. Var scope = pFrameDisplay->GetItem(i);
  2461. if (scope && !Js::ScopeSlots::Is(scope) && Js::ActivationObjectEx::Is(scope))
  2462. {
  2463. Js::ActivationObjectEx::FromVar(scope)->InvalidateCachedScope();
  2464. }
  2465. }
  2466. }
  2467. }
  2468. }
  2469. return StackScriptFunction::EnsureBoxed(BOX_PARAM(funcCaller, nullptr, _u("caller")));
  2470. }
  2471. BOOL JavascriptFunction::GetCallerProperty(Var originalInstance, Var* value, ScriptContext* requestContext)
  2472. {
  2473. ScriptContext* scriptContext = this->GetScriptContext();
  2474. *value = nullptr;
  2475. if (this->IsStrictMode())
  2476. {
  2477. return false;
  2478. }
  2479. if (this->GetEntryPoint() == JavascriptFunction::PrototypeEntryPoint)
  2480. {
  2481. if (scriptContext->GetThreadContext()->RecordImplicitException())
  2482. {
  2483. JavascriptFunction* accessor = requestContext->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction();
  2484. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  2485. {
  2486. *value = CALL_FUNCTION(scriptContext->GetThreadContext(), accessor, CallInfo(1), originalInstance);
  2487. }
  2488. END_SAFE_REENTRANT_CALL
  2489. }
  2490. return true;
  2491. }
  2492. JavascriptFunction* nullValue = (JavascriptFunction*)requestContext->GetLibrary()->GetNull();
  2493. if (this->IsLibraryCode()) // Hide .caller for builtins
  2494. {
  2495. *value = nullValue;
  2496. return true;
  2497. }
  2498. // Use a stack walker to find this function's frame. If we find it, find its caller.
  2499. BOOL foundThis = FALSE;
  2500. JavascriptFunction* funcCaller = FindCaller(&foundThis, nullValue, requestContext);
  2501. // WOOB #1142373. We are trying to get the caller in window.onerror = function(){alert(arguments.callee.caller);} case
  2502. // window.onerror is called outside of JavascriptFunction::CallFunction loop, so the caller information is not available
  2503. // in the stack to be found by the stack walker.
  2504. // As we had already walked the stack at throw time retrieve the caller information stored in the exception object
  2505. // The down side is that we can only find the top level caller at thrown time, and won't be able to find caller.caller etc.
  2506. // We'll try to fetch the caller only if we can find the function on the stack, but we can't find the caller if and we are in
  2507. // window.onerror scenario.
  2508. *value = funcCaller;
  2509. if (foundThis && funcCaller == nullValue && scriptContext->GetThreadContext()->HasUnhandledException())
  2510. {
  2511. Js::JavascriptExceptionObject* unhandledExceptionObject = scriptContext->GetThreadContext()->GetUnhandledExceptionObject();
  2512. if (unhandledExceptionObject)
  2513. {
  2514. JavascriptFunction* exceptionFunction = unhandledExceptionObject->GetFunction();
  2515. // This is for getcaller in window.onError. The behavior is different in different browsers
  2516. if (exceptionFunction
  2517. && scriptContext == exceptionFunction->GetScriptContext()
  2518. && exceptionFunction->IsScriptFunction()
  2519. && !exceptionFunction->GetFunctionBody()->GetIsGlobalFunc())
  2520. {
  2521. *value = exceptionFunction;
  2522. }
  2523. }
  2524. }
  2525. else if (foundThis && scriptContext != funcCaller->GetScriptContext())
  2526. {
  2527. HRESULT hr = scriptContext->GetHostScriptContext()->CheckCrossDomainScriptContext(funcCaller->GetScriptContext());
  2528. if (S_OK != hr)
  2529. {
  2530. *value = nullValue;
  2531. }
  2532. else
  2533. {
  2534. *value = CrossSite::MarshalVar(requestContext, funcCaller, funcCaller->GetScriptContext());
  2535. }
  2536. }
  2537. if (Js::JavascriptFunction::Is(*value) && Js::JavascriptFunction::FromVar(*value)->IsStrictMode())
  2538. {
  2539. if (scriptContext->GetThreadContext()->RecordImplicitException())
  2540. {
  2541. // ES5.15.3.5.4 [[Get]] (P) -- access to the 'caller' property of strict mode function results in TypeError.
  2542. // Note that for caller coming from remote context (see the check right above) we can't call IsStrictMode()
  2543. // unless CheckCrossDomainScriptContext succeeds. If it fails we don't know whether caller is strict mode
  2544. // function or not and throw if it's not, so just return Null.
  2545. JavascriptError::ThrowTypeError(scriptContext, JSERR_AccessRestrictedProperty);
  2546. }
  2547. }
  2548. return true;
  2549. }
  2550. BOOL JavascriptFunction::GetArgumentsProperty(Var originalInstance, Var* value, ScriptContext* requestContext)
  2551. {
  2552. ScriptContext* scriptContext = this->GetScriptContext();
  2553. if (this->IsStrictMode())
  2554. {
  2555. return false;
  2556. }
  2557. if (this->GetEntryPoint() == JavascriptFunction::PrototypeEntryPoint)
  2558. {
  2559. if (scriptContext->GetThreadContext()->RecordImplicitException())
  2560. {
  2561. JavascriptFunction* accessor = requestContext->GetLibrary()->GetThrowTypeErrorRestrictedPropertyAccessorFunction();
  2562. BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
  2563. {
  2564. *value = CALL_FUNCTION(scriptContext->GetThreadContext(), accessor, CallInfo(1), originalInstance);
  2565. }
  2566. END_SAFE_REENTRANT_CALL
  2567. }
  2568. return true;
  2569. }
  2570. if (!this->IsScriptFunction())
  2571. {
  2572. // builtin function do not have an argument object - return null.
  2573. *value = scriptContext->GetLibrary()->GetNull();
  2574. return true;
  2575. }
  2576. // Use a stack walker to find this function's frame. If we find it, compute its arguments.
  2577. // Note that we are currently unable to guarantee that the binding between formal arguments
  2578. // and foo.arguments[n] will be maintained after this object is returned.
  2579. JavascriptStackWalker walker(scriptContext);
  2580. if (walker.WalkToTarget(this))
  2581. {
  2582. if (walker.IsCallerGlobalFunction())
  2583. {
  2584. *value = requestContext->GetLibrary()->GetNull();
  2585. }
  2586. else
  2587. {
  2588. Var args = nullptr;
  2589. // Since the arguments will be returned back to script, box the arguments to ensure a copy of
  2590. // them with their own lifetime (as well as move any from the stack to the heap).
  2591. const CallInfo callInfo = walker.GetCallInfo();
  2592. args = JavascriptOperators::LoadHeapArguments(
  2593. this, callInfo.Count - 1,
  2594. walker.GetJavascriptArgs(true /* boxArgsAndDeepCopy */),
  2595. scriptContext->GetLibrary()->GetNull(),
  2596. scriptContext->GetLibrary()->GetNull(),
  2597. scriptContext,
  2598. /* formalsAreLetDecls */ false);
  2599. *value = args;
  2600. }
  2601. }
  2602. else
  2603. {
  2604. *value = scriptContext->GetLibrary()->GetNull();
  2605. }
  2606. return true;
  2607. }
  2608. PropertyQueryFlags JavascriptFunction::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  2609. {
  2610. BOOL result = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext)) ? TRUE : FALSE;
  2611. if (result)
  2612. {
  2613. if (propertyId == PropertyIds::prototype)
  2614. {
  2615. PropertyValueInfo::DisableStoreFieldCache(info);
  2616. }
  2617. }
  2618. else
  2619. {
  2620. GetPropertyBuiltIns(originalInstance, propertyId, value, requestContext, &result);
  2621. }
  2622. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  2623. }
  2624. PropertyQueryFlags JavascriptFunction::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  2625. {
  2626. BOOL result;
  2627. PropertyRecord const* propertyRecord = nullptr;
  2628. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  2629. result = JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext)) ? TRUE : FALSE;
  2630. if (result)
  2631. {
  2632. if (propertyRecord != nullptr && propertyRecord->GetPropertyId() == PropertyIds::prototype)
  2633. {
  2634. PropertyValueInfo::DisableStoreFieldCache(info);
  2635. }
  2636. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  2637. }
  2638. if (propertyRecord != nullptr)
  2639. {
  2640. GetPropertyBuiltIns(originalInstance, propertyRecord->GetPropertyId(), value, requestContext, &result);
  2641. }
  2642. return JavascriptConversion::BooleanToPropertyQueryFlags(result);
  2643. }
  2644. bool JavascriptFunction::GetPropertyBuiltIns(Var originalInstance, PropertyId propertyId, Var* value, ScriptContext* requestContext, BOOL* result)
  2645. {
  2646. if (propertyId == PropertyIds::caller && this->HasRestrictedProperties())
  2647. {
  2648. *result = GetCallerProperty(originalInstance, value, requestContext);
  2649. return true;
  2650. }
  2651. if (propertyId == PropertyIds::arguments && this->HasRestrictedProperties())
  2652. {
  2653. *result = GetArgumentsProperty(originalInstance, value, requestContext);
  2654. return true;
  2655. }
  2656. if (propertyId == PropertyIds::length)
  2657. {
  2658. FunctionProxy *proxy = this->GetFunctionProxy();
  2659. if (proxy)
  2660. {
  2661. *value = TaggedInt::ToVarUnchecked(proxy->EnsureDeserialized()->GetReportedInParamsCount() - 1);
  2662. *result = true;
  2663. return true;
  2664. }
  2665. }
  2666. *result = false;
  2667. return false;
  2668. }
  2669. BOOL JavascriptFunction::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  2670. {
  2671. bool isReadOnly = false;
  2672. switch (propertyId)
  2673. {
  2674. case PropertyIds::caller:
  2675. if (this->HasRestrictedProperties())
  2676. {
  2677. isReadOnly = true;
  2678. }
  2679. break;
  2680. case PropertyIds::arguments:
  2681. if (this->HasRestrictedProperties())
  2682. {
  2683. isReadOnly = true;
  2684. }
  2685. break;
  2686. case PropertyIds::length:
  2687. if (this->IsScriptFunction())
  2688. {
  2689. isReadOnly = true;
  2690. }
  2691. break;
  2692. }
  2693. if (isReadOnly)
  2694. {
  2695. JavascriptError::ThrowCantAssignIfStrictMode(flags, this->GetScriptContext());
  2696. return false;
  2697. }
  2698. BOOL result = DynamicObject::SetProperty(propertyId, value, flags, info);
  2699. if (propertyId == PropertyIds::prototype || propertyId == PropertyIds::_symbolHasInstance)
  2700. {
  2701. PropertyValueInfo::SetNoCache(info, this);
  2702. InvalidateConstructorCacheOnPrototypeChange();
  2703. this->GetScriptContext()->GetThreadContext()->InvalidateIsInstInlineCachesForFunction(this);
  2704. }
  2705. return result;
  2706. }
  2707. BOOL JavascriptFunction::SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects)
  2708. {
  2709. BOOL result = __super::SetPropertyWithAttributes(propertyId, value, attributes, info, flags, possibleSideEffects);
  2710. if (propertyId == PropertyIds::prototype || propertyId == PropertyIds::_symbolHasInstance)
  2711. {
  2712. PropertyValueInfo::SetNoCache(info, this);
  2713. InvalidateConstructorCacheOnPrototypeChange();
  2714. this->GetScriptContext()->GetThreadContext()->InvalidateIsInstInlineCachesForFunction(this);
  2715. }
  2716. return result;
  2717. }
  2718. BOOL JavascriptFunction::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  2719. {
  2720. PropertyRecord const * propertyRecord;
  2721. this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
  2722. if (propertyRecord != nullptr)
  2723. {
  2724. return JavascriptFunction::SetProperty(propertyRecord->GetPropertyId(), value, flags, info);
  2725. }
  2726. else
  2727. {
  2728. return DynamicObject::SetProperty(propertyNameString, value, flags, info);
  2729. }
  2730. }
  2731. BOOL JavascriptFunction::DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags)
  2732. {
  2733. switch (propertyId)
  2734. {
  2735. case PropertyIds::caller:
  2736. case PropertyIds::arguments:
  2737. if (this->HasRestrictedProperties())
  2738. {
  2739. JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), this->GetScriptContext()->GetPropertyName(propertyId)->GetBuffer());
  2740. return false;
  2741. }
  2742. break;
  2743. case PropertyIds::length:
  2744. if (this->IsScriptFunction())
  2745. {
  2746. JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), this->GetScriptContext()->GetPropertyName(propertyId)->GetBuffer());
  2747. return false;
  2748. }
  2749. break;
  2750. }
  2751. BOOL result = DynamicObject::DeleteProperty(propertyId, flags);
  2752. if (result && (propertyId == PropertyIds::prototype || propertyId == PropertyIds::_symbolHasInstance))
  2753. {
  2754. InvalidateConstructorCacheOnPrototypeChange();
  2755. this->GetScriptContext()->GetThreadContext()->InvalidateIsInstInlineCachesForFunction(this);
  2756. if (propertyId == PropertyIds::prototype)
  2757. {
  2758. this->GetTypeHandler()->ClearHasKnownSlot0();
  2759. }
  2760. }
  2761. return result;
  2762. }
  2763. BOOL JavascriptFunction::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
  2764. {
  2765. if (BuiltInPropertyRecords::caller.Equals(propertyNameString) || BuiltInPropertyRecords::arguments.Equals(propertyNameString))
  2766. {
  2767. if (this->HasRestrictedProperties())
  2768. {
  2769. JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), propertyNameString->GetString());
  2770. return false;
  2771. }
  2772. }
  2773. else if (BuiltInPropertyRecords::length.Equals(propertyNameString))
  2774. {
  2775. if (this->IsScriptFunction())
  2776. {
  2777. JavascriptError::ThrowCantDeleteIfStrictMode(flags, this->GetScriptContext(), propertyNameString->GetString());
  2778. return false;
  2779. }
  2780. }
  2781. BOOL result = DynamicObject::DeleteProperty(propertyNameString, flags);
  2782. if (result && (BuiltInPropertyRecords::prototype.Equals(propertyNameString) || BuiltInPropertyRecords::_symbolHasInstance.Equals(propertyNameString)))
  2783. {
  2784. InvalidateConstructorCacheOnPrototypeChange();
  2785. this->GetScriptContext()->GetThreadContext()->InvalidateIsInstInlineCachesForFunction(this);
  2786. if (BuiltInPropertyRecords::prototype.Equals(propertyNameString))
  2787. {
  2788. this->GetTypeHandler()->ClearHasKnownSlot0();
  2789. }
  2790. }
  2791. return result;
  2792. }
  2793. void JavascriptFunction::InvalidateConstructorCacheOnPrototypeChange()
  2794. {
  2795. Assert(this->constructorCache != nullptr);
  2796. #if DBG_DUMP
  2797. if (PHASE_TRACE1(Js::ConstructorCachePhase))
  2798. {
  2799. // This is under DBG_DUMP so we can allow a check
  2800. ParseableFunctionInfo* body = this->GetFunctionProxy() != nullptr ? this->GetFunctionProxy()->EnsureDeserialized() : nullptr;
  2801. const char16* ctorName = body != nullptr ? body->GetDisplayName() : _u("<unknown>");
  2802. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  2803. Output::Print(_u("CtorCache: before invalidating cache (0x%p) for ctor %s (%s): "), PointerValue(this->constructorCache), ctorName,
  2804. body ? body->GetDebugNumberSet(debugStringBuffer) : _u("(null)"));
  2805. this->constructorCache->Dump();
  2806. Output::Print(_u("\n"));
  2807. Output::Flush();
  2808. }
  2809. #endif
  2810. this->constructorCache->InvalidateOnPrototypeChange();
  2811. #if DBG_DUMP
  2812. if (PHASE_TRACE1(Js::ConstructorCachePhase))
  2813. {
  2814. // This is under DBG_DUMP so we can allow a check
  2815. ParseableFunctionInfo* body = this->GetFunctionProxy() != nullptr ? this->GetFunctionProxy()->EnsureDeserialized() : nullptr;
  2816. const char16* ctorName = body != nullptr ? body->GetDisplayName() : _u("<unknown>");
  2817. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  2818. Output::Print(_u("CtorCache: after invalidating cache (0x%p) for ctor %s (%s): "), PointerValue(this->constructorCache), ctorName,
  2819. body ? body->GetDebugNumberSet(debugStringBuffer) : _u("(null)"));
  2820. this->constructorCache->Dump();
  2821. Output::Print(_u("\n"));
  2822. Output::Flush();
  2823. }
  2824. #endif
  2825. }
  2826. BOOL JavascriptFunction::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  2827. {
  2828. JavascriptString * pString = NULL;
  2829. Var sourceString = this->GetSourceString();
  2830. if (sourceString == nullptr)
  2831. {
  2832. FunctionProxy* proxy = this->GetFunctionProxy();
  2833. if (proxy)
  2834. {
  2835. ParseableFunctionInfo * func = proxy->EnsureDeserialized();
  2836. Utf8SourceInfo* sourceInfo = func->GetUtf8SourceInfo();
  2837. if (sourceInfo->GetIsLibraryCode())
  2838. {
  2839. charcount_t displayNameLength = 0;
  2840. pString = JavascriptFunction::GetLibraryCodeDisplayString(this->GetScriptContext(), func->GetShortDisplayName(&displayNameLength));
  2841. }
  2842. else
  2843. {
  2844. charcount_t count = min(DIAG_MAX_FUNCTION_STRING, func->LengthInChars());
  2845. utf8::DecodeOptions options = sourceInfo->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
  2846. LPCUTF8 source = func->GetSource(_u("JavascriptFunction::GetDiagValueString"));
  2847. size_t cbLength = sourceInfo->GetCbLength(_u("JavascriptFunction::GetDiagValueString"));
  2848. size_t cbIndex = utf8::CharacterIndexToByteIndex(source, cbLength, count, options);
  2849. utf8::DecodeUnitsInto(stringBuilder->AllocBufferSpace(count), source, source + cbIndex, options);
  2850. stringBuilder->IncreaseCount(count);
  2851. return TRUE;
  2852. }
  2853. }
  2854. else
  2855. {
  2856. pString = GetLibrary()->GetFunctionDisplayString();
  2857. }
  2858. }
  2859. else
  2860. {
  2861. if (TaggedInt::Is(sourceString))
  2862. {
  2863. pString = GetNativeFunctionDisplayString(this->GetScriptContext(), this->GetScriptContext()->GetPropertyString(TaggedInt::ToInt32(sourceString)));
  2864. }
  2865. else
  2866. {
  2867. Assert(JavascriptString::Is(sourceString));
  2868. pString = JavascriptString::FromVar(sourceString);
  2869. }
  2870. }
  2871. Assert(pString);
  2872. stringBuilder->Append(pString->GetString(), pString->GetLength());
  2873. return TRUE;
  2874. }
  2875. BOOL JavascriptFunction::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  2876. {
  2877. stringBuilder->AppendCppLiteral(_u("Object, (Function)"));
  2878. return TRUE;
  2879. }
  2880. JavascriptString* JavascriptFunction::GetDisplayNameImpl() const
  2881. {
  2882. Assert(this->GetFunctionProxy() != nullptr); // The caller should guarantee a proxy exists
  2883. ParseableFunctionInfo * func = this->GetFunctionProxy()->EnsureDeserialized();
  2884. charcount_t length = 0;
  2885. const char16* name = func->GetShortDisplayName(&length);
  2886. return DisplayNameHelper(name, length);
  2887. }
  2888. JavascriptString* JavascriptFunction::DisplayNameHelper(const char16* name, charcount_t length) const
  2889. {
  2890. ScriptContext* scriptContext = this->GetScriptContext();
  2891. Assert(this->GetFunctionProxy() != nullptr); // The caller should guarantee a proxy exists
  2892. ParseableFunctionInfo * func = this->GetFunctionProxy()->EnsureDeserialized();
  2893. if (func->GetDisplayName() == Js::Constants::FunctionCode)
  2894. {
  2895. return LiteralString::NewCopyBuffer(Js::Constants::Anonymous, Js::Constants::AnonymousLength, scriptContext);
  2896. }
  2897. else if (func->GetIsAccessor())
  2898. {
  2899. const char16* accessorName = func->GetDisplayName();
  2900. if (accessorName[0] == _u('g'))
  2901. {
  2902. return LiteralString::Concat(LiteralString::NewCopySz(_u("get "), scriptContext), LiteralString::NewCopyBuffer(name, length, scriptContext));
  2903. }
  2904. AssertMsg(accessorName[0] == _u('s'), "should be a set");
  2905. return LiteralString::Concat(LiteralString::NewCopySz(_u("set "), scriptContext), LiteralString::NewCopyBuffer(name, length, scriptContext));
  2906. }
  2907. return LiteralString::NewCopyBuffer(name, length, scriptContext);
  2908. }
  2909. bool JavascriptFunction::GetFunctionName(JavascriptString** name) const
  2910. {
  2911. Assert(name != nullptr);
  2912. FunctionProxy* proxy = this->GetFunctionProxy();
  2913. JavascriptFunction* thisFunction = const_cast<JavascriptFunction*>(this);
  2914. if (proxy || thisFunction->IsBoundFunction() || JavascriptGeneratorFunction::Test(thisFunction) || JavascriptAsyncFunction::Test(thisFunction))
  2915. {
  2916. *name = GetDisplayNameImpl();
  2917. return true;
  2918. }
  2919. Assert(!ScriptFunction::Is(thisFunction));
  2920. return GetSourceStringName(name);
  2921. }
  2922. bool JavascriptFunction::GetSourceStringName(JavascriptString** name) const
  2923. {
  2924. Assert(name != nullptr);
  2925. ScriptContext* scriptContext = this->GetScriptContext();
  2926. Var sourceString = this->GetSourceString();
  2927. if (sourceString)
  2928. {
  2929. if (TaggedInt::Is(sourceString))
  2930. {
  2931. int32 propertyIdOfSourceString = TaggedInt::ToInt32(sourceString);
  2932. *name = scriptContext->GetPropertyString(propertyIdOfSourceString);
  2933. return true;
  2934. }
  2935. Assert(JavascriptString::Is(sourceString));
  2936. *name = JavascriptString::FromVar(sourceString);
  2937. return true;
  2938. }
  2939. return false;
  2940. }
  2941. JavascriptString* JavascriptFunction::GetDisplayName() const
  2942. {
  2943. ScriptContext* scriptContext = this->GetScriptContext();
  2944. FunctionProxy* proxy = this->GetFunctionProxy();
  2945. JavascriptLibrary* library = scriptContext->GetLibrary();
  2946. if (proxy)
  2947. {
  2948. ParseableFunctionInfo * func = proxy->EnsureDeserialized();
  2949. return LiteralString::NewCopySz(func->GetDisplayName(), scriptContext);
  2950. }
  2951. JavascriptString* sourceStringName = nullptr;
  2952. if (GetSourceStringName(&sourceStringName))
  2953. {
  2954. return sourceStringName;
  2955. }
  2956. return library->GetFunctionDisplayString();
  2957. }
  2958. Var JavascriptFunction::GetTypeOfString(ScriptContext * requestContext)
  2959. {
  2960. return requestContext->GetLibrary()->GetFunctionTypeDisplayString();
  2961. }
  2962. // Check if this function is native/script library code
  2963. bool JavascriptFunction::IsLibraryCode() const
  2964. {
  2965. return !this->IsScriptFunction() || this->GetFunctionProxy()->GetUtf8SourceInfo()->GetIsLibraryCode();
  2966. }
  2967. // Implementation of Function.prototype[@@hasInstance](V) as specified in 19.2.3.6 of ES6 spec
  2968. Var JavascriptFunction::EntrySymbolHasInstance(RecyclableObject* function, CallInfo callInfo, ...)
  2969. {
  2970. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  2971. ARGUMENTS(args, callInfo);
  2972. ScriptContext* scriptContext = function->GetScriptContext();
  2973. Assert(!(callInfo.Flags & CallFlags_New));
  2974. if (!JavascriptConversion::IsCallable(args[0]) || args.Info.Count < 2)
  2975. {
  2976. return JavascriptBoolean::ToVar(FALSE, scriptContext);
  2977. }
  2978. RecyclableObject * constructor = RecyclableObject::FromVar(args[0]);
  2979. Var instance = args[1];
  2980. Assert(JavascriptProxy::Is(constructor) || JavascriptFunction::Is(constructor));
  2981. return JavascriptBoolean::ToVar(constructor->HasInstance(instance, scriptContext, NULL), scriptContext);
  2982. }
  2983. BOOL JavascriptFunction::HasInstance(Var instance, ScriptContext* scriptContext, IsInstInlineCache* inlineCache)
  2984. {
  2985. Var funcPrototype;
  2986. if (this->GetTypeHandler()->GetHasKnownSlot0())
  2987. {
  2988. Assert(this->GetDynamicType()->GetTypeHandler()->GetPropertyId(scriptContext, (PropertyIndex)0) == PropertyIds::prototype);
  2989. funcPrototype = this->GetSlot(0);
  2990. }
  2991. else
  2992. {
  2993. funcPrototype = JavascriptOperators::GetPropertyNoCache(this, PropertyIds::prototype, scriptContext);
  2994. }
  2995. funcPrototype = CrossSite::MarshalVar(scriptContext, funcPrototype);
  2996. return JavascriptFunction::HasInstance(funcPrototype, instance, scriptContext, inlineCache, this);
  2997. }
  2998. BOOL JavascriptFunction::HasInstance(Var funcPrototype, Var instance, ScriptContext * scriptContext, IsInstInlineCache* inlineCache, JavascriptFunction *function)
  2999. {
  3000. BOOL result = FALSE;
  3001. JavascriptBoolean * javascriptResult;
  3002. //
  3003. // if "instance" is not a JavascriptObject, return false
  3004. //
  3005. if (!JavascriptOperators::IsObject(instance))
  3006. {
  3007. // Only update the cache for primitive cache if it is empty already for the JIT fast path
  3008. if (inlineCache && inlineCache->function == nullptr
  3009. && scriptContext == function->GetScriptContext())// only register when function has same scriptContext
  3010. {
  3011. inlineCache->Cache(RecyclableObject::Is(instance) ?
  3012. RecyclableObject::UnsafeFromVar(instance)->GetType() : nullptr,
  3013. function, scriptContext->GetLibrary()->GetFalse(), scriptContext);
  3014. }
  3015. return result;
  3016. }
  3017. // If we have an instance of inline cache, let's try to use it to speed up the operation.
  3018. // We would like to catch all cases when we already know (by having checked previously)
  3019. // that an object on the left of instance of has been created by a function on the right,
  3020. // as well as when we already know the object on the left has not been created by a function on the right.
  3021. // In practice, we can do so only if the function matches the function in the cache, and the object's type matches the
  3022. // type in the cache. Notably, this typically means that if some of the objects evolved after construction,
  3023. // while others did not, we will miss the cache for one of the two (sets of objects).
  3024. // An important subtlety here arises when a function is called from different script contexts.
  3025. // Suppose we called function foo from script context A, and we pass it an object o created in the same script context.
  3026. // When function foo checks if object o is an instance of itself (function foo) for the first time (from context A) we will
  3027. // populate the cache with function foo and object o's type (which is permanently bound to the script context A,
  3028. // in which object o was created). If we later invoked function foo from script context B and perform the same instance-of check,
  3029. // the function will still match the function in the cache (because objects' identities do not change during cross-context marshalling).
  3030. // However, object o's type (even if it is of the same "shape" as before) will be different, because the object types are permanently
  3031. // bound and unique to the script context from which they were created. Hence, the cache may miss, even if the function matches.
  3032. if (inlineCache != nullptr)
  3033. {
  3034. Assert(function != nullptr);
  3035. if (inlineCache->TryGetResult(instance, function, &javascriptResult))
  3036. {
  3037. return javascriptResult == scriptContext->GetLibrary()->GetTrue();
  3038. }
  3039. }
  3040. // If we are here, then me must have missed the cache. This may be because:
  3041. // a) the cache has never been populated in the first place,
  3042. // b) the cache has been populated, but for an object of a different type (even if the object was created by the same constructor function),
  3043. // c) the cache has been populated, but for a different function,
  3044. // d) the cache has been populated, even for the same object type and function, but has since been invalidated, because the function's
  3045. // prototype property has been changed (see JavascriptFunction::SetProperty and ThreadContext::InvalidateIsInstInlineCachesForFunction).
  3046. // We may even miss the cache if we ask again about the very same object the very same function the cache was populated with.
  3047. // This subtlety arises when a function is called from two (or more) different script contexts.
  3048. // Suppose we called function foo from script context A, and passed it an object o created in the same script context.
  3049. // When function foo checks if object o is an instance of itself (function foo) for the first time (from context A) we will
  3050. // populate the cache with function foo and object o's type (which is permanently bound to the script context A,
  3051. // in which object o was created). If we later invoked function foo from script context B and perform the same instance of check,
  3052. // the function will still match the function in the cache (because objects' identities do not change during cross-context marshalling).
  3053. // However, object o's type (even if it is of the same "shape" as before, and even if o is the very same object) will be different,
  3054. // because the object types are permanently bound and unique to the script context from which they were created.
  3055. RecyclableObject* instanceObject = RecyclableObject::FromVar(instance);
  3056. Var prototype = JavascriptOperators::GetPrototype(instanceObject);
  3057. if (!JavascriptOperators::IsObject(funcPrototype))
  3058. {
  3059. JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidPrototype);
  3060. }
  3061. // Since we missed the cache, we must now walk the prototype chain of the object to check if the given function's prototype is somewhere in
  3062. // that chain. If it is, we return true. Otherwise (i.e., we hit the end of the chain before finding the function's prototype) we return false.
  3063. while (!JavascriptOperators::IsNull(prototype))
  3064. {
  3065. if (prototype == funcPrototype)
  3066. {
  3067. result = TRUE;
  3068. break;
  3069. }
  3070. prototype = JavascriptOperators::GetPrototype(RecyclableObject::FromVar(prototype));
  3071. }
  3072. // Now that we know the answer, let's cache it for next time if we have a cache.
  3073. if (inlineCache != NULL)
  3074. {
  3075. Assert(function != NULL);
  3076. JavascriptBoolean * boolResult = result ? scriptContext->GetLibrary()->GetTrue() :
  3077. scriptContext->GetLibrary()->GetFalse();
  3078. Type * instanceType = RecyclableObject::FromVar(instance)->GetType();
  3079. if (!instanceType->HasSpecialPrototype()
  3080. && scriptContext == function->GetScriptContext()) // only register when function has same scriptContext, otherwise when scriptContext close
  3081. // and the isInst inline cache chain will be broken by clearing the arenaAllocator
  3082. {
  3083. inlineCache->Cache(instanceType, function, boolResult, scriptContext);
  3084. }
  3085. }
  3086. return result;
  3087. }
  3088. #ifdef ALLOW_JIT_REPRO
  3089. Var JavascriptFunction::EntryInvokeJit(RecyclableObject* function, CallInfo callInfo, ...)
  3090. {
  3091. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  3092. ARGUMENTS(args, callInfo);
  3093. ScriptContext* scriptContext = function->GetScriptContext();
  3094. Assert(!(callInfo.Flags & CallFlags_New));
  3095. // todo:: make it work with inproc jit
  3096. if (!JITManager::GetJITManager()->IsOOPJITEnabled())
  3097. {
  3098. Output::Print(_u("Out of proc jit is necessary to repro using an encoded buffer"));
  3099. Js::Throw::FatalInternalError();
  3100. }
  3101. if (args.Info.Count < 2 || !ArrayBufferBase::Is(args[1]))
  3102. {
  3103. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedArrayBufferObject);
  3104. }
  3105. ArrayBufferBase* arrayBuffer = ArrayBufferBase::FromVar(args[1]);
  3106. const byte* buffer = arrayBuffer->GetBuffer();
  3107. uint32 size = arrayBuffer->GetByteLength();
  3108. HRESULT hr = JitFromEncodedWorkItem(scriptContext->GetNativeCodeGenerator(), buffer, size);
  3109. if (FAILED(hr))
  3110. {
  3111. #ifdef _WIN32
  3112. char16* lpMsgBuf = nullptr;
  3113. DWORD bufLen = FormatMessageW(
  3114. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  3115. FORMAT_MESSAGE_FROM_SYSTEM |
  3116. FORMAT_MESSAGE_IGNORE_INSERTS,
  3117. NULL,
  3118. hr,
  3119. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  3120. (LPTSTR)&lpMsgBuf,
  3121. 0, NULL);
  3122. if (bufLen)
  3123. {
  3124. JavascriptString* string = JavascriptString::NewCopyBuffer(lpMsgBuf, bufLen, scriptContext);
  3125. LocalFree(lpMsgBuf);
  3126. JavascriptExceptionOperators::OP_Throw(string, scriptContext);
  3127. }
  3128. #endif
  3129. return JavascriptNumber::New(hr, scriptContext);
  3130. }
  3131. return scriptContext->GetLibrary()->GetUndefined();
  3132. }
  3133. #endif