ByteCodeGenerator.cpp 196 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260
  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 "RuntimeByteCodePch.h"
  6. #include "FormalsUtil.h"
  7. #include "Library/StackScriptFunction.h"
  8. #if DBG
  9. #include "pnodewalk.h"
  10. #endif
  11. void PreVisitBlock(ParseNodeBlock *pnodeBlock, ByteCodeGenerator *byteCodeGenerator);
  12. void PostVisitBlock(ParseNodeBlock *pnodeBlock, ByteCodeGenerator *byteCodeGenerator);
  13. bool IsCallOfConstants(ParseNode *pnode)
  14. {
  15. return pnode->AsParseNodeCall()->callOfConstants && pnode->AsParseNodeCall()->argCount > ByteCodeGenerator::MinArgumentsForCallOptimization;
  16. }
  17. template <class PrefixFn, class PostfixFn>
  18. void Visit(ParseNode *pnode, ByteCodeGenerator* byteCodeGenerator, PrefixFn prefix, PostfixFn postfix, ParseNode * pnodeParent = nullptr);
  19. //the only point of this type (as opposed to using a lambda) is to provide a named type in code coverage
  20. template <typename TContext> class ParseNodeVisitor
  21. {
  22. TContext* m_context;
  23. void(*m_fn)(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, TContext* context);
  24. public:
  25. ParseNodeVisitor(TContext* ctx, void(*prefixParam)(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, TContext* context)) :
  26. m_context(ctx), m_fn(prefixParam)
  27. {
  28. }
  29. void operator () (ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator)
  30. {
  31. if (m_fn)
  32. {
  33. m_fn(pnode, byteCodeGenerator, m_context);
  34. }
  35. }
  36. };
  37. template<class TContext>
  38. void VisitIndirect(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, TContext* context,
  39. void (*prefix)(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, TContext* context),
  40. void (*postfix)(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, TContext* context))
  41. {
  42. ParseNodeVisitor<TContext> prefixHelper(context, prefix);
  43. ParseNodeVisitor<TContext> postfixHelper(context, postfix);
  44. Visit(pnode, byteCodeGenerator, prefixHelper, postfixHelper, nullptr);
  45. }
  46. template <class PrefixFn, class PostfixFn>
  47. void VisitList(ParseNode *pnode, ByteCodeGenerator* byteCodeGenerator, PrefixFn prefix, PostfixFn postfix)
  48. {
  49. Assert(pnode != nullptr);
  50. Assert(pnode->nop == knopList);
  51. do
  52. {
  53. ParseNode * pnode1 = pnode->AsParseNodeBin()->pnode1;
  54. Visit(pnode1, byteCodeGenerator, prefix, postfix);
  55. pnode = pnode->AsParseNodeBin()->pnode2;
  56. }
  57. while (pnode->nop == knopList);
  58. Visit(pnode, byteCodeGenerator, prefix, postfix);
  59. }
  60. template <class PrefixFn, class PostfixFn>
  61. void VisitWithStmt(ParseNode *pnode, Js::RegSlot loc, ByteCodeGenerator* byteCodeGenerator, PrefixFn prefix, PostfixFn postfix, ParseNode *pnodeParent)
  62. {
  63. // Note the fact that we're visiting the body of a with statement. This allows us to optimize register assignment
  64. // in the normal case of calls not requiring that their "this" objects be found dynamically.
  65. Scope *scope = pnode->AsParseNodeWith()->scope;
  66. byteCodeGenerator->PushScope(scope);
  67. Visit(pnode->AsParseNodeWith()->pnodeBody, byteCodeGenerator, prefix, postfix, pnodeParent);
  68. scope->SetIsObject();
  69. scope->SetMustInstantiate(true);
  70. byteCodeGenerator->PopScope();
  71. }
  72. bool BlockHasOwnScope(ParseNodeBlock* pnodeBlock, ByteCodeGenerator *byteCodeGenerator)
  73. {
  74. Assert(pnodeBlock->nop == knopBlock);
  75. return pnodeBlock->scope != nullptr &&
  76. (!(pnodeBlock->grfpn & fpnSyntheticNode) ||
  77. (pnodeBlock->blockType == PnodeBlockType::Global && byteCodeGenerator->IsEvalWithNoParentScopeInfo()));
  78. }
  79. void BeginVisitBlock(ParseNodeBlock *pnode, ByteCodeGenerator *byteCodeGenerator)
  80. {
  81. if (BlockHasOwnScope(pnode, byteCodeGenerator))
  82. {
  83. Scope *scope = pnode->scope;
  84. FuncInfo *func = scope->GetFunc();
  85. if (scope->IsInnerScope())
  86. {
  87. // Give this scope an index so its slots can be accessed via the index in the byte code,
  88. // not a register.
  89. scope->SetInnerScopeIndex(func->AcquireInnerScopeIndex());
  90. }
  91. byteCodeGenerator->PushBlock(pnode);
  92. byteCodeGenerator->PushScope(pnode->scope);
  93. }
  94. }
  95. void EndVisitBlock(ParseNodeBlock *pnode, ByteCodeGenerator *byteCodeGenerator)
  96. {
  97. if (BlockHasOwnScope(pnode, byteCodeGenerator))
  98. {
  99. Scope *scope = pnode->scope;
  100. FuncInfo *func = scope->GetFunc();
  101. if (!(byteCodeGenerator->IsInDebugMode() || func->byteCodeFunction->IsCoroutine())
  102. && scope->HasInnerScopeIndex())
  103. {
  104. // In debug mode (or for the generator/async function), don't release the current index, as we're giving each scope a unique index, regardless
  105. // of nesting.
  106. Assert(scope->GetInnerScopeIndex() == func->CurrentInnerScopeIndex());
  107. func->ReleaseInnerScopeIndex();
  108. }
  109. Assert(byteCodeGenerator->GetCurrentScope() == scope);
  110. byteCodeGenerator->PopScope();
  111. byteCodeGenerator->PopBlock();
  112. }
  113. }
  114. void BeginVisitCatch(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  115. {
  116. Scope *scope = pnode->AsParseNodeCatch()->scope;
  117. FuncInfo *func = scope->GetFunc();
  118. if (func->GetCallsEval() || func->GetChildCallsEval() ||
  119. (byteCodeGenerator->GetFlags() & (fscrEval | fscrImplicitThis)))
  120. {
  121. scope->SetIsObject();
  122. }
  123. // Give this scope an index so its slots can be accessed via the index in the byte code,
  124. // not a register.
  125. scope->SetInnerScopeIndex(func->AcquireInnerScopeIndex());
  126. byteCodeGenerator->PushScope(pnode->AsParseNodeCatch()->scope);
  127. }
  128. void EndVisitCatch(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  129. {
  130. Scope *scope = pnode->AsParseNodeCatch()->scope;
  131. FuncInfo *func = scope->GetFunc();
  132. if (scope->HasInnerScopeIndex() && !(byteCodeGenerator->IsInDebugMode() || func->byteCodeFunction->IsCoroutine()))
  133. {
  134. // In debug mode (or for the generator/async function), don't release the current index, as we're giving each scope a unique index,
  135. // regardless of nesting.
  136. Assert(scope->GetInnerScopeIndex() == func->CurrentInnerScopeIndex());
  137. func->ReleaseInnerScopeIndex();
  138. }
  139. byteCodeGenerator->PopScope();
  140. }
  141. bool CreateNativeArrays(ByteCodeGenerator *byteCodeGenerator, FuncInfo *funcInfo)
  142. {
  143. #if ENABLE_PROFILE_INFO
  144. Js::FunctionBody *functionBody = funcInfo ? funcInfo->GetParsedFunctionBody() : nullptr;
  145. return
  146. !PHASE_OFF_OPTFUNC(Js::NativeArrayPhase, functionBody) &&
  147. !byteCodeGenerator->IsInDebugMode() &&
  148. (
  149. functionBody
  150. ? Js::DynamicProfileInfo::IsEnabled(Js::NativeArrayPhase, functionBody)
  151. : Js::DynamicProfileInfo::IsEnabledForAtLeastOneFunction(
  152. Js::NativeArrayPhase,
  153. byteCodeGenerator->GetScriptContext())
  154. );
  155. #else
  156. return false;
  157. #endif
  158. }
  159. bool EmitAsConstantArray(ParseNode *pnodeArr, ByteCodeGenerator *byteCodeGenerator)
  160. {
  161. Assert(pnodeArr && pnodeArr->nop == knopArray);
  162. // TODO: We shouldn't have to handle an empty funcinfo stack here, but there seem to be issues
  163. // with the stack involved nested deferral. Remove this null check when those are resolved.
  164. if (CreateNativeArrays(byteCodeGenerator, byteCodeGenerator->TopFuncInfo()))
  165. {
  166. return pnodeArr->AsParseNodeArrLit()->arrayOfNumbers;
  167. }
  168. return pnodeArr->AsParseNodeArrLit()->arrayOfTaggedInts && pnodeArr->AsParseNodeArrLit()->count > 1;
  169. }
  170. void PropagateFlags(ParseNode *pnodeChild, ParseNode *pnodeParent);
  171. template<class PrefixFn, class PostfixFn>
  172. void Visit(ParseNode *pnode, ByteCodeGenerator* byteCodeGenerator, PrefixFn prefix, PostfixFn postfix, ParseNode *pnodeParent)
  173. {
  174. if (pnode == nullptr)
  175. {
  176. return;
  177. }
  178. ThreadContext::ProbeCurrentStackNoDispose(Js::Constants::MinStackByteCodeVisitor, byteCodeGenerator->GetScriptContext());
  179. prefix(pnode, byteCodeGenerator);
  180. switch (pnode->nop)
  181. {
  182. default:
  183. {
  184. uint flags = ParseNode::Grfnop(pnode->nop);
  185. if (flags&fnopUni)
  186. {
  187. Visit(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator, prefix, postfix);
  188. }
  189. else if (flags&fnopBin)
  190. {
  191. Visit(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator, prefix, postfix);
  192. Visit(pnode->AsParseNodeBin()->pnode2, byteCodeGenerator, prefix, postfix);
  193. if (ByteCodeGenerator::IsSuper(pnode->AsParseNodeBin()->pnode1))
  194. {
  195. Visit(pnode->AsParseNodeSuperReference()->pnodeThis, byteCodeGenerator, prefix, postfix);
  196. }
  197. }
  198. break;
  199. }
  200. case knopParamPattern:
  201. Visit(pnode->AsParseNodeParamPattern()->pnode1, byteCodeGenerator, prefix, postfix);
  202. break;
  203. case knopArrayPattern:
  204. if (!byteCodeGenerator->InDestructuredPattern())
  205. {
  206. byteCodeGenerator->SetInDestructuredPattern(true);
  207. Visit(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator, prefix, postfix);
  208. byteCodeGenerator->SetInDestructuredPattern(false);
  209. }
  210. else
  211. {
  212. Visit(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator, prefix, postfix);
  213. }
  214. break;
  215. case knopCall:
  216. Visit(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, prefix, postfix);
  217. Visit(pnode->AsParseNodeCall()->pnodeArgs, byteCodeGenerator, prefix, postfix);
  218. if (pnode->AsParseNodeCall()->isSuperCall)
  219. {
  220. Visit(pnode->AsParseNodeSuperCall()->pnodeThis, byteCodeGenerator, prefix, postfix);
  221. Visit(pnode->AsParseNodeSuperCall()->pnodeNewTarget, byteCodeGenerator, prefix, postfix);
  222. }
  223. break;
  224. case knopNew:
  225. {
  226. Visit(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator, prefix, postfix);
  227. if (!IsCallOfConstants(pnode))
  228. {
  229. Visit(pnode->AsParseNodeCall()->pnodeArgs, byteCodeGenerator, prefix, postfix);
  230. }
  231. break;
  232. }
  233. case knopQmark:
  234. Visit(pnode->AsParseNodeTri()->pnode1, byteCodeGenerator, prefix, postfix);
  235. Visit(pnode->AsParseNodeTri()->pnode2, byteCodeGenerator, prefix, postfix);
  236. Visit(pnode->AsParseNodeTri()->pnode3, byteCodeGenerator, prefix, postfix);
  237. break;
  238. case knopList:
  239. VisitList(pnode, byteCodeGenerator, prefix, postfix);
  240. break;
  241. // PTNODE(knopVarDecl , "varDcl" ,None ,Var ,fnopNone)
  242. case knopVarDecl:
  243. case knopConstDecl:
  244. case knopLetDecl:
  245. if (pnode->AsParseNodeVar()->pnodeInit != nullptr)
  246. Visit(pnode->AsParseNodeVar()->pnodeInit, byteCodeGenerator, prefix, postfix);
  247. break;
  248. // PTNODE(knopFncDecl , "fncDcl" ,None ,Fnc ,fnopLeaf)
  249. case knopFncDecl:
  250. {
  251. // Inner function declarations are visited before anything else in the scope.
  252. // (See VisitFunctionsInScope.)
  253. break;
  254. }
  255. case knopClassDecl:
  256. {
  257. Visit(pnode->AsParseNodeClass()->pnodeDeclName, byteCodeGenerator, prefix, postfix);
  258. // Now visit the class name and methods.
  259. BeginVisitBlock(pnode->AsParseNodeClass()->pnodeBlock, byteCodeGenerator);
  260. // The extends clause is bound to the scope which contains the class name
  261. // (and the class name identifier is in a TDZ when the extends clause is evaluated).
  262. // See ES 2017 14.5.13 Runtime Semantics: ClassDefinitionEvaluation.
  263. Visit(pnode->AsParseNodeClass()->pnodeExtends, byteCodeGenerator, prefix, postfix);
  264. Visit(pnode->AsParseNodeClass()->pnodeName, byteCodeGenerator, prefix, postfix);
  265. Visit(pnode->AsParseNodeClass()->pnodeStaticMembers, byteCodeGenerator, prefix, postfix);
  266. Visit(pnode->AsParseNodeClass()->pnodeConstructor, byteCodeGenerator, prefix, postfix);
  267. Visit(pnode->AsParseNodeClass()->pnodeMembers, byteCodeGenerator, prefix, postfix);
  268. EndVisitBlock(pnode->AsParseNodeClass()->pnodeBlock, byteCodeGenerator);
  269. break;
  270. }
  271. case knopStrTemplate:
  272. {
  273. // Visit the string node lists only if we do not have a tagged template.
  274. // We never need to visit the raw strings as they are not used in non-tagged templates and
  275. // tagged templates will register them as part of the callsite constant object.
  276. if (!pnode->AsParseNodeStrTemplate()->isTaggedTemplate)
  277. {
  278. Visit(pnode->AsParseNodeStrTemplate()->pnodeStringLiterals, byteCodeGenerator, prefix, postfix);
  279. }
  280. Visit(pnode->AsParseNodeStrTemplate()->pnodeSubstitutionExpressions, byteCodeGenerator, prefix, postfix);
  281. break;
  282. }
  283. case knopExportDefault:
  284. Visit(pnode->AsParseNodeExportDefault()->pnodeExpr, byteCodeGenerator, prefix, postfix);
  285. break;
  286. // PTNODE(knopProg , "program" ,None ,Fnc ,fnopNone)
  287. case knopProg:
  288. {
  289. // We expect that the global statements have been generated (meaning that the pnodeFncs
  290. // field is a real pointer, not an enumeration).
  291. Assert(pnode->AsParseNodeFnc()->pnodeBody);
  292. uint i = 0;
  293. VisitNestedScopes(pnode->AsParseNodeFnc()->pnodeScopes, pnode, byteCodeGenerator, prefix, postfix, &i);
  294. // Visiting global code: track the last value statement.
  295. BeginVisitBlock(pnode->AsParseNodeFnc()->pnodeScopes, byteCodeGenerator);
  296. pnode->AsParseNodeProg()->pnodeLastValStmt = VisitBlock(pnode->AsParseNodeFnc()->pnodeBody, byteCodeGenerator, prefix, postfix);
  297. EndVisitBlock(pnode->AsParseNodeFnc()->pnodeScopes, byteCodeGenerator);
  298. break;
  299. }
  300. case knopFor:
  301. BeginVisitBlock(pnode->AsParseNodeFor()->pnodeBlock, byteCodeGenerator);
  302. Visit(pnode->AsParseNodeFor()->pnodeInit, byteCodeGenerator, prefix, postfix);
  303. byteCodeGenerator->EnterLoop();
  304. Visit(pnode->AsParseNodeFor()->pnodeCond, byteCodeGenerator, prefix, postfix);
  305. Visit(pnode->AsParseNodeFor()->pnodeIncr, byteCodeGenerator, prefix, postfix);
  306. Visit(pnode->AsParseNodeFor()->pnodeBody, byteCodeGenerator, prefix, postfix, pnode);
  307. byteCodeGenerator->ExitLoop();
  308. EndVisitBlock(pnode->AsParseNodeFor()->pnodeBlock, byteCodeGenerator);
  309. break;
  310. // PTNODE(knopIf , "if" ,None ,If ,fnopNone)
  311. case knopIf:
  312. Visit(pnode->AsParseNodeIf()->pnodeCond, byteCodeGenerator, prefix, postfix);
  313. Visit(pnode->AsParseNodeIf()->pnodeTrue, byteCodeGenerator, prefix, postfix, pnode);
  314. if (pnode->AsParseNodeIf()->pnodeFalse != nullptr)
  315. {
  316. Visit(pnode->AsParseNodeIf()->pnodeFalse, byteCodeGenerator, prefix, postfix, pnode);
  317. }
  318. break;
  319. // PTNODE(knopWhile , "while" ,None ,While,fnopBreak|fnopContinue)
  320. // PTNODE(knopDoWhile , "do-while" ,None ,While,fnopBreak|fnopContinue)
  321. case knopDoWhile:
  322. case knopWhile:
  323. byteCodeGenerator->EnterLoop();
  324. Visit(pnode->AsParseNodeWhile()->pnodeCond, byteCodeGenerator, prefix, postfix);
  325. Visit(pnode->AsParseNodeWhile()->pnodeBody, byteCodeGenerator, prefix, postfix, pnode);
  326. byteCodeGenerator->ExitLoop();
  327. break;
  328. // PTNODE(knopForIn , "for in" ,None ,ForIn,fnopBreak|fnopContinue|fnopCleanup)
  329. case knopForIn:
  330. case knopForOf:
  331. BeginVisitBlock(pnode->AsParseNodeForInOrForOf()->pnodeBlock, byteCodeGenerator);
  332. Visit(pnode->AsParseNodeForInOrForOf()->pnodeLval, byteCodeGenerator, prefix, postfix);
  333. Visit(pnode->AsParseNodeForInOrForOf()->pnodeObj, byteCodeGenerator, prefix, postfix);
  334. byteCodeGenerator->EnterLoop();
  335. Visit(pnode->AsParseNodeForInOrForOf()->pnodeBody, byteCodeGenerator, prefix, postfix, pnode);
  336. byteCodeGenerator->ExitLoop();
  337. EndVisitBlock(pnode->AsParseNodeForInOrForOf()->pnodeBlock, byteCodeGenerator);
  338. break;
  339. // PTNODE(knopReturn , "return" ,None ,Uni ,fnopNone)
  340. case knopReturn:
  341. if (pnode->AsParseNodeReturn()->pnodeExpr != nullptr)
  342. Visit(pnode->AsParseNodeReturn()->pnodeExpr, byteCodeGenerator, prefix, postfix);
  343. break;
  344. // PTNODE(knopBlock , "{}" ,None ,Block,fnopNone)
  345. case knopBlock:
  346. {
  347. ParseNodeBlock * pnodeBlock = pnode->AsParseNodeBlock();
  348. if (pnodeBlock->pnodeStmt != nullptr)
  349. {
  350. BeginVisitBlock(pnodeBlock, byteCodeGenerator);
  351. pnodeBlock->pnodeLastValStmt = VisitBlock(pnodeBlock->pnodeStmt, byteCodeGenerator, prefix, postfix, pnode);
  352. EndVisitBlock(pnodeBlock, byteCodeGenerator);
  353. }
  354. else
  355. {
  356. pnodeBlock->pnodeLastValStmt = nullptr;
  357. }
  358. break;
  359. }
  360. // PTNODE(knopWith , "with" ,None ,With ,fnopCleanup)
  361. case knopWith:
  362. Visit(pnode->AsParseNodeWith()->pnodeObj, byteCodeGenerator, prefix, postfix);
  363. VisitWithStmt(pnode, pnode->AsParseNodeWith()->pnodeObj->location, byteCodeGenerator, prefix, postfix, pnode);
  364. break;
  365. // PTNODE(knopBreak , "break" ,None ,Jump ,fnopNone)
  366. case knopBreak:
  367. // TODO: some representation of target
  368. break;
  369. // PTNODE(knopContinue , "continue" ,None ,Jump ,fnopNone)
  370. case knopContinue:
  371. // TODO: some representation of target
  372. break;
  373. // PTNODE(knopSwitch , "switch" ,None ,Switch,fnopBreak)
  374. case knopSwitch:
  375. Visit(pnode->AsParseNodeSwitch()->pnodeVal, byteCodeGenerator, prefix, postfix);
  376. BeginVisitBlock(pnode->AsParseNodeSwitch()->pnodeBlock, byteCodeGenerator);
  377. for (ParseNodeCase *pnodeT = pnode->AsParseNodeSwitch()->pnodeCases; nullptr != pnodeT; pnodeT = pnodeT->pnodeNext)
  378. {
  379. Visit(pnodeT, byteCodeGenerator, prefix, postfix, pnode);
  380. }
  381. Visit(pnode->AsParseNodeSwitch()->pnodeBlock, byteCodeGenerator, prefix, postfix);
  382. EndVisitBlock(pnode->AsParseNodeSwitch()->pnodeBlock, byteCodeGenerator);
  383. break;
  384. // PTNODE(knopCase , "case" ,None ,Case ,fnopNone)
  385. case knopCase:
  386. Visit(pnode->AsParseNodeCase()->pnodeExpr, byteCodeGenerator, prefix, postfix);
  387. Visit(pnode->AsParseNodeCase()->pnodeBody, byteCodeGenerator, prefix, postfix, pnode);
  388. break;
  389. case knopTypeof:
  390. Visit(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator, prefix, postfix);
  391. break;
  392. // PTNODE(knopTryCatchFinally,"try-catch-finally",None,TryCatchFinally,fnopCleanup)
  393. case knopTryFinally:
  394. Visit(pnode->AsParseNodeTryFinally()->pnodeTry, byteCodeGenerator, prefix, postfix, pnode);
  395. Visit(pnode->AsParseNodeTryFinally()->pnodeFinally, byteCodeGenerator, prefix, postfix, pnode);
  396. break;
  397. // PTNODE(knopTryCatch , "try-catch" ,None ,TryCatch ,fnopCleanup)
  398. case knopTryCatch:
  399. Visit(pnode->AsParseNodeTryCatch()->pnodeTry, byteCodeGenerator, prefix, postfix, pnode);
  400. Visit(pnode->AsParseNodeTryCatch()->pnodeCatch, byteCodeGenerator, prefix, postfix, pnode);
  401. break;
  402. // PTNODE(knopTry , "try" ,None ,Try ,fnopCleanup)
  403. case knopTry:
  404. Visit(pnode->AsParseNodeTry()->pnodeBody, byteCodeGenerator, prefix, postfix, pnode);
  405. break;
  406. case knopCatch:
  407. BeginVisitCatch(pnode, byteCodeGenerator);
  408. Visit(pnode->AsParseNodeCatch()->GetParam(), byteCodeGenerator, prefix, postfix);
  409. Visit(pnode->AsParseNodeCatch()->pnodeBody, byteCodeGenerator, prefix, postfix, pnode);
  410. EndVisitCatch(pnode, byteCodeGenerator);
  411. break;
  412. case knopFinally:
  413. Visit(pnode->AsParseNodeFinally()->pnodeBody, byteCodeGenerator, prefix, postfix, pnode);
  414. break;
  415. // PTNODE(knopThrow , "throw" ,None ,Uni ,fnopNone)
  416. case knopThrow:
  417. Visit(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator, prefix, postfix);
  418. break;
  419. case knopArray:
  420. {
  421. bool arrayLitOpt = EmitAsConstantArray(pnode, byteCodeGenerator);
  422. if (!arrayLitOpt)
  423. {
  424. Visit(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator, prefix, postfix);
  425. }
  426. break;
  427. }
  428. case knopComma:
  429. {
  430. ParseNode *pnode1 = pnode->AsParseNodeBin()->pnode1;
  431. if (pnode1->nop == knopComma)
  432. {
  433. // Spot-fix to avoid recursion on very large comma expressions.
  434. ArenaAllocator *alloc = byteCodeGenerator->GetAllocator();
  435. SList<ParseNode*> rhsStack(alloc);
  436. do
  437. {
  438. rhsStack.Push(pnode1->AsParseNodeBin()->pnode2);
  439. pnode1 = pnode1->AsParseNodeBin()->pnode1;
  440. }
  441. while (pnode1->nop == knopComma);
  442. Visit(pnode1, byteCodeGenerator, prefix, postfix);
  443. while (!rhsStack.Empty())
  444. {
  445. ParseNode *pnodeRhs = rhsStack.Pop();
  446. Visit(pnodeRhs, byteCodeGenerator, prefix, postfix);
  447. }
  448. }
  449. else
  450. {
  451. Visit(pnode1, byteCodeGenerator, prefix, postfix);
  452. }
  453. Visit(pnode->AsParseNodeBin()->pnode2, byteCodeGenerator, prefix, postfix);
  454. }
  455. break;
  456. }
  457. if (pnodeParent)
  458. {
  459. PropagateFlags(pnode, pnodeParent);
  460. }
  461. postfix(pnode, byteCodeGenerator);
  462. }
  463. bool IsJump(ParseNode *pnode)
  464. {
  465. switch (pnode->nop)
  466. {
  467. case knopBreak:
  468. case knopContinue:
  469. case knopThrow:
  470. case knopReturn:
  471. return true;
  472. case knopBlock:
  473. case knopDoWhile:
  474. case knopWhile:
  475. case knopWith:
  476. case knopIf:
  477. case knopForIn:
  478. case knopForOf:
  479. case knopFor:
  480. case knopSwitch:
  481. case knopCase:
  482. case knopTryFinally:
  483. case knopTryCatch:
  484. case knopTry:
  485. case knopCatch:
  486. case knopFinally:
  487. return (pnode->AsParseNodeStmt()->grfnop & fnopJump) != 0;
  488. default:
  489. return false;
  490. }
  491. }
  492. void PropagateFlags(ParseNode *pnodeChild, ParseNode *pnodeParent)
  493. {
  494. if (IsJump(pnodeChild))
  495. {
  496. pnodeParent->AsParseNodeStmt()->grfnop |= fnopJump;
  497. }
  498. }
  499. void Bind(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator);
  500. void BindReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator);
  501. void AssignRegisters(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator);
  502. // TODO[ianhall]: This should be in a shared AST Utility header or source file
  503. bool IsExpressionStatement(ParseNode* stmt, const Js::ScriptContext *const scriptContext)
  504. {
  505. if (stmt->nop == knopFncDecl)
  506. {
  507. // 'knopFncDecl' is used for both function declarations and function expressions. In a program, a function expression
  508. // produces the function object that is created for the function expression as its value for the program. A function
  509. // declaration does not produce a value for the program.
  510. return !stmt->AsParseNodeFnc()->IsDeclaration();
  511. }
  512. if ((stmt->nop >= 0) && (stmt->nop<knopLim))
  513. {
  514. return (ParseNode::Grfnop(stmt->nop) & fnopNotExprStmt) == 0;
  515. }
  516. return false;
  517. }
  518. bool MustProduceValue(ParseNode *pnode, const Js::ScriptContext *const scriptContext)
  519. {
  520. // Determine whether the current statement is guaranteed to produce a value.
  521. if (IsExpressionStatement(pnode, scriptContext))
  522. {
  523. // These are trivially true.
  524. return true;
  525. }
  526. for (;;)
  527. {
  528. switch (pnode->nop)
  529. {
  530. case knopFor:
  531. // Check the common "for (;;)" case.
  532. if (pnode->AsParseNodeFor()->pnodeCond != nullptr ||
  533. pnode->AsParseNodeFor()->pnodeBody == nullptr)
  534. {
  535. return false;
  536. }
  537. // Loop body is always executed. Look at the loop body next.
  538. pnode = pnode->AsParseNodeFor()->pnodeBody;
  539. break;
  540. case knopIf:
  541. // True only if both "if" and "else" exist, and both produce values.
  542. if (pnode->AsParseNodeIf()->pnodeTrue == nullptr ||
  543. pnode->AsParseNodeIf()->pnodeFalse == nullptr)
  544. {
  545. return false;
  546. }
  547. if (!MustProduceValue(pnode->AsParseNodeIf()->pnodeFalse, scriptContext))
  548. {
  549. return false;
  550. }
  551. pnode = pnode->AsParseNodeIf()->pnodeTrue;
  552. break;
  553. case knopWhile:
  554. // Check the common "while (1)" case.
  555. if (pnode->AsParseNodeWhile()->pnodeBody == nullptr ||
  556. (pnode->AsParseNodeWhile()->pnodeCond &&
  557. (pnode->AsParseNodeWhile()->pnodeCond->nop != knopInt ||
  558. pnode->AsParseNodeWhile()->pnodeCond->AsParseNodeInt()->lw == 0)))
  559. {
  560. return false;
  561. }
  562. // Loop body is always executed. Look at the loop body next.
  563. pnode = pnode->AsParseNodeWhile()->pnodeBody;
  564. break;
  565. case knopDoWhile:
  566. if (pnode->AsParseNodeWhile()->pnodeBody == nullptr)
  567. {
  568. return false;
  569. }
  570. // Loop body is always executed. Look at the loop body next.
  571. pnode = pnode->AsParseNodeWhile()->pnodeBody;
  572. break;
  573. case knopBlock:
  574. return pnode->AsParseNodeBlock()->pnodeLastValStmt != nullptr;
  575. case knopWith:
  576. if (pnode->AsParseNodeWith()->pnodeBody == nullptr)
  577. {
  578. return false;
  579. }
  580. pnode = pnode->AsParseNodeWith()->pnodeBody;
  581. break;
  582. case knopSwitch:
  583. {
  584. // This is potentially the most inefficient case. We could consider adding a flag to the PnSwitch
  585. // struct and computing it when we visit the switch, but:
  586. // a. switch statements at global scope shouldn't be that common;
  587. // b. switch statements with many arms shouldn't be that common;
  588. // c. switches without default cases can be trivially skipped.
  589. if (pnode->AsParseNodeSwitch()->pnodeDefault == nullptr)
  590. {
  591. // Can't guarantee that any code is executed.
  592. return false;
  593. }
  594. ParseNodeCase *pnodeCase;
  595. for (pnodeCase = pnode->AsParseNodeSwitch()->pnodeCases; pnodeCase; pnodeCase = pnodeCase->pnodeNext)
  596. {
  597. if (pnodeCase->pnodeBody == nullptr)
  598. {
  599. if (pnodeCase->pnodeNext == nullptr)
  600. {
  601. // Last case has no code to execute.
  602. return false;
  603. }
  604. // Fall through to the next case.
  605. }
  606. else
  607. {
  608. if (!MustProduceValue(pnodeCase->pnodeBody, scriptContext))
  609. {
  610. return false;
  611. }
  612. }
  613. }
  614. return true;
  615. }
  616. case knopTryCatch:
  617. // True only if both try and catch produce a value.
  618. if (pnode->AsParseNodeTryCatch()->pnodeTry->pnodeBody == nullptr ||
  619. pnode->AsParseNodeTryCatch()->pnodeCatch->pnodeBody == nullptr)
  620. {
  621. return false;
  622. }
  623. if (!MustProduceValue(pnode->AsParseNodeTryCatch()->pnodeCatch->pnodeBody, scriptContext))
  624. {
  625. return false;
  626. }
  627. pnode = pnode->AsParseNodeTryCatch()->pnodeTry->pnodeBody;
  628. break;
  629. case knopTryFinally:
  630. if (pnode->AsParseNodeTryFinally()->pnodeFinally->pnodeBody == nullptr)
  631. {
  632. // No finally body: look at the try body.
  633. if (pnode->AsParseNodeTryFinally()->pnodeTry->pnodeBody == nullptr)
  634. {
  635. return false;
  636. }
  637. pnode = pnode->AsParseNodeTryFinally()->pnodeTry->pnodeBody;
  638. break;
  639. }
  640. // Skip the try body, since the finally body will always follow it.
  641. pnode = pnode->AsParseNodeTryFinally()->pnodeFinally->pnodeBody;
  642. break;
  643. default:
  644. return false;
  645. }
  646. }
  647. }
  648. ByteCodeGenerator::ByteCodeGenerator(Js::ScriptContext* scriptContext, Js::ScopeInfo* parentScopeInfo) :
  649. alloc(nullptr),
  650. scriptContext(scriptContext),
  651. flags(0),
  652. funcInfoStack(nullptr),
  653. pRootFunc(nullptr),
  654. pCurrentFunction(nullptr),
  655. globalScope(nullptr),
  656. currentScope(nullptr),
  657. parentScopeInfo(parentScopeInfo),
  658. dynamicScopeCount(0),
  659. isBinding(false),
  660. inDestructuredPattern(false)
  661. {
  662. m_writer.Create();
  663. }
  664. void ByteCodeGenerator::FinalizeFuncInfos()
  665. {
  666. if (this->funcInfosToFinalize == nullptr)
  667. {
  668. return;
  669. }
  670. FOREACH_SLIST_ENTRY(FuncInfo*, funcInfo, this->funcInfosToFinalize)
  671. {
  672. if (funcInfo->canDefer)
  673. {
  674. funcInfo->byteCodeFunction->SetAttributes((Js::FunctionInfo::Attributes)(funcInfo->byteCodeFunction->GetAttributes() | Js::FunctionInfo::Attributes::CanDefer));
  675. }
  676. }
  677. NEXT_SLIST_ENTRY;
  678. this->funcInfosToFinalize = nullptr;
  679. }
  680. void ByteCodeGenerator::AddFuncInfoToFinalizationSet(FuncInfo * funcInfo)
  681. {
  682. if (this->funcInfosToFinalize == nullptr)
  683. {
  684. this->funcInfosToFinalize = Anew(alloc, SList<FuncInfo*>, alloc);
  685. }
  686. this->funcInfosToFinalize->Prepend(funcInfo);
  687. }
  688. /* static */
  689. bool ByteCodeGenerator::IsFalse(ParseNode* node)
  690. {
  691. return (node->nop == knopInt && node->AsParseNodeInt()->lw == 0) || node->nop == knopFalse;
  692. }
  693. /* static */
  694. bool ByteCodeGenerator::IsThis(ParseNode* pnode)
  695. {
  696. return pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isThis;
  697. }
  698. /* static */
  699. bool ByteCodeGenerator::IsSuper(ParseNode* pnode)
  700. {
  701. return pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isSuper;
  702. }
  703. bool ByteCodeGenerator::IsES6DestructuringEnabled() const
  704. {
  705. return scriptContext->GetConfig()->IsES6DestructuringEnabled();
  706. }
  707. bool ByteCodeGenerator::IsES6ForLoopSemanticsEnabled() const
  708. {
  709. return scriptContext->GetConfig()->IsES6ForLoopSemanticsEnabled();
  710. }
  711. // ByteCodeGenerator debug mode means we are generating debug mode user-code. Library code is always in non-debug mode.
  712. bool ByteCodeGenerator::IsInDebugMode() const
  713. {
  714. return m_utf8SourceInfo->IsInDebugMode();
  715. }
  716. // ByteCodeGenerator non-debug mode means we are not debugging, or we are generating library code which is always in non-debug mode.
  717. bool ByteCodeGenerator::IsInNonDebugMode() const
  718. {
  719. return scriptContext->IsScriptContextInNonDebugMode() || m_utf8SourceInfo->GetIsLibraryCode();
  720. }
  721. bool ByteCodeGenerator::ShouldTrackDebuggerMetadata() const
  722. {
  723. return (IsInDebugMode())
  724. #if DBG_DUMP
  725. || (Js::Configuration::Global.flags.Debug)
  726. #endif
  727. ;
  728. }
  729. void ByteCodeGenerator::SetRootFuncInfo(FuncInfo* func)
  730. {
  731. Assert(pRootFunc == nullptr || pRootFunc == func->byteCodeFunction || !IsInNonDebugMode());
  732. if ((this->flags & fscrImplicitThis) && !this->HasParentScopeInfo())
  733. {
  734. // Mark a top-level event handler, since it will need to construct the "this" pointer's
  735. // namespace hierarchy to access globals.
  736. Assert(!func->IsGlobalFunction());
  737. func->SetIsTopLevelEventHandler(true);
  738. }
  739. if (pRootFunc)
  740. {
  741. return;
  742. }
  743. this->pRootFunc = func->byteCodeFunction->GetParseableFunctionInfo();
  744. this->m_utf8SourceInfo->AddTopLevelFunctionInfo(func->byteCodeFunction->GetFunctionInfo(), scriptContext->GetRecycler());
  745. }
  746. Js::RegSlot ByteCodeGenerator::NextVarRegister()
  747. {
  748. return funcInfoStack->Top()->NextVarRegister();
  749. }
  750. Js::RegSlot ByteCodeGenerator::NextConstRegister()
  751. {
  752. return funcInfoStack->Top()->NextConstRegister();
  753. }
  754. FuncInfo * ByteCodeGenerator::TopFuncInfo() const
  755. {
  756. return funcInfoStack->Empty() ? nullptr : funcInfoStack->Top();
  757. }
  758. void ByteCodeGenerator::EnterLoop()
  759. {
  760. if (this->TopFuncInfo())
  761. {
  762. this->TopFuncInfo()->hasLoop = true;
  763. }
  764. loopDepth++;
  765. }
  766. void ByteCodeGenerator::SetHasTry(bool has)
  767. {
  768. TopFuncInfo()->GetParsedFunctionBody()->SetHasTry(has);
  769. }
  770. void ByteCodeGenerator::SetHasFinally(bool has)
  771. {
  772. TopFuncInfo()->GetParsedFunctionBody()->SetHasFinally(has);
  773. }
  774. // TODO: per-function register assignment for env and global symbols
  775. void ByteCodeGenerator::AssignRegister(Symbol *sym)
  776. {
  777. AssertMsg(sym->GetDecl() == nullptr || sym->GetDecl()->nop != knopConstDecl || sym->GetDecl()->nop != knopLetDecl,
  778. "const and let should get only temporary register, assigned during emit stage");
  779. if (sym->GetLocation() == Js::Constants::NoRegister)
  780. {
  781. sym->SetLocation(NextVarRegister());
  782. }
  783. }
  784. void ByteCodeGenerator::AddTargetStmt(ParseNodeStmt *pnodeStmt)
  785. {
  786. FuncInfo *top = funcInfoStack->Top();
  787. top->AddTargetStmt(pnodeStmt);
  788. }
  789. Js::RegSlot ByteCodeGenerator::AssignThisConstRegister()
  790. {
  791. FuncInfo *top = funcInfoStack->Top();
  792. return top->AssignThisConstRegister();
  793. }
  794. Js::RegSlot ByteCodeGenerator::AssignNullConstRegister()
  795. {
  796. FuncInfo *top = funcInfoStack->Top();
  797. return top->AssignNullConstRegister();
  798. }
  799. Js::RegSlot ByteCodeGenerator::AssignUndefinedConstRegister()
  800. {
  801. FuncInfo *top = funcInfoStack->Top();
  802. return top->AssignUndefinedConstRegister();
  803. }
  804. Js::RegSlot ByteCodeGenerator::AssignTrueConstRegister()
  805. {
  806. FuncInfo *top = funcInfoStack->Top();
  807. return top->AssignTrueConstRegister();
  808. }
  809. Js::RegSlot ByteCodeGenerator::AssignFalseConstRegister()
  810. {
  811. FuncInfo *top = funcInfoStack->Top();
  812. return top->AssignFalseConstRegister();
  813. }
  814. void ByteCodeGenerator::SetNeedEnvRegister()
  815. {
  816. FuncInfo *top = funcInfoStack->Top();
  817. top->SetNeedEnvRegister();
  818. }
  819. void ByteCodeGenerator::AssignFrameObjRegister()
  820. {
  821. FuncInfo* top = funcInfoStack->Top();
  822. if (top->frameObjRegister == Js::Constants::NoRegister)
  823. {
  824. top->frameObjRegister = top->NextVarRegister();
  825. }
  826. }
  827. void ByteCodeGenerator::AssignFrameDisplayRegister()
  828. {
  829. FuncInfo* top = funcInfoStack->Top();
  830. if (top->frameDisplayRegister == Js::Constants::NoRegister)
  831. {
  832. top->frameDisplayRegister = top->NextVarRegister();
  833. }
  834. }
  835. void ByteCodeGenerator::AssignFrameSlotsRegister()
  836. {
  837. FuncInfo* top = funcInfoStack->Top();
  838. if (top->frameSlotsRegister == Js::Constants::NoRegister)
  839. {
  840. top->frameSlotsRegister = NextVarRegister();
  841. }
  842. }
  843. void ByteCodeGenerator::AssignParamSlotsRegister()
  844. {
  845. FuncInfo* top = funcInfoStack->Top();
  846. Assert(top->paramSlotsRegister == Js::Constants::NoRegister);
  847. top->paramSlotsRegister = NextVarRegister();
  848. }
  849. void ByteCodeGenerator::SetNumberOfInArgs(Js::ArgSlot argCount)
  850. {
  851. FuncInfo *top = funcInfoStack->Top();
  852. top->inArgsCount = argCount;
  853. }
  854. Js::RegSlot ByteCodeGenerator::EnregisterConstant(unsigned int constant)
  855. {
  856. Js::RegSlot loc = Js::Constants::NoRegister;
  857. FuncInfo *top = funcInfoStack->Top();
  858. if (!top->constantToRegister.TryGetValue(constant, &loc))
  859. {
  860. loc = NextConstRegister();
  861. top->constantToRegister.Add(constant, loc);
  862. }
  863. return loc;
  864. }
  865. Js::RegSlot ByteCodeGenerator::EnregisterStringConstant(IdentPtr pid)
  866. {
  867. Js::RegSlot loc = Js::Constants::NoRegister;
  868. FuncInfo *top = funcInfoStack->Top();
  869. if (!top->stringToRegister.TryGetValue(pid, &loc))
  870. {
  871. loc = NextConstRegister();
  872. top->stringToRegister.Add(pid, loc);
  873. }
  874. return loc;
  875. }
  876. Js::RegSlot ByteCodeGenerator::EnregisterDoubleConstant(double d)
  877. {
  878. Js::RegSlot loc = Js::Constants::NoRegister;
  879. FuncInfo *top = funcInfoStack->Top();
  880. if (!top->TryGetDoubleLoc(d, &loc))
  881. {
  882. loc = NextConstRegister();
  883. top->AddDoubleConstant(d, loc);
  884. }
  885. return loc;
  886. }
  887. Js::RegSlot ByteCodeGenerator::EnregisterStringTemplateCallsiteConstant(ParseNode* pnode)
  888. {
  889. Assert(pnode->nop == knopStrTemplate);
  890. Assert(pnode->AsParseNodeStrTemplate()->isTaggedTemplate);
  891. Js::RegSlot loc = Js::Constants::NoRegister;
  892. FuncInfo* top = funcInfoStack->Top();
  893. if (!top->stringTemplateCallsiteRegisterMap.TryGetValue(pnode, &loc))
  894. {
  895. loc = NextConstRegister();
  896. top->stringTemplateCallsiteRegisterMap.Add(pnode, loc);
  897. }
  898. return loc;
  899. }
  900. //
  901. // Restore all outer func scope info when reparsing a deferred func.
  902. //
  903. void ByteCodeGenerator::RestoreScopeInfo(Js::ScopeInfo *scopeInfo, FuncInfo * func)
  904. {
  905. if (scopeInfo)
  906. {
  907. PROBE_STACK_NO_DISPOSE(scriptContext, Js::Constants::MinStackByteCodeVisitor);
  908. Js::ParseableFunctionInfo * pfi = scopeInfo->GetFunctionInfo()->GetParseableFunctionInfo();
  909. bool newFunc = (func == nullptr || func->byteCodeFunction != pfi);
  910. if (newFunc)
  911. {
  912. func = Anew(alloc, FuncInfo, pfi->GetDisplayName(), alloc, this, nullptr, nullptr, nullptr, pfi);
  913. }
  914. // Recursively restore enclosing scope info so outermost scopes/funcs are pushed first.
  915. this->RestoreScopeInfo(scopeInfo->GetParentScopeInfo(), func);
  916. this->RestoreOneScope(scopeInfo, func);
  917. if (newFunc)
  918. {
  919. PushFuncInfo(_u("RestoreScopeInfo"), func);
  920. if (!pfi->DoStackNestedFunc())
  921. {
  922. func->hasEscapedUseNestedFunc = true;
  923. }
  924. }
  925. }
  926. else
  927. {
  928. Assert(this->TopFuncInfo() == nullptr);
  929. // funcBody is glo
  930. Assert(currentScope == nullptr);
  931. currentScope = Anew(alloc, Scope, alloc, ScopeType_Global);
  932. globalScope = currentScope;
  933. if (func == nullptr || !func->byteCodeFunction->GetIsGlobalFunc())
  934. {
  935. func = Anew(alloc, FuncInfo, Js::Constants::GlobalFunction,
  936. alloc, this, nullptr, nullptr/*currentScope*/, nullptr, nullptr/*functionBody*/);
  937. PushFuncInfo(_u("RestoreScopeInfo"), func);
  938. }
  939. func->SetBodyScope(currentScope);
  940. }
  941. }
  942. void ByteCodeGenerator::RestoreOneScope(Js::ScopeInfo * scopeInfo, FuncInfo * func)
  943. {
  944. TRACE_BYTECODE(_u("\nRestore ScopeInfo: %s #symbols: %d %s\n"),
  945. func->name, scopeInfo->GetSymbolCount(), scopeInfo->IsObject() ? _u("isObject") : _u(""));
  946. Scope * scope = scopeInfo->GetScope();
  947. scope->SetFunc(func);
  948. switch (scope->GetScopeType())
  949. {
  950. case ScopeType_Parameter:
  951. Assert(func->GetParamScope() == nullptr);
  952. func->SetParamScope(scope);
  953. break;
  954. case ScopeType_FuncExpr:
  955. Assert(func->GetFuncExprScope() == nullptr);
  956. func->SetFuncExprScope(scope);
  957. break;
  958. case ScopeType_FunctionBody:
  959. case ScopeType_GlobalEvalBlock:
  960. Assert(func->GetBodyScope() == nullptr || (func->GetBodyScope()->GetScopeType() == ScopeType_Global && scope->GetScopeType() == ScopeType_GlobalEvalBlock));
  961. func->SetBodyScope(scope);
  962. func->SetHasCachedScope(scopeInfo->IsCached());
  963. break;
  964. }
  965. Assert(!scopeInfo->IsCached() || scope == func->GetBodyScope());
  966. // scopeInfo->scope was created/saved during parsing.
  967. // We no longer need it by now.
  968. // Clear it to avoid GC false positive (arena memory later used by GC).
  969. scopeInfo->SetScope(nullptr);
  970. this->PushScope(scope);
  971. }
  972. FuncInfo * ByteCodeGenerator::StartBindGlobalStatements(ParseNodeProg *pnode)
  973. {
  974. if (parentScopeInfo)
  975. {
  976. trackEnvDepth = true;
  977. RestoreScopeInfo(parentScopeInfo, nullptr);
  978. trackEnvDepth = false;
  979. // "currentScope" is the parentFunc scope. This ensures the deferred func declaration
  980. // symbol will bind to the func declaration symbol already available in parentFunc scope.
  981. }
  982. else
  983. {
  984. currentScope = pnode->scope;
  985. Assert(currentScope);
  986. globalScope = currentScope;
  987. }
  988. Js::FunctionBody * byteCodeFunction;
  989. if (!IsInNonDebugMode() && this->pCurrentFunction != nullptr && this->pCurrentFunction->GetIsGlobalFunc() && !this->pCurrentFunction->IsFakeGlobalFunc(flags))
  990. {
  991. // we will re-use the global FunctionBody which was created before deferred parse.
  992. byteCodeFunction = this->pCurrentFunction;
  993. byteCodeFunction->RemoveDeferParseAttribute();
  994. byteCodeFunction->ResetByteCodeGenVisitState();
  995. }
  996. else if ((this->flags & fscrDeferredFnc))
  997. {
  998. byteCodeFunction = this->EnsureFakeGlobalFuncForUndefer(pnode);
  999. }
  1000. else
  1001. {
  1002. byteCodeFunction = this->MakeGlobalFunctionBody(pnode);
  1003. // Mark this global function to required for register script event
  1004. byteCodeFunction->SetIsTopLevel(true);
  1005. if (pnode->GetStrictMode() != 0)
  1006. {
  1007. byteCodeFunction->SetIsStrictMode();
  1008. }
  1009. }
  1010. if (byteCodeFunction->IsReparsed())
  1011. {
  1012. byteCodeFunction->RestoreState(pnode);
  1013. }
  1014. else
  1015. {
  1016. byteCodeFunction->SaveState(pnode);
  1017. }
  1018. FuncInfo *funcInfo = Anew(alloc, FuncInfo, Js::Constants::GlobalFunction,
  1019. alloc, this, nullptr, globalScope, pnode, byteCodeFunction);
  1020. int32 currentAstSize = pnode->astSize;
  1021. if (currentAstSize > this->maxAstSize)
  1022. {
  1023. this->maxAstSize = currentAstSize;
  1024. }
  1025. PushFuncInfo(_u("StartBindGlobalStatements"), funcInfo);
  1026. return funcInfo;
  1027. }
  1028. void ByteCodeGenerator::AssignPropertyId(IdentPtr pid)
  1029. {
  1030. if (pid->GetPropertyId() == Js::Constants::NoProperty)
  1031. {
  1032. Js::PropertyId id = TopFuncInfo()->byteCodeFunction->GetOrAddPropertyIdTracked(SymbolName(pid->Psz(), pid->Cch()));
  1033. pid->SetPropertyId(id);
  1034. }
  1035. }
  1036. void ByteCodeGenerator::AssignPropertyId(Symbol *sym, Js::ParseableFunctionInfo* functionInfo)
  1037. {
  1038. sym->SetPosition(functionInfo->GetOrAddPropertyIdTracked(sym->GetName()));
  1039. }
  1040. template <class PrefixFn, class PostfixFn>
  1041. ParseNode* VisitBlock(ParseNode *pnode, ByteCodeGenerator* byteCodeGenerator, PrefixFn prefix, PostfixFn postfix, ParseNode *pnodeParent = nullptr)
  1042. {
  1043. ParseNode *pnodeLastVal = nullptr;
  1044. if (pnode != nullptr)
  1045. {
  1046. bool fTrackVal = byteCodeGenerator->IsBinding() &&
  1047. (byteCodeGenerator->GetFlags() & fscrReturnExpression) &&
  1048. byteCodeGenerator->TopFuncInfo()->IsGlobalFunction();
  1049. while (pnode->nop == knopList)
  1050. {
  1051. Visit(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator, prefix, postfix, pnodeParent);
  1052. if (fTrackVal)
  1053. {
  1054. // If we're tracking values, find the last statement (if any) in the block that is
  1055. // guaranteed to produce a value.
  1056. if (MustProduceValue(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator->GetScriptContext()))
  1057. {
  1058. pnodeLastVal = pnode->AsParseNodeBin()->pnode1;
  1059. }
  1060. if (IsJump(pnode->AsParseNodeBin()->pnode1))
  1061. {
  1062. // This is a jump out of the current block. The remaining instructions (if any)
  1063. // will not be executed, so stop tracking them.
  1064. fTrackVal = false;
  1065. }
  1066. }
  1067. pnode = pnode->AsParseNodeBin()->pnode2;
  1068. }
  1069. Visit(pnode, byteCodeGenerator, prefix, postfix, pnodeParent);
  1070. if (fTrackVal)
  1071. {
  1072. if (MustProduceValue(pnode, byteCodeGenerator->GetScriptContext()))
  1073. {
  1074. pnodeLastVal = pnode;
  1075. }
  1076. }
  1077. }
  1078. return pnodeLastVal;
  1079. }
  1080. // Attributes that should be consistent between defer parse and full parse.
  1081. static const Js::FunctionInfo::Attributes StableFunctionInfoAttributesMask = (Js::FunctionInfo::Attributes)
  1082. (
  1083. Js::FunctionInfo::Attributes::ErrorOnNew |
  1084. Js::FunctionInfo::Attributes::Async |
  1085. Js::FunctionInfo::Attributes::Lambda |
  1086. Js::FunctionInfo::Attributes::SuperReference |
  1087. Js::FunctionInfo::Attributes::ClassConstructor |
  1088. Js::FunctionInfo::Attributes::BaseConstructorKind |
  1089. Js::FunctionInfo::Attributes::ClassMethod |
  1090. Js::FunctionInfo::Attributes::Method |
  1091. Js::FunctionInfo::Attributes::Generator |
  1092. Js::FunctionInfo::Attributes::Module |
  1093. Js::FunctionInfo::Attributes::ComputedName |
  1094. Js::FunctionInfo::Attributes::HomeObj
  1095. );
  1096. static Js::FunctionInfo::Attributes GetFunctionInfoAttributes(ParseNodeFnc * pnodeFnc)
  1097. {
  1098. Js::FunctionInfo::Attributes attributes = Js::FunctionInfo::Attributes::None;
  1099. if (pnodeFnc->IsAsync())
  1100. {
  1101. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::ErrorOnNew | Js::FunctionInfo::Attributes::Async);
  1102. }
  1103. if (pnodeFnc->IsLambda())
  1104. {
  1105. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::ErrorOnNew | Js::FunctionInfo::Attributes::Lambda);
  1106. }
  1107. if (pnodeFnc->HasSuperReference())
  1108. {
  1109. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::SuperReference);
  1110. }
  1111. if (pnodeFnc->IsClassMember())
  1112. {
  1113. if (pnodeFnc->IsClassConstructor())
  1114. {
  1115. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::ClassConstructor);
  1116. if (pnodeFnc->IsBaseClassConstructor())
  1117. {
  1118. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::BaseConstructorKind);
  1119. }
  1120. }
  1121. else
  1122. {
  1123. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::ErrorOnNew | Js::FunctionInfo::Attributes::ClassMethod);
  1124. }
  1125. }
  1126. if (pnodeFnc->IsMethod())
  1127. {
  1128. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::Method);
  1129. }
  1130. if (pnodeFnc->IsGenerator())
  1131. {
  1132. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::Generator);
  1133. }
  1134. if (pnodeFnc->IsAccessor())
  1135. {
  1136. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::ErrorOnNew);
  1137. }
  1138. if (pnodeFnc->IsModule())
  1139. {
  1140. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::Module);
  1141. }
  1142. if (pnodeFnc->CanBeDeferred())
  1143. {
  1144. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::CanDefer);
  1145. }
  1146. if (pnodeFnc->HasComputedName() && pnodeFnc->pnodeName == nullptr)
  1147. {
  1148. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::ComputedName);
  1149. }
  1150. if (pnodeFnc->HasHomeObj())
  1151. {
  1152. attributes = (Js::FunctionInfo::Attributes)(attributes | Js::FunctionInfo::Attributes::HomeObj);
  1153. }
  1154. return attributes;
  1155. }
  1156. FuncInfo * ByteCodeGenerator::StartBindFunction(const char16 *name, uint nameLength, uint shortNameOffset, bool* pfuncExprWithName, ParseNodeFnc *pnodeFnc, Js::ParseableFunctionInfo * reuseNestedFunc)
  1157. {
  1158. bool funcExprWithName;
  1159. Js::ParseableFunctionInfo* parseableFunctionInfo = nullptr;
  1160. Js::AutoRestoreFunctionInfo autoRestoreFunctionInfo(reuseNestedFunc, reuseNestedFunc ? reuseNestedFunc->GetOriginalEntryPoint_Unchecked() : nullptr);
  1161. if (this->pCurrentFunction &&
  1162. this->pCurrentFunction->IsFunctionParsed())
  1163. {
  1164. Assert(this->pCurrentFunction->StartInDocument() == pnodeFnc->ichMin);
  1165. Assert(this->pCurrentFunction->LengthInChars() == pnodeFnc->LengthInCodepoints());
  1166. // This is the root function for the current AST subtree, and it already has a FunctionBody
  1167. // (created by a deferred parse) which we're now filling in.
  1168. Js::FunctionBody * parsedFunctionBody = this->pCurrentFunction;
  1169. parsedFunctionBody->RemoveDeferParseAttribute();
  1170. Assert(!parsedFunctionBody->IsDeferredParseFunction() || parsedFunctionBody->IsReparsed());
  1171. pnodeFnc->SetDeclaration(parsedFunctionBody->GetIsDeclaration());
  1172. if (!pnodeFnc->CanBeDeferred())
  1173. {
  1174. parsedFunctionBody->SetAttributes(
  1175. (Js::FunctionInfo::Attributes)(parsedFunctionBody->GetAttributes() & ~Js::FunctionInfo::Attributes::CanDefer));
  1176. }
  1177. funcExprWithName =
  1178. !(parsedFunctionBody->GetIsDeclaration() || pnodeFnc->IsMethod()) &&
  1179. pnodeFnc->pnodeName != nullptr &&
  1180. pnodeFnc->pnodeName->nop == knopVarDecl;
  1181. *pfuncExprWithName = funcExprWithName;
  1182. Assert(parsedFunctionBody->GetLocalFunctionId() == pnodeFnc->functionId || !IsInNonDebugMode());
  1183. // Some state may be tracked on the function body during the visit pass. Since the previous visit pass may have failed,
  1184. // we need to reset the state on the function body.
  1185. parsedFunctionBody->ResetByteCodeGenVisitState();
  1186. if (parsedFunctionBody->GetScopeInfo())
  1187. {
  1188. // Propagate flags from the (real) parent function.
  1189. Js::ParseableFunctionInfo *parent = parsedFunctionBody->GetScopeInfo()->GetParseableFunctionInfo();
  1190. if (parent)
  1191. {
  1192. if (parent->GetHasOrParentHasArguments())
  1193. {
  1194. parsedFunctionBody->SetHasOrParentHasArguments(true);
  1195. }
  1196. }
  1197. }
  1198. parseableFunctionInfo = parsedFunctionBody;
  1199. }
  1200. else
  1201. {
  1202. funcExprWithName = *pfuncExprWithName;
  1203. Js::LocalFunctionId functionId = pnodeFnc->functionId;
  1204. // Create a function body if:
  1205. // 1. The parse node is not defer parsed
  1206. // 2. Or creating function proxies is disallowed
  1207. bool createFunctionBody = (pnodeFnc->pnodeBody != nullptr);
  1208. if (!CONFIG_FLAG(CreateFunctionProxy)) createFunctionBody = true;
  1209. const Js::FunctionInfo::Attributes attributes = GetFunctionInfoAttributes(pnodeFnc);
  1210. if (createFunctionBody)
  1211. {
  1212. if (reuseNestedFunc)
  1213. {
  1214. if (!reuseNestedFunc->IsFunctionBody())
  1215. {
  1216. reuseNestedFunc->GetUtf8SourceInfo()->StopTrackingDeferredFunction(reuseNestedFunc->GetLocalFunctionId());
  1217. Js::FunctionBody * parsedFunctionBody =
  1218. Js::FunctionBody::NewFromParseableFunctionInfo(reuseNestedFunc->GetParseableFunctionInfo());
  1219. autoRestoreFunctionInfo.funcBody = parsedFunctionBody;
  1220. parseableFunctionInfo = parsedFunctionBody;
  1221. }
  1222. else
  1223. {
  1224. parseableFunctionInfo = reuseNestedFunc->GetFunctionBody();
  1225. }
  1226. Assert((parseableFunctionInfo->GetAttributes() & StableFunctionInfoAttributesMask) == (attributes & StableFunctionInfoAttributesMask));
  1227. }
  1228. else
  1229. {
  1230. parseableFunctionInfo = Js::FunctionBody::NewFromRecycler(scriptContext, name, nameLength, shortNameOffset, pnodeFnc->nestedCount, m_utf8SourceInfo,
  1231. m_utf8SourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId, functionId
  1232. , attributes
  1233. , pnodeFnc->IsClassConstructor() ?
  1234. Js::FunctionBody::FunctionBodyFlags::Flags_None :
  1235. Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue
  1236. #ifdef PERF_COUNTERS
  1237. , false /* is function from deferred deserialized proxy */
  1238. #endif
  1239. );
  1240. }
  1241. }
  1242. else
  1243. {
  1244. if (reuseNestedFunc)
  1245. {
  1246. Assert(!reuseNestedFunc->IsFunctionBody() || reuseNestedFunc->GetFunctionBody()->GetByteCode() != nullptr);
  1247. Assert(pnodeFnc->pnodeBody == nullptr);
  1248. parseableFunctionInfo = reuseNestedFunc;
  1249. Assert((parseableFunctionInfo->GetAttributes() & StableFunctionInfoAttributesMask) == (attributes & StableFunctionInfoAttributesMask));
  1250. }
  1251. else
  1252. {
  1253. parseableFunctionInfo = Js::ParseableFunctionInfo::New(scriptContext, pnodeFnc->nestedCount, functionId, m_utf8SourceInfo, name, nameLength, shortNameOffset, attributes,
  1254. pnodeFnc->IsClassConstructor() ?
  1255. Js::FunctionBody::FunctionBodyFlags::Flags_None :
  1256. Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue);
  1257. }
  1258. }
  1259. // In either case register the function reference
  1260. scriptContext->GetLibrary()->RegisterDynamicFunctionReference(parseableFunctionInfo);
  1261. #if DBG
  1262. parseableFunctionInfo->deferredParseNextFunctionId = pnodeFnc->deferredParseNextFunctionId;
  1263. #endif
  1264. parseableFunctionInfo->SetIsDeclaration(pnodeFnc->IsDeclaration() != 0);
  1265. parseableFunctionInfo->SetIsMethod(pnodeFnc->IsMethod() != 0);
  1266. parseableFunctionInfo->SetIsAccessor(pnodeFnc->IsAccessor() != 0);
  1267. if (pnodeFnc->IsAccessor())
  1268. {
  1269. scriptContext->optimizationOverrides.SetSideEffects(Js::SideEffects_Accessor);
  1270. }
  1271. }
  1272. Scope *funcExprScope = nullptr;
  1273. if (funcExprWithName)
  1274. {
  1275. funcExprScope = pnodeFnc->scope;
  1276. Assert(funcExprScope);
  1277. PushScope(funcExprScope);
  1278. Symbol *sym = AddSymbolToScope(funcExprScope, name, nameLength, pnodeFnc->pnodeName, STFunction);
  1279. sym->SetIsFuncExpr(true);
  1280. sym->SetPosition(parseableFunctionInfo->GetOrAddPropertyIdTracked(sym->GetName()));
  1281. pnodeFnc->SetFuncSymbol(sym);
  1282. if (funcExprScope->GetIsObject())
  1283. {
  1284. funcExprScope->SetMustInstantiate(true);
  1285. }
  1286. }
  1287. Scope *paramScope = pnodeFnc->pnodeScopes ? pnodeFnc->pnodeScopes->scope : nullptr;
  1288. Scope *bodyScope = pnodeFnc->pnodeBodyScope ? pnodeFnc->pnodeBodyScope->scope : nullptr;
  1289. Assert(paramScope != nullptr || !pnodeFnc->pnodeScopes);
  1290. if (paramScope == nullptr)
  1291. {
  1292. paramScope = Anew(alloc, Scope, alloc, ScopeType_Parameter, true);
  1293. if (pnodeFnc->pnodeScopes)
  1294. {
  1295. pnodeFnc->pnodeScopes->scope = paramScope;
  1296. }
  1297. }
  1298. if (bodyScope == nullptr)
  1299. {
  1300. bodyScope = Anew(alloc, Scope, alloc, ScopeType_FunctionBody, true);
  1301. if (pnodeFnc->pnodeBodyScope)
  1302. {
  1303. pnodeFnc->pnodeBodyScope->scope = bodyScope;
  1304. }
  1305. }
  1306. AssertMsg(pnodeFnc->nop == knopFncDecl, "Non-function declaration trying to create function body");
  1307. parseableFunctionInfo->SetIsGlobalFunc(false);
  1308. if (pnodeFnc->GetStrictMode() != 0)
  1309. {
  1310. parseableFunctionInfo->SetIsStrictMode();
  1311. }
  1312. FuncInfo *funcInfo = Anew(alloc, FuncInfo, name, alloc, this, paramScope, bodyScope, pnodeFnc, parseableFunctionInfo);
  1313. #if DBG
  1314. funcInfo->isReused = (reuseNestedFunc != nullptr);
  1315. #endif
  1316. if (pnodeFnc->GetArgumentsObjectEscapes())
  1317. {
  1318. // If the parser detected that the arguments object escapes, then the function scope escapes
  1319. // and cannot be cached.
  1320. this->FuncEscapes(bodyScope);
  1321. funcInfo->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("ArgumentsObjectEscapes")));
  1322. }
  1323. if (parseableFunctionInfo->IsFunctionBody())
  1324. {
  1325. Js::FunctionBody * parsedFunctionBody = parseableFunctionInfo->GetFunctionBody();
  1326. if (parsedFunctionBody->IsReparsed())
  1327. {
  1328. parsedFunctionBody->RestoreState(pnodeFnc);
  1329. }
  1330. else
  1331. {
  1332. parsedFunctionBody->SaveState(pnodeFnc);
  1333. }
  1334. }
  1335. funcInfo->SetChildCallsEval(!!pnodeFnc->ChildCallsEval());
  1336. if (pnodeFnc->CallsEval())
  1337. {
  1338. funcInfo->SetCallsEval(true);
  1339. bodyScope->SetIsDynamic(true);
  1340. bodyScope->SetIsObject();
  1341. bodyScope->SetCapturesAll(true);
  1342. bodyScope->SetMustInstantiate(true);
  1343. // Do not mark param scope as dynamic as it does not leak declarations
  1344. paramScope->SetIsObject();
  1345. paramScope->SetCapturesAll(true);
  1346. paramScope->SetMustInstantiate(true);
  1347. }
  1348. PushFuncInfo(_u("StartBindFunction"), funcInfo);
  1349. if (funcExprScope)
  1350. {
  1351. funcExprScope->SetFunc(funcInfo);
  1352. funcInfo->funcExprScope = funcExprScope;
  1353. }
  1354. int32 currentAstSize = pnodeFnc->astSize;
  1355. if (currentAstSize > this->maxAstSize)
  1356. {
  1357. this->maxAstSize = currentAstSize;
  1358. }
  1359. autoRestoreFunctionInfo.Clear();
  1360. if (!pnodeFnc->IsBodyAndParamScopeMerged())
  1361. {
  1362. funcInfo->ResetBodyAndParamScopeMerged();
  1363. }
  1364. return funcInfo;
  1365. }
  1366. void ByteCodeGenerator::EndBindFunction(bool funcExprWithName)
  1367. {
  1368. bool isGlobalScope = currentScope->GetScopeType() == ScopeType_Global;
  1369. Assert(currentScope->GetScopeType() == ScopeType_FunctionBody || isGlobalScope);
  1370. PopScope(); // function body
  1371. if (isGlobalScope)
  1372. {
  1373. Assert(currentScope == nullptr);
  1374. }
  1375. else
  1376. {
  1377. Assert(currentScope->GetScopeType() == ScopeType_Parameter);
  1378. PopScope(); // parameter scope
  1379. }
  1380. if (funcExprWithName)
  1381. {
  1382. Assert(currentScope->GetScopeType() == ScopeType_FuncExpr);
  1383. PopScope();
  1384. }
  1385. funcInfoStack->Pop();
  1386. }
  1387. void ByteCodeGenerator::StartBindCatch(ParseNode *pnode)
  1388. {
  1389. Scope *scope = pnode->AsParseNodeCatch()->scope;
  1390. Assert(scope);
  1391. Assert(currentScope);
  1392. scope->SetFunc(currentScope->GetFunc());
  1393. PushScope(scope);
  1394. }
  1395. void ByteCodeGenerator::EndBindCatch()
  1396. {
  1397. PopScope();
  1398. }
  1399. void ByteCodeGenerator::PushScope(Scope *innerScope)
  1400. {
  1401. Assert(innerScope != nullptr);
  1402. innerScope->SetEnclosingScope(currentScope);
  1403. currentScope = innerScope;
  1404. if (currentScope->GetIsDynamic())
  1405. {
  1406. this->dynamicScopeCount++;
  1407. }
  1408. if (this->trackEnvDepth && currentScope->GetMustInstantiate())
  1409. {
  1410. this->envDepth++;
  1411. if (this->envDepth == 0)
  1412. {
  1413. Js::Throw::OutOfMemory();
  1414. }
  1415. }
  1416. }
  1417. void ByteCodeGenerator::PopScope()
  1418. {
  1419. Assert(currentScope != nullptr);
  1420. if (this->trackEnvDepth && currentScope->GetMustInstantiate())
  1421. {
  1422. this->envDepth--;
  1423. Assert(this->envDepth != (uint16)-1);
  1424. }
  1425. if (currentScope->GetIsDynamic())
  1426. {
  1427. this->dynamicScopeCount--;
  1428. }
  1429. currentScope = currentScope->GetEnclosingScope();
  1430. }
  1431. void ByteCodeGenerator::PushBlock(ParseNodeBlock *pnode)
  1432. {
  1433. pnode->SetEnclosingBlock(currentBlock);
  1434. currentBlock = pnode;
  1435. }
  1436. void ByteCodeGenerator::PopBlock()
  1437. {
  1438. currentBlock = currentBlock->GetEnclosingBlock();
  1439. }
  1440. void ByteCodeGenerator::PushFuncInfo(char16 const * location, FuncInfo* funcInfo)
  1441. {
  1442. // We might have multiple global scope for deferparse.
  1443. // Assert(!funcInfo->IsGlobalFunction() || this->TopFuncInfo() == nullptr || this->TopFuncInfo()->IsGlobalFunction());
  1444. if (PHASE_TRACE1(Js::ByteCodePhase))
  1445. {
  1446. Output::Print(_u("%s: PushFuncInfo: %s"), location, funcInfo->name);
  1447. if (this->TopFuncInfo())
  1448. {
  1449. Output::Print(_u(" Top: %s"), this->TopFuncInfo()->name);
  1450. }
  1451. Output::Print(_u("\n"));
  1452. Output::Flush();
  1453. }
  1454. funcInfoStack->Push(funcInfo);
  1455. }
  1456. void ByteCodeGenerator::PopFuncInfo(char16 const * location)
  1457. {
  1458. FuncInfo * funcInfo = funcInfoStack->Pop();
  1459. // Assert(!funcInfo->IsGlobalFunction() || this->TopFuncInfo() == nullptr || this->TopFuncInfo()->IsGlobalFunction());
  1460. if (PHASE_TRACE1(Js::ByteCodePhase))
  1461. {
  1462. Output::Print(_u("%s: PopFuncInfo: %s"), location, funcInfo->name);
  1463. if (this->TopFuncInfo())
  1464. {
  1465. Output::Print(_u(" Top: %s"), this->TopFuncInfo()->name);
  1466. }
  1467. Output::Print(_u("\n"));
  1468. Output::Flush();
  1469. }
  1470. }
  1471. Symbol * ByteCodeGenerator::FindSymbol(Symbol **symRef, IdentPtr pid, bool forReference)
  1472. {
  1473. const char16 *key = nullptr;
  1474. Symbol *sym = nullptr;
  1475. Assert(symRef);
  1476. if (*symRef)
  1477. {
  1478. sym = *symRef;
  1479. }
  1480. else
  1481. {
  1482. this->AssignPropertyId(pid);
  1483. return nullptr;
  1484. }
  1485. key = reinterpret_cast<const char16*>(sym->GetPid()->Psz());
  1486. Scope *symScope = sym->GetScope();
  1487. Assert(symScope);
  1488. #if DBG_DUMP
  1489. if (this->Trace())
  1490. {
  1491. if (sym != nullptr)
  1492. {
  1493. Output::Print(_u("resolved %s to symbol of type %s: \n"), key, sym->GetSymbolTypeName());
  1494. }
  1495. else
  1496. {
  1497. Output::Print(_u("did not resolve %s\n"), key);
  1498. }
  1499. }
  1500. #endif
  1501. if (!sym->GetIsGlobal() && !sym->GetIsModuleExportStorage())
  1502. {
  1503. FuncInfo *top = funcInfoStack->Top();
  1504. bool nonLocalRef = symScope->GetFunc() != top;
  1505. Scope *scope = nullptr;
  1506. if (forReference)
  1507. {
  1508. Js::PropertyId i;
  1509. scope = FindScopeForSym(symScope, nullptr, &i, top);
  1510. // If we have a reference to a local within a with, we want to generate a closure represented by an object.
  1511. if (scope != symScope && scope->GetIsDynamic())
  1512. {
  1513. nonLocalRef = true;
  1514. sym->SetHasNonLocalReference();
  1515. symScope->SetIsObject();
  1516. }
  1517. }
  1518. // This may not be a non-local reference, but the symbol may still be accessed non-locally. ('with', e.g.)
  1519. // In that case, make sure we still process the symbol and its scope for closure capture.
  1520. if (nonLocalRef || sym->GetHasNonLocalReference())
  1521. {
  1522. // Symbol referenced through a closure. Mark it as such and give it a property ID.
  1523. this->ProcessCapturedSym(sym);
  1524. sym->SetPosition(top->byteCodeFunction->GetOrAddPropertyIdTracked(sym->GetName()));
  1525. // If this is var is local to a function (meaning that it belongs to the function's scope
  1526. // *or* to scope that need not be instantiated, like a function expression scope, which we'll
  1527. // merge with the function scope, then indicate that fact.
  1528. this->ProcessScopeWithCapturedSym(symScope);
  1529. if (symScope->GetFunc()->GetHasArguments() && sym->GetIsFormal())
  1530. {
  1531. // A formal is referenced non-locally. We need to allocate it on the heap, so
  1532. // do the same for the whole arguments object.
  1533. // Formal is referenced. So count of formals to function > 0.
  1534. // So no need to check for inParams here.
  1535. symScope->GetFunc()->SetHasHeapArguments(true);
  1536. }
  1537. if (symScope->GetFunc() != top)
  1538. {
  1539. top->SetHasClosureReference(true);
  1540. }
  1541. }
  1542. else if (!nonLocalRef && sym->GetHasNonLocalReference() && !sym->GetIsCommittedToSlot() && !sym->HasVisitedCapturingFunc())
  1543. {
  1544. sym->SetHasNonCommittedReference(true);
  1545. }
  1546. if (sym->GetIsFuncExpr())
  1547. {
  1548. symScope->GetFunc()->SetFuncExprNameReference(true);
  1549. }
  1550. }
  1551. return sym;
  1552. }
  1553. Symbol * ByteCodeGenerator::AddSymbolToScope(Scope *scope, const char16 *key, int keyLength, ParseNode *varDecl, SymbolType symbolType)
  1554. {
  1555. Symbol *sym = nullptr;
  1556. switch (varDecl->nop)
  1557. {
  1558. case knopConstDecl:
  1559. case knopLetDecl:
  1560. case knopVarDecl:
  1561. sym = varDecl->AsParseNodeVar()->sym;
  1562. break;
  1563. case knopName:
  1564. AnalysisAssert(varDecl->AsParseNodeName()->GetSymRef());
  1565. sym = *varDecl->AsParseNodeName()->GetSymRef();
  1566. break;
  1567. default:
  1568. AnalysisAssert(0);
  1569. sym = nullptr;
  1570. break;
  1571. }
  1572. if (sym->GetScope() != scope && sym->GetScope()->GetScopeType() != ScopeType_Parameter)
  1573. {
  1574. // This can happen when we have a function declared at global eval scope, and it has
  1575. // references in deferred function bodies inside the eval. The BCG creates a new global scope
  1576. // on such compiles, so we essentially have to migrate the symbol to the new scope.
  1577. // We check fscrEvalCode, not fscrEval, because the same thing can happen in indirect eval,
  1578. // when fscrEval is not set.
  1579. Assert(scope->GetScopeType() == ScopeType_Global || scope->GetScopeType() == ScopeType_GlobalEvalBlock);
  1580. scope->AddNewSymbol(sym);
  1581. }
  1582. Assert(sym && sym->GetScope() && (sym->GetScope() == scope || sym->GetScope()->GetScopeType() == ScopeType_Parameter));
  1583. if (sym->NeedsScopeObject())
  1584. {
  1585. scope->SetIsObject();
  1586. }
  1587. return sym;
  1588. }
  1589. Symbol * ByteCodeGenerator::AddSymbolToFunctionScope(const char16 *key, int keyLength, ParseNode *varDecl, SymbolType symbolType)
  1590. {
  1591. Scope* scope = currentScope->GetFunc()->GetBodyScope();
  1592. return this->AddSymbolToScope(scope, key, keyLength, varDecl, symbolType);
  1593. }
  1594. FuncInfo *ByteCodeGenerator::FindEnclosingNonLambda()
  1595. {
  1596. for (Scope *scope = GetCurrentScope(); scope; scope = scope->GetEnclosingScope())
  1597. {
  1598. if (!scope->GetFunc()->IsLambda())
  1599. {
  1600. return scope->GetFunc();
  1601. }
  1602. }
  1603. Assert(0);
  1604. return nullptr;
  1605. }
  1606. FuncInfo* ByteCodeGenerator::GetParentFuncInfo(FuncInfo* child)
  1607. {
  1608. for (Scope* scope = child->GetBodyScope(); scope; scope = scope->GetEnclosingScope())
  1609. {
  1610. if (scope->GetFunc() != child)
  1611. {
  1612. return scope->GetFunc();
  1613. }
  1614. }
  1615. Assert(0);
  1616. return nullptr;
  1617. }
  1618. FuncInfo* ByteCodeGenerator::GetEnclosingFuncInfo()
  1619. {
  1620. FuncInfo* top = this->funcInfoStack->Pop();
  1621. Assert(!this->funcInfoStack->Empty());
  1622. FuncInfo* second = this->funcInfoStack->Top();
  1623. this->funcInfoStack->Push(top);
  1624. return second;
  1625. }
  1626. bool ByteCodeGenerator::CanStackNestedFunc(FuncInfo * funcInfo, bool trace)
  1627. {
  1628. #if ENABLE_DEBUG_CONFIG_OPTIONS
  1629. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  1630. #endif
  1631. Assert(!funcInfo->IsGlobalFunction());
  1632. bool const doStackNestedFunc = !funcInfo->HasMaybeEscapedNestedFunc() && !IsInDebugMode()
  1633. && !funcInfo->byteCodeFunction->IsCoroutine()
  1634. && !funcInfo->byteCodeFunction->IsModule()
  1635. && !Js::ScriptContext::ExceedsStackNestedFuncCount(funcInfo->root->nestedCount);
  1636. if (!doStackNestedFunc)
  1637. {
  1638. return false;
  1639. }
  1640. bool callsEval = funcInfo->GetCallsEval() || funcInfo->GetChildCallsEval();
  1641. if (callsEval)
  1642. {
  1643. if (trace)
  1644. {
  1645. PHASE_PRINT_TESTTRACE(Js::StackFuncPhase, funcInfo->byteCodeFunction,
  1646. _u("HasMaybeEscapedNestedFunc (Eval): %s (function %s)\n"),
  1647. funcInfo->byteCodeFunction->GetDisplayName(),
  1648. funcInfo->byteCodeFunction->GetDebugNumberSet(debugStringBuffer));
  1649. }
  1650. return false;
  1651. }
  1652. if (funcInfo->GetBodyScope()->GetIsObject() || funcInfo->GetParamScope()->GetIsObject() || (funcInfo->GetFuncExprScope() && funcInfo->GetFuncExprScope()->GetIsObject()))
  1653. {
  1654. if (trace)
  1655. {
  1656. PHASE_PRINT_TESTTRACE(Js::StackFuncPhase, funcInfo->byteCodeFunction,
  1657. _u("HasMaybeEscapedNestedFunc (ObjectScope): %s (function %s)\n"),
  1658. funcInfo->byteCodeFunction->GetDisplayName(),
  1659. funcInfo->byteCodeFunction->GetDebugNumberSet(debugStringBuffer));
  1660. }
  1661. return false;
  1662. }
  1663. if (!funcInfo->IsBodyAndParamScopeMerged())
  1664. {
  1665. if (trace)
  1666. {
  1667. PHASE_PRINT_TESTTRACE(Js::StackFuncPhase, funcInfo->byteCodeFunction,
  1668. _u("CanStackNestedFunc: %s (Split Scope)\n"),
  1669. funcInfo->byteCodeFunction->GetDisplayName());
  1670. }
  1671. return false;
  1672. }
  1673. if (trace && funcInfo->byteCodeFunction->GetNestedCount())
  1674. {
  1675. // Only print functions that actually have nested functions, although we will still mark
  1676. // functions that don't have nested child functions as DoStackNestedFunc.
  1677. PHASE_PRINT_TESTTRACE(Js::StackFuncPhase, funcInfo->byteCodeFunction,
  1678. _u("DoStackNestedFunc: %s (function %s)\n"),
  1679. funcInfo->byteCodeFunction->GetDisplayName(),
  1680. funcInfo->byteCodeFunction->GetDebugNumberSet(debugStringBuffer));
  1681. }
  1682. return !PHASE_OFF(Js::StackFuncPhase, funcInfo->byteCodeFunction);
  1683. }
  1684. bool ByteCodeGenerator::NeedObjectAsFunctionScope(FuncInfo * funcInfo, ParseNodeFnc * pnodeFnc) const
  1685. {
  1686. return funcInfo->GetCallsEval()
  1687. || funcInfo->GetChildCallsEval()
  1688. || NeedScopeObjectForArguments(funcInfo, pnodeFnc)
  1689. || (this->flags & (fscrEval | fscrImplicitThis));
  1690. }
  1691. Scope * ByteCodeGenerator::FindScopeForSym(Scope *symScope, Scope *scope, Js::PropertyId *envIndex, FuncInfo *funcInfo) const
  1692. {
  1693. for (scope = scope ? scope->GetEnclosingScope() : currentScope; scope; scope = scope->GetEnclosingScope())
  1694. {
  1695. if (scope->GetFunc() != funcInfo
  1696. && scope->GetMustInstantiate()
  1697. && scope != this->globalScope)
  1698. {
  1699. (*envIndex)++;
  1700. }
  1701. if (scope == symScope || scope->GetIsDynamic())
  1702. {
  1703. break;
  1704. }
  1705. }
  1706. Assert(scope);
  1707. return scope;
  1708. }
  1709. /* static */
  1710. Js::OpCode ByteCodeGenerator::GetStFldOpCode(FuncInfo* funcInfo, bool isRoot, bool isLetDecl, bool isConstDecl, bool isClassMemberInit)
  1711. {
  1712. return GetStFldOpCode(funcInfo->GetIsStrictMode(), isRoot, isLetDecl, isConstDecl, isClassMemberInit);
  1713. }
  1714. /* static */
  1715. Js::OpCode ByteCodeGenerator::GetScopedStFldOpCode(FuncInfo* funcInfo, bool isConsoleScopeLetConst)
  1716. {
  1717. return GetScopedStFldOpCode(funcInfo->GetIsStrictMode(), isConsoleScopeLetConst);
  1718. }
  1719. /* static */
  1720. Js::OpCode ByteCodeGenerator::GetStElemIOpCode(FuncInfo* funcInfo)
  1721. {
  1722. return GetStElemIOpCode(funcInfo->GetIsStrictMode());
  1723. }
  1724. bool ByteCodeGenerator::DoJitLoopBodies(FuncInfo *funcInfo) const
  1725. {
  1726. // Never JIT loop bodies in a function with a try.
  1727. // Otherwise, always JIT loop bodies under /forcejitloopbody.
  1728. // Otherwise, JIT loop bodies unless we're in eval/"new Function" or feature is disabled.
  1729. Assert(funcInfo->byteCodeFunction->IsFunctionParsed());
  1730. Js::FunctionBody* functionBody = funcInfo->byteCodeFunction->GetFunctionBody();
  1731. return functionBody->ForceJITLoopBody() || funcInfo->byteCodeFunction->IsJitLoopBodyPhaseEnabled();
  1732. }
  1733. void ByteCodeGenerator::Generate(__in ParseNodeProg *pnodeProg, uint32 grfscr, __in ByteCodeGenerator* byteCodeGenerator,
  1734. __inout Js::ParseableFunctionInfo ** ppRootFunc, __in uint sourceIndex,
  1735. __in bool forceNoNative, __in Parser* parser, Js::ScriptFunction **functionRef)
  1736. {
  1737. #if DBG
  1738. struct WalkerPolicyTest : public WalkerPolicyBase<bool, ParseNodeWalker<WalkerPolicyTest>*>
  1739. {
  1740. inline bool ContinueWalk(ResultType) { return ThreadContext::IsCurrentStackAvailable(Js::Constants::MinStackByteCodeVisitor); }
  1741. virtual ResultType WalkChild(ParseNode *pnode, ParseNodeWalker<WalkerPolicyTest>* walker) { return ContinueWalk(true) && walker->Walk(pnode, walker); }
  1742. };
  1743. ParseNodeWalker<WalkerPolicyTest> walker;
  1744. // Just walk the ast to see if our walker encounters any problems
  1745. walker.Walk(pnodeProg, &walker);
  1746. #endif
  1747. Js::ScriptContext * scriptContext = byteCodeGenerator->scriptContext;
  1748. #ifdef PROFILE_EXEC
  1749. scriptContext->ProfileBegin(Js::ByteCodePhase);
  1750. #endif
  1751. JS_ETW_INTERNAL(EventWriteJSCRIPT_BYTECODEGEN_START(scriptContext, 0));
  1752. ThreadContext * threadContext = scriptContext->GetThreadContext();
  1753. Js::Utf8SourceInfo * utf8SourceInfo = scriptContext->GetSource(sourceIndex);
  1754. byteCodeGenerator->m_utf8SourceInfo = utf8SourceInfo;
  1755. // For dynamic code, just provide a small number since that source info should have very few functions
  1756. // For static code, the nextLocalFunctionId is a good guess of the initial size of the array to minimize reallocs
  1757. SourceContextInfo * sourceContextInfo = utf8SourceInfo->GetSrcInfo()->sourceContextInfo;
  1758. utf8SourceInfo->EnsureInitialized((grfscr & fscrDynamicCode) ? 4 : (sourceContextInfo->nextLocalFunctionId - pnodeProg->functionId));
  1759. sourceContextInfo->EnsureInitialized();
  1760. ArenaAllocator localAlloc(_u("ByteCode"), threadContext->GetPageAllocator(), Js::Throw::OutOfMemory);
  1761. // Make sure FuncInfo's get finalized when byte code gen is done.
  1762. struct AutoFinalizeFuncInfos {
  1763. AutoFinalizeFuncInfos(ByteCodeGenerator * byteCodeGenerator) : byteCodeGenerator(byteCodeGenerator) {}
  1764. ~AutoFinalizeFuncInfos() {
  1765. if (byteCodeGenerator)
  1766. {
  1767. byteCodeGenerator->FinalizeFuncInfos();
  1768. }
  1769. }
  1770. ByteCodeGenerator * byteCodeGenerator;
  1771. } autoFinalizeFuncInfos(byteCodeGenerator);
  1772. byteCodeGenerator->parser = parser;
  1773. byteCodeGenerator->SetCurrentSourceIndex(sourceIndex);
  1774. byteCodeGenerator->Begin(&localAlloc, grfscr, *ppRootFunc);
  1775. byteCodeGenerator->functionRef = functionRef;
  1776. Visit(pnodeProg, byteCodeGenerator, Bind, AssignRegisters);
  1777. byteCodeGenerator->forceNoNative = forceNoNative;
  1778. byteCodeGenerator->EmitProgram(pnodeProg);
  1779. if (byteCodeGenerator->flags & fscrEval)
  1780. {
  1781. // The eval caller's frame always escapes if eval refers to the caller's arguments.
  1782. byteCodeGenerator->GetRootFunc()->GetFunctionBody()->SetFuncEscapes(
  1783. byteCodeGenerator->funcEscapes || pnodeProg->m_UsesArgumentsAtGlobal);
  1784. }
  1785. #ifdef IR_VIEWER
  1786. if (grfscr & fscrIrDumpEnable)
  1787. {
  1788. byteCodeGenerator->GetRootFunc()->GetFunctionBody()->SetIRDumpEnabled(true);
  1789. }
  1790. #endif /* IR_VIEWER */
  1791. byteCodeGenerator->CheckDeferParseHasMaybeEscapedNestedFunc();
  1792. #ifdef PROFILE_EXEC
  1793. scriptContext->ProfileEnd(Js::ByteCodePhase);
  1794. #endif
  1795. JS_ETW_INTERNAL(EventWriteJSCRIPT_BYTECODEGEN_STOP(scriptContext, 0));
  1796. #if ENABLE_NATIVE_CODEGEN && defined(ENABLE_PREJIT)
  1797. if (!byteCodeGenerator->forceNoNative && !scriptContext->GetConfig()->IsNoNative()
  1798. && Js::Configuration::Global.flags.Prejit
  1799. && (grfscr & fscrNoPreJit) == 0)
  1800. {
  1801. GenerateAllFunctions(scriptContext->GetNativeCodeGenerator(), byteCodeGenerator->GetRootFunc()->GetFunctionBody());
  1802. }
  1803. #endif
  1804. if (ppRootFunc)
  1805. {
  1806. *ppRootFunc = byteCodeGenerator->GetRootFunc();
  1807. }
  1808. #ifdef PERF_COUNTERS
  1809. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: deferparse - # of func: %d # deferparsed: %d\n"),
  1810. PerfCounter::CodeCounterSet::GetTotalFunctionCounter().GetValue(), PerfCounter::CodeCounterSet::GetDeferredFunctionCounter().GetValue());
  1811. #endif
  1812. }
  1813. void ByteCodeGenerator::CheckDeferParseHasMaybeEscapedNestedFunc()
  1814. {
  1815. if (!this->parentScopeInfo)
  1816. {
  1817. return;
  1818. }
  1819. Assert(this->funcInfoStack && !this->funcInfoStack->Empty());
  1820. // Box the stack nested function if we detected new may be escaped use function.
  1821. SList<FuncInfo *>::Iterator i(this->funcInfoStack);
  1822. bool succeed = i.Next();
  1823. Assert(succeed);
  1824. Assert(i.Data()->IsGlobalFunction()); // We always leave a glo on type when defer parsing.
  1825. Assert(!i.Data()->IsRestored());
  1826. succeed = i.Next();
  1827. FuncInfo * top = i.Data();
  1828. Assert(!top->IsGlobalFunction());
  1829. Assert(top->IsRestored());
  1830. Js::FunctionBody * rootFuncBody = this->GetRootFunc()->GetFunctionBody();
  1831. if (!rootFuncBody->DoStackNestedFunc())
  1832. {
  1833. top->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("DeferredChild")));
  1834. }
  1835. else
  1836. {
  1837. // We have to wait until it is parsed before we populate the stack nested func parent.
  1838. FuncInfo * parentFunc = top->GetParamScope() ? top->GetParamScope()->GetEnclosingFunc() : top->GetBodyScope()->GetEnclosingFunc();
  1839. if (!parentFunc->IsGlobalFunction())
  1840. {
  1841. Assert(parentFunc->byteCodeFunction != rootFuncBody);
  1842. Js::ParseableFunctionInfo * parentFunctionInfo = parentFunc->byteCodeFunction;
  1843. if (parentFunctionInfo->DoStackNestedFunc())
  1844. {
  1845. rootFuncBody->SetStackNestedFuncParent(parentFunctionInfo->GetFunctionInfo());
  1846. }
  1847. }
  1848. }
  1849. do
  1850. {
  1851. FuncInfo * funcInfo = i.Data();
  1852. Assert(funcInfo->IsRestored());
  1853. Js::ParseableFunctionInfo * parseableFunctionInfo = funcInfo->byteCodeFunction;
  1854. if (parseableFunctionInfo == nullptr)
  1855. {
  1856. Assert(funcInfo->GetBodyScope() && funcInfo->GetBodyScope()->GetScopeType() == ScopeType_Global);
  1857. return;
  1858. }
  1859. bool didStackNestedFunc = parseableFunctionInfo->DoStackNestedFunc();
  1860. if (!didStackNestedFunc)
  1861. {
  1862. return;
  1863. }
  1864. if (!parseableFunctionInfo->IsFunctionBody())
  1865. {
  1866. continue;
  1867. }
  1868. Js::FunctionBody * functionBody = funcInfo->GetParsedFunctionBody();
  1869. if (funcInfo->HasMaybeEscapedNestedFunc())
  1870. {
  1871. // This should box the rest of the parent functions.
  1872. if (PHASE_TESTTRACE(Js::StackFuncPhase, this->pCurrentFunction))
  1873. {
  1874. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  1875. Output::Print(_u("DeferParse: box and disable stack function: %s (function %s)\n"),
  1876. functionBody->GetDisplayName(), functionBody->GetDebugNumberSet(debugStringBuffer));
  1877. Output::Flush();
  1878. }
  1879. // During the box workflow we reset all the parents of all nested functions and up. If a fault occurs when the stack function
  1880. // is created this will cause further issues when trying to use the function object again. So failing faster seems to make more sense.
  1881. try
  1882. {
  1883. Js::StackScriptFunction::Box(functionBody, functionRef);
  1884. }
  1885. catch (Js::OutOfMemoryException)
  1886. {
  1887. FailedToBox_OOM_unrecoverable_error((ULONG_PTR)functionBody);
  1888. }
  1889. return;
  1890. }
  1891. }
  1892. while (i.Next());
  1893. }
  1894. void ByteCodeGenerator::Begin(
  1895. __in ArenaAllocator *alloc,
  1896. __in uint32 grfscr,
  1897. __in Js::ParseableFunctionInfo* pRootFunc)
  1898. {
  1899. this->alloc = alloc;
  1900. this->flags = grfscr;
  1901. this->pRootFunc = pRootFunc;
  1902. this->pCurrentFunction = pRootFunc ? pRootFunc->GetFunctionBody() : nullptr;
  1903. if (this->pCurrentFunction && this->pCurrentFunction->GetIsGlobalFunc() && IsInNonDebugMode())
  1904. {
  1905. // This is the deferred parse case (not due to debug mode), in which case the global function will not be marked to compiled again.
  1906. this->pCurrentFunction = nullptr;
  1907. }
  1908. this->globalScope = nullptr;
  1909. this->currentScope = nullptr;
  1910. this->currentBlock = nullptr;
  1911. this->isBinding = true;
  1912. this->inPrologue = false;
  1913. this->funcEscapes = false;
  1914. this->maxAstSize = 0;
  1915. this->loopDepth = 0;
  1916. this->envDepth = 0;
  1917. this->trackEnvDepth = false;
  1918. this->funcInfosToFinalize = nullptr;
  1919. this->funcInfoStack = Anew(alloc, SList<FuncInfo*>, alloc);
  1920. }
  1921. HRESULT GenerateByteCode(__in ParseNodeProg *pnode, __in uint32 grfscr, __in Js::ScriptContext* scriptContext, __inout Js::ParseableFunctionInfo ** ppRootFunc,
  1922. __in uint sourceIndex, __in bool forceNoNative, __in Parser* parser, __in CompileScriptException *pse, Js::ScopeInfo* parentScopeInfo,
  1923. Js::ScriptFunction ** functionRef)
  1924. {
  1925. HRESULT hr = S_OK;
  1926. ByteCodeGenerator byteCodeGenerator(scriptContext, parentScopeInfo);
  1927. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT_NESTED
  1928. {
  1929. // Main code.
  1930. ByteCodeGenerator::Generate(pnode, grfscr, &byteCodeGenerator, ppRootFunc, sourceIndex, forceNoNative, parser, functionRef);
  1931. }
  1932. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  1933. if (FAILED(hr))
  1934. {
  1935. hr = pse->ProcessError(nullptr, hr, nullptr);
  1936. }
  1937. return hr;
  1938. }
  1939. void BindInstAndMember(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  1940. {
  1941. Assert(pnode->nop == knopDot);
  1942. BindReference(pnode, byteCodeGenerator);
  1943. ParseNodeName *right = pnode->AsParseNodeBin()->pnode2->AsParseNodeName();
  1944. byteCodeGenerator->AssignPropertyId(right->pid);
  1945. right->sym = nullptr;
  1946. right->ClearSymRef();
  1947. right->grfpn |= fpnMemberReference;
  1948. }
  1949. void BindReference(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  1950. {
  1951. // Do special reference-op binding so that we can, for instance, handle call from inside "with"
  1952. // where the "this" instance must be found dynamically.
  1953. bool isCallNode = false;
  1954. bool funcEscapes = false;
  1955. switch (pnode->nop)
  1956. {
  1957. case knopCall:
  1958. isCallNode = true;
  1959. pnode = pnode->AsParseNodeCall()->pnodeTarget;
  1960. break;
  1961. case knopDelete:
  1962. case knopTypeof:
  1963. pnode = pnode->AsParseNodeUni()->pnode1;
  1964. break;
  1965. case knopDot:
  1966. case knopIndex:
  1967. funcEscapes = true;
  1968. // fall through
  1969. case knopAsg:
  1970. pnode = pnode->AsParseNodeBin()->pnode1;
  1971. break;
  1972. default:
  1973. AssertMsg(0, "Unexpected opcode in BindReference");
  1974. return;
  1975. }
  1976. if (pnode->nop == knopName)
  1977. {
  1978. ParseNodeName * pnodeName = pnode->AsParseNodeName();
  1979. pnodeName->sym = byteCodeGenerator->FindSymbol(pnodeName->GetSymRef(), pnodeName->pid, isCallNode);
  1980. if (funcEscapes &&
  1981. pnodeName->sym &&
  1982. pnodeName->sym->GetSymbolType() == STFunction &&
  1983. (!pnodeName->sym->GetIsGlobal() || (byteCodeGenerator->GetFlags() & fscrEval)))
  1984. {
  1985. // Dot, index, and scope ops can cause a local function on the LHS to escape.
  1986. // Make sure scopes are not cached in this case.
  1987. byteCodeGenerator->FuncEscapes(pnodeName->sym->GetScope());
  1988. }
  1989. }
  1990. }
  1991. void MarkFormal(ByteCodeGenerator *byteCodeGenerator, Symbol *formal, bool assignLocation, bool needDeclaration)
  1992. {
  1993. if (assignLocation)
  1994. {
  1995. formal->SetLocation(byteCodeGenerator->NextVarRegister());
  1996. }
  1997. if (needDeclaration)
  1998. {
  1999. formal->SetNeedDeclaration(true);
  2000. }
  2001. }
  2002. void AddArgsToScope(ParseNodeFnc * pnodeFnc, ByteCodeGenerator *byteCodeGenerator, bool assignLocation)
  2003. {
  2004. Assert(byteCodeGenerator->TopFuncInfo()->varRegsCount == 0);
  2005. Js::ArgSlot pos = 1;
  2006. bool isNonSimpleParameterList = pnodeFnc->HasNonSimpleParameterList();
  2007. auto addArgToScope = [&](ParseNode *arg)
  2008. {
  2009. if (arg->IsVarLetOrConst())
  2010. {
  2011. ParseNodeVar * pnodeVarArg = arg->AsParseNodeVar();
  2012. Symbol *formal = byteCodeGenerator->AddSymbolToScope(byteCodeGenerator->TopFuncInfo()->GetParamScope(),
  2013. reinterpret_cast<const char16*>(pnodeVarArg->pid->Psz()),
  2014. pnodeVarArg->pid->Cch(),
  2015. pnodeVarArg,
  2016. STFormal);
  2017. #if DBG_DUMP
  2018. if (byteCodeGenerator->Trace())
  2019. {
  2020. Output::Print(_u("current context has declared arg %s of type %s at position %d\n"), arg->AsParseNodeVar()->pid->Psz(), formal->GetSymbolTypeName(), pos);
  2021. }
  2022. #endif
  2023. if (isNonSimpleParameterList)
  2024. {
  2025. formal->SetIsNonSimpleParameter(true);
  2026. }
  2027. pnodeVarArg->sym = formal;
  2028. MarkFormal(byteCodeGenerator, formal, assignLocation || isNonSimpleParameterList, isNonSimpleParameterList);
  2029. }
  2030. else if (arg->nop == knopParamPattern)
  2031. {
  2032. arg->AsParseNodeParamPattern()->location = byteCodeGenerator->NextVarRegister();
  2033. }
  2034. else
  2035. {
  2036. Assert(false);
  2037. }
  2038. ArgSlotMath::Inc(pos);
  2039. };
  2040. // We process rest separately because the number of in args needs to exclude rest.
  2041. MapFormalsWithoutRest(pnodeFnc, addArgToScope);
  2042. byteCodeGenerator->SetNumberOfInArgs(pos);
  2043. if (pnodeFnc->pnodeRest != nullptr)
  2044. {
  2045. // The rest parameter will always be in a register, regardless of whether it is in a scope slot.
  2046. // We save the assignLocation value for the assert condition below.
  2047. bool assignLocationSave = assignLocation;
  2048. assignLocation = true;
  2049. addArgToScope(pnodeFnc->pnodeRest);
  2050. assignLocation = assignLocationSave;
  2051. }
  2052. MapFormalsFromPattern(pnodeFnc, addArgToScope);
  2053. Assert(!assignLocation || byteCodeGenerator->TopFuncInfo()->varRegsCount + 1 == pos);
  2054. }
  2055. void AddVarsToScope(ParseNode *vars, ByteCodeGenerator *byteCodeGenerator)
  2056. {
  2057. while (vars != nullptr)
  2058. {
  2059. Symbol *sym = byteCodeGenerator->AddSymbolToFunctionScope(reinterpret_cast<const char16*>(vars->AsParseNodeVar()->pid->Psz()), vars->AsParseNodeVar()->pid->Cch(), vars, STVariable);
  2060. #if DBG_DUMP
  2061. if (sym->GetSymbolType() == STVariable && byteCodeGenerator->Trace())
  2062. {
  2063. Output::Print(_u("current context has declared var %s of type %s\n"),
  2064. vars->AsParseNodeVar()->pid->Psz(), sym->GetSymbolTypeName());
  2065. }
  2066. #endif
  2067. if (sym->IsArguments() || sym->IsSpecialSymbol() || vars->AsParseNodeVar()->pnodeInit == nullptr)
  2068. {
  2069. // LHS's of var decls are usually bound to symbols later, during the Visit/Bind pass,
  2070. // so that things like catch scopes can be taken into account.
  2071. // The exception is "arguments", which always binds to the local scope.
  2072. // We can also bind to the function scope symbol now if there's no init value
  2073. // to assign.
  2074. vars->AsParseNodeVar()->sym = sym;
  2075. if (sym->IsArguments())
  2076. {
  2077. FuncInfo* funcInfo = byteCodeGenerator->TopFuncInfo();
  2078. funcInfo->SetArgumentsSymbol(sym);
  2079. }
  2080. else if (sym->IsSpecialSymbol())
  2081. {
  2082. FuncInfo* funcInfo = byteCodeGenerator->TopFuncInfo();
  2083. if (sym->IsThis())
  2084. {
  2085. funcInfo->SetThisSymbol(sym);
  2086. }
  2087. else if (sym->IsNewTarget())
  2088. {
  2089. funcInfo->SetNewTargetSymbol(sym);
  2090. }
  2091. else if (sym->IsSuper())
  2092. {
  2093. funcInfo->SetSuperSymbol(sym);
  2094. }
  2095. else if (sym->IsSuperConstructor())
  2096. {
  2097. funcInfo->SetSuperConstructorSymbol(sym);
  2098. }
  2099. }
  2100. }
  2101. else
  2102. {
  2103. vars->AsParseNodeVar()->sym = nullptr;
  2104. }
  2105. vars = vars->AsParseNodeVar()->pnodeNext;
  2106. }
  2107. }
  2108. template <class Fn>
  2109. void VisitFncDecls(ParseNode *fns, Fn action)
  2110. {
  2111. while (fns != nullptr)
  2112. {
  2113. switch (fns->nop)
  2114. {
  2115. case knopFncDecl:
  2116. action(fns);
  2117. fns = fns->AsParseNodeFnc()->pnodeNext;
  2118. break;
  2119. case knopBlock:
  2120. fns = fns->AsParseNodeBlock()->pnodeNext;
  2121. break;
  2122. case knopCatch:
  2123. fns = fns->AsParseNodeCatch()->pnodeNext;
  2124. break;
  2125. case knopWith:
  2126. fns = fns->AsParseNodeWith()->pnodeNext;
  2127. break;
  2128. default:
  2129. AssertMsg(false, "Unexpected opcode in tree of scopes");
  2130. return;
  2131. }
  2132. }
  2133. }
  2134. FuncInfo* PreVisitFunction(ParseNodeFnc* pnodeFnc, ByteCodeGenerator* byteCodeGenerator, Js::ParseableFunctionInfo *reuseNestedFunc)
  2135. {
  2136. // Do binding of function name(s), initialize function scope, propagate function-wide properties from
  2137. // the parent (if any).
  2138. FuncInfo* parentFunc = byteCodeGenerator->TopFuncInfo();
  2139. // fIsRoot indicates that this is the root function to be returned to a ParseProcedureText/AddScriptLet/etc. call.
  2140. // In such cases, the global function is just a wrapper around the root function's declaration.
  2141. // We used to assert that this was the only top-level function body, but it's possible to trick
  2142. // "new Function" into compiling more than one function (see WOOB 1121759).
  2143. bool fIsRoot = (!(byteCodeGenerator->GetFlags() & fscrGlobalCode) &&
  2144. parentFunc->IsGlobalFunction() &&
  2145. parentFunc->root->GetTopLevelScope() == pnodeFnc);
  2146. const char16 *funcName = Js::Constants::AnonymousFunction;
  2147. uint funcNameLength = Js::Constants::AnonymousFunctionLength;
  2148. uint functionNameOffset = 0;
  2149. bool funcExprWithName = false;
  2150. if (pnodeFnc->hint != nullptr)
  2151. {
  2152. funcName = reinterpret_cast<const char16*>(pnodeFnc->hint);
  2153. funcNameLength = pnodeFnc->hintLength;
  2154. functionNameOffset = pnodeFnc->hintOffset;
  2155. Assert(funcNameLength != 0 || funcNameLength == (int)wcslen(funcName));
  2156. }
  2157. if (pnodeFnc->IsDeclaration() || pnodeFnc->IsMethod())
  2158. {
  2159. // Class members have the fully qualified name stored in 'hint', no need to replace it.
  2160. if (pnodeFnc->pid && !pnodeFnc->IsClassMember())
  2161. {
  2162. funcName = reinterpret_cast<const char16*>(pnodeFnc->pid->Psz());
  2163. funcNameLength = pnodeFnc->pid->Cch();
  2164. functionNameOffset = 0;
  2165. }
  2166. }
  2167. else if (pnodeFnc->pnodeName != nullptr)
  2168. {
  2169. Assert(pnodeFnc->pnodeName->nop == knopVarDecl);
  2170. funcName = reinterpret_cast<const char16*>(pnodeFnc->pnodeName->pid->Psz());
  2171. funcNameLength = pnodeFnc->pnodeName->pid->Cch();
  2172. functionNameOffset = 0;
  2173. //
  2174. // create the new scope for Function expression only in ES5 mode
  2175. //
  2176. funcExprWithName = true;
  2177. }
  2178. if (byteCodeGenerator->Trace())
  2179. {
  2180. Output::Print(_u("function start %s\n"), funcName);
  2181. }
  2182. Assert(pnodeFnc->funcInfo == nullptr);
  2183. FuncInfo* funcInfo = pnodeFnc->funcInfo = byteCodeGenerator->StartBindFunction(funcName, funcNameLength, functionNameOffset, &funcExprWithName, pnodeFnc, reuseNestedFunc);
  2184. funcInfo->byteCodeFunction->SetIsNamedFunctionExpression(funcExprWithName);
  2185. funcInfo->byteCodeFunction->SetIsNameIdentifierRef(pnodeFnc->isNameIdentifierRef);
  2186. if (fIsRoot)
  2187. {
  2188. byteCodeGenerator->SetRootFuncInfo(funcInfo);
  2189. }
  2190. if (pnodeFnc->pnodeBody == nullptr)
  2191. {
  2192. // This is a deferred byte code gen, so we're done.
  2193. // Process the formal arguments, even if there's no AST for the body, to support Function.length.
  2194. Js::ArgSlot pos = 1;
  2195. // We skip the rest parameter here because it is not counted towards the in arg count.
  2196. MapFormalsWithoutRest(pnodeFnc, [&](ParseNode *pnode) { ArgSlotMath::Inc(pos); });
  2197. byteCodeGenerator->SetNumberOfInArgs(pos);
  2198. return funcInfo;
  2199. }
  2200. if (pnodeFnc->HasReferenceableBuiltInArguments())
  2201. {
  2202. // The parser identified that there is a way to reference the built-in 'arguments' variable from this function. So, we
  2203. // need to determine whether we need to create the variable or not. We need to create the variable iff:
  2204. if (pnodeFnc->CallsEval())
  2205. {
  2206. // 1. eval is called.
  2207. // 2. when the debugging is enabled, since user can seek arguments during breakpoint.
  2208. funcInfo->SetHasArguments(true);
  2209. funcInfo->SetHasHeapArguments(true);
  2210. if (funcInfo->inArgsCount == 0)
  2211. {
  2212. // If no formals to function, no need to create the propertyid array
  2213. byteCodeGenerator->AssignNullConstRegister();
  2214. }
  2215. }
  2216. else if (pnodeFnc->UsesArguments())
  2217. {
  2218. // 3. the function directly references an 'arguments' identifier
  2219. funcInfo->SetHasArguments(true);
  2220. funcInfo->GetParsedFunctionBody()->SetUsesArgumentsObject(true);
  2221. if (pnodeFnc->HasHeapArguments())
  2222. {
  2223. bool doStackArgsOpt = (!pnodeFnc->HasAnyWriteToFormals() || funcInfo->GetIsStrictMode());
  2224. #ifdef PERF_HINT
  2225. if (PHASE_TRACE1(Js::PerfHintPhase) && !doStackArgsOpt)
  2226. {
  2227. WritePerfHint(PerfHints::HeapArgumentsDueToWriteToFormals, funcInfo->GetParsedFunctionBody(), 0);
  2228. }
  2229. #endif
  2230. //With statements - need scope object to be present.
  2231. if ((doStackArgsOpt && pnodeFnc->funcInfo->GetParamScope()->Count() > 1) && ((byteCodeGenerator->GetFlags() & fscrEval) ||
  2232. pnodeFnc->HasWithStmt() || byteCodeGenerator->IsInDebugMode() || PHASE_OFF1(Js::StackArgFormalsOptPhase) || PHASE_OFF1(Js::StackArgOptPhase)))
  2233. {
  2234. doStackArgsOpt = false;
  2235. #ifdef PERF_HINT
  2236. if (PHASE_TRACE1(Js::PerfHintPhase))
  2237. {
  2238. if (pnodeFnc->HasWithStmt())
  2239. {
  2240. WritePerfHint(PerfHints::HasWithBlock, funcInfo->GetParsedFunctionBody(), 0);
  2241. }
  2242. if(byteCodeGenerator->GetFlags() & fscrEval)
  2243. {
  2244. WritePerfHint(PerfHints::SrcIsEval, funcInfo->GetParsedFunctionBody(), 0);
  2245. }
  2246. }
  2247. #endif
  2248. }
  2249. funcInfo->SetHasHeapArguments(true, !pnodeFnc->IsCoroutine() && doStackArgsOpt /*= Optimize arguments in backend*/);
  2250. if (funcInfo->inArgsCount == 0)
  2251. {
  2252. // If no formals to function, no need to create the propertyid array
  2253. byteCodeGenerator->AssignNullConstRegister();
  2254. }
  2255. }
  2256. }
  2257. }
  2258. Js::FunctionBody* parentFunctionBody = parentFunc->GetParsedFunctionBody();
  2259. if (funcInfo->GetHasArguments() ||
  2260. parentFunctionBody->GetHasOrParentHasArguments())
  2261. {
  2262. // The JIT uses this info, for instance, to narrow kills of array operations
  2263. funcInfo->GetParsedFunctionBody()->SetHasOrParentHasArguments(true);
  2264. }
  2265. PreVisitBlock(pnodeFnc->pnodeScopes, byteCodeGenerator);
  2266. // If we have arguments, we are going to need locations if the function is in strict mode or we have a non-simple parameter list. This is because we will not create a scope object.
  2267. bool assignLocationForFormals = !byteCodeGenerator->NeedScopeObjectForArguments(funcInfo, funcInfo->root);
  2268. AddArgsToScope(pnodeFnc, byteCodeGenerator, assignLocationForFormals);
  2269. return funcInfo;
  2270. }
  2271. void AssignFuncSymRegister(ParseNodeFnc * pnodeFnc, ByteCodeGenerator * byteCodeGenerator, FuncInfo * callee)
  2272. {
  2273. // register to hold the allocated function (in enclosing sequence of global statements)
  2274. // TODO: Make the parser identify uses of function decls as RHS's of expressions.
  2275. // Currently they're all marked as used, so they all get permanent (non-temp) registers.
  2276. if (pnodeFnc->pnodeName == nullptr)
  2277. {
  2278. return;
  2279. }
  2280. Assert(pnodeFnc->pnodeName->nop == knopVarDecl);
  2281. Symbol *sym = pnodeFnc->pnodeName->sym;
  2282. if (sym)
  2283. {
  2284. if (!sym->GetIsGlobal() && !(callee->funcExprScope && callee->funcExprScope->GetIsObject()))
  2285. {
  2286. // If the func decl is used, we have to give the expression a register to protect against:
  2287. // x.x = function f() {...};
  2288. // x.y = function f() {...};
  2289. // If we let the value reside in the local slot for f, then both assignments will get the
  2290. // second definition.
  2291. if (!pnodeFnc->IsDeclaration())
  2292. {
  2293. // A named function expression's name belongs to the enclosing scope.
  2294. // In ES5 mode, it is visible only inside the inner function.
  2295. // Allocate a register for the 'name' symbol from an appropriate register namespace.
  2296. if (callee->GetFuncExprNameReference())
  2297. {
  2298. // This is a function expression with a name, but probably doesn't have a use within
  2299. // the function. If that is the case then allocate a register for LdFuncExpr inside the function
  2300. // we just finished post-visiting.
  2301. if (sym->GetLocation() == Js::Constants::NoRegister)
  2302. {
  2303. sym->SetLocation(callee->NextVarRegister());
  2304. }
  2305. }
  2306. }
  2307. else
  2308. {
  2309. // Function declaration
  2310. byteCodeGenerator->AssignRegister(sym);
  2311. pnodeFnc->location = sym->GetLocation();
  2312. Assert(byteCodeGenerator->GetCurrentScope()->GetFunc() == sym->GetScope()->GetFunc());
  2313. if (byteCodeGenerator->GetCurrentScope()->GetFunc() != sym->GetScope()->GetFunc())
  2314. {
  2315. Assert(ByteCodeGenerator::GetParentFuncInfo(byteCodeGenerator->GetCurrentScope()->GetFunc()) == sym->GetScope()->GetFunc());
  2316. sym->GetScope()->SetMustInstantiate(true);
  2317. byteCodeGenerator->ProcessCapturedSym(sym);
  2318. sym->GetScope()->GetFunc()->SetHasLocalInClosure(true);
  2319. }
  2320. Symbol * functionScopeVarSym = sym->GetFuncScopeVarSym();
  2321. if (functionScopeVarSym &&
  2322. !functionScopeVarSym->GetIsGlobal() &&
  2323. !functionScopeVarSym->IsInSlot(byteCodeGenerator, sym->GetScope()->GetFunc()))
  2324. {
  2325. byteCodeGenerator->AssignRegister(functionScopeVarSym);
  2326. }
  2327. }
  2328. }
  2329. else if (!pnodeFnc->IsDeclaration())
  2330. {
  2331. if (sym->GetLocation() == Js::Constants::NoRegister)
  2332. {
  2333. // Here, we are assigning a register for the LdFuncExpr instruction inside the function we just finished
  2334. // post-visiting. The symbol is given a register from the register pool for the function we just finished
  2335. // post-visiting, rather than from the parent function's register pool.
  2336. sym->SetLocation(callee->NextVarRegister());
  2337. }
  2338. }
  2339. }
  2340. }
  2341. bool FuncAllowsDirectSuper(FuncInfo *funcInfo, ByteCodeGenerator *byteCodeGenerator)
  2342. {
  2343. if (!funcInfo->IsBaseClassConstructor() && funcInfo->IsClassConstructor())
  2344. {
  2345. return true;
  2346. }
  2347. if (funcInfo->IsGlobalFunction() && ((byteCodeGenerator->GetFlags() & fscrEval) != 0))
  2348. {
  2349. Js::JavascriptFunction *caller = nullptr;
  2350. if (Js::JavascriptStackWalker::GetCaller(&caller, byteCodeGenerator->GetScriptContext()) && caller->GetFunctionInfo()->GetAllowDirectSuper())
  2351. {
  2352. return true;
  2353. }
  2354. }
  2355. return false;
  2356. }
  2357. FuncInfo* PostVisitFunction(ParseNodeFnc* pnodeFnc, ByteCodeGenerator* byteCodeGenerator)
  2358. {
  2359. // Assign function-wide registers such as local frame object, closure environment, etc., based on
  2360. // observed attributes. Propagate attributes to the parent function (if any).
  2361. FuncInfo *top = byteCodeGenerator->TopFuncInfo();
  2362. Symbol *sym = pnodeFnc->GetFuncSymbol();
  2363. bool funcExprWithName = !top->IsGlobalFunction() && sym && sym->GetIsFuncExpr();
  2364. if (top->IsLambda())
  2365. {
  2366. FuncInfo *enclosingNonLambda = byteCodeGenerator->FindEnclosingNonLambda();
  2367. if (enclosingNonLambda->IsGlobalFunction())
  2368. {
  2369. top->byteCodeFunction->SetEnclosedByGlobalFunc();
  2370. }
  2371. if (FuncAllowsDirectSuper(enclosingNonLambda, byteCodeGenerator))
  2372. {
  2373. top->byteCodeFunction->GetFunctionInfo()->SetAllowDirectSuper();
  2374. }
  2375. }
  2376. else if (FuncAllowsDirectSuper(top, byteCodeGenerator))
  2377. {
  2378. top->byteCodeFunction->GetFunctionInfo()->SetAllowDirectSuper();
  2379. }
  2380. // If this is a named function expression and has deferred child, mark has non-local reference.
  2381. if (funcExprWithName)
  2382. {
  2383. // If we are reparsing this function due to being in debug mode - we should restore the state of this from the earlier parse
  2384. if (top->byteCodeFunction->IsFunctionParsed() && top->GetParsedFunctionBody()->HasFuncExprNameReference())
  2385. {
  2386. top->SetFuncExprNameReference(true);
  2387. }
  2388. if (sym->GetHasNonLocalReference())
  2389. {
  2390. // Before doing this, though, make sure there's no local symbol that hides the function name
  2391. // from the nested functions. If a lookup starting at the current local scope finds some symbol
  2392. // other than the func expr, then it's hidden. (See Win8 393618.)
  2393. byteCodeGenerator->ProcessCapturedSym(sym);
  2394. top->SetFuncExprNameReference(true);
  2395. if (pnodeFnc->pnodeBody)
  2396. {
  2397. top->GetParsedFunctionBody()->SetFuncExprNameReference(true);
  2398. }
  2399. byteCodeGenerator->ProcessScopeWithCapturedSym(sym->GetScope());
  2400. }
  2401. }
  2402. if (pnodeFnc->nop != knopProg
  2403. && !top->bodyScope->GetIsObject()
  2404. && byteCodeGenerator->NeedObjectAsFunctionScope(top, pnodeFnc))
  2405. {
  2406. // Even if it wasn't determined during visiting this function that we need a scope object, we still have a few conditions that may require one.
  2407. top->bodyScope->SetIsObject();
  2408. if (!top->IsBodyAndParamScopeMerged())
  2409. {
  2410. // If we have the function inside an eval then access to outer variables should go through scope object.
  2411. // So we set the body scope as object and we need to set the param scope also as object in case of split scope.
  2412. top->paramScope->SetIsObject();
  2413. }
  2414. }
  2415. if (pnodeFnc->nop == knopProg
  2416. && top->byteCodeFunction->GetIsStrictMode()
  2417. && (byteCodeGenerator->GetFlags() & fscrEval))
  2418. {
  2419. // At global scope inside a strict mode eval, vars will not leak out and require a scope object (along with its parent.)
  2420. top->bodyScope->SetIsObject();
  2421. }
  2422. if (pnodeFnc->pnodeBody)
  2423. {
  2424. if (!top->IsGlobalFunction())
  2425. {
  2426. auto fnProcess =
  2427. [byteCodeGenerator, top](Symbol *const sym)
  2428. {
  2429. if (sym->GetHasNonLocalReference() && !sym->GetIsModuleExportStorage())
  2430. {
  2431. byteCodeGenerator->ProcessCapturedSym(sym);
  2432. }
  2433. };
  2434. Scope *bodyScope = top->bodyScope;
  2435. Scope *paramScope = top->paramScope;
  2436. if (paramScope != nullptr)
  2437. {
  2438. if (paramScope->GetHasOwnLocalInClosure())
  2439. {
  2440. paramScope->ForEachSymbol(fnProcess);
  2441. top->SetHasLocalInClosure(true);
  2442. }
  2443. }
  2444. if (bodyScope->GetHasOwnLocalInClosure())
  2445. {
  2446. bodyScope->ForEachSymbol(fnProcess);
  2447. top->SetHasLocalInClosure(true);
  2448. }
  2449. PostVisitBlock(pnodeFnc->pnodeBodyScope, byteCodeGenerator);
  2450. PostVisitBlock(pnodeFnc->pnodeScopes, byteCodeGenerator);
  2451. }
  2452. // This function refers to the closure environment if:
  2453. // 1. it has a child function (we'll pass the environment to the constructor when the child is created -
  2454. // even if it's not needed, it's as cheap as loading "null" from the library);
  2455. // 2. it calls eval (and will use the environment to construct the scope chain to pass to eval);
  2456. // 3. it refers to a local defined in a parent function;
  2457. // 4. some parent calls eval;
  2458. // 5. we're in an event handler;
  2459. // 6. the function was declared inside a "with";
  2460. // 7. we're in an eval expression.
  2461. if (pnodeFnc->nestedCount != 0 ||
  2462. top->GetCallsEval() ||
  2463. top->GetHasClosureReference() ||
  2464. byteCodeGenerator->InDynamicScope() ||
  2465. (byteCodeGenerator->GetFlags() & (fscrImplicitThis | fscrEval)))
  2466. {
  2467. byteCodeGenerator->SetNeedEnvRegister();
  2468. }
  2469. // This function needs to construct a local frame on the heap if it is not the global function (even in eval) and:
  2470. // 1. it calls eval, which may refer to or declare any locals in this frame;
  2471. // 2. a child calls eval (which may refer to locals through a closure);
  2472. // 3. it uses non-strict mode "arguments", so the arguments have to be put in a closure;
  2473. // 4. it defines a local that is used by a child function (read from a closure).
  2474. // 5. it is a main function that's wrapped in a function expression scope but has locals used through
  2475. // a closure (used in forReference function call cases in a with for example).
  2476. if (!top->IsGlobalFunction())
  2477. {
  2478. if (top->GetCallsEval() ||
  2479. top->GetChildCallsEval() ||
  2480. (top->GetHasArguments() && byteCodeGenerator->NeedScopeObjectForArguments(top, pnodeFnc)) ||
  2481. top->GetHasLocalInClosure() ||
  2482. (top->funcExprScope && top->funcExprScope->GetMustInstantiate()) ||
  2483. // When we have split scope normally either eval will be present or the GetHasLocalInClosure will be true as one of the formal is
  2484. // captured. But when we force split scope or split scope happens due to some other reasons we have to make sure we allocate frame
  2485. // slot register here.
  2486. (!top->IsBodyAndParamScopeMerged()))
  2487. {
  2488. if (!top->GetCallsEval() && top->GetHasLocalInClosure())
  2489. {
  2490. byteCodeGenerator->AssignFrameSlotsRegister();
  2491. }
  2492. if (!top->IsBodyAndParamScopeMerged())
  2493. {
  2494. byteCodeGenerator->AssignParamSlotsRegister();
  2495. }
  2496. if (byteCodeGenerator->NeedObjectAsFunctionScope(top, top->root)
  2497. || top->bodyScope->GetIsObject()
  2498. || top->paramScope->GetIsObject())
  2499. {
  2500. byteCodeGenerator->AssignFrameObjRegister();
  2501. }
  2502. // The function also needs to construct a frame display if:
  2503. // 1. it calls eval;
  2504. // 2. it has a child function.
  2505. // 3. When has arguments and in debug mode. So that frame display be there along with frame object register.
  2506. if (top->GetCallsEval() ||
  2507. pnodeFnc->nestedCount != 0
  2508. || (top->GetHasArguments()
  2509. && (pnodeFnc->pnodeParams != nullptr)
  2510. && byteCodeGenerator->IsInDebugMode()))
  2511. {
  2512. byteCodeGenerator->SetNeedEnvRegister(); // This to ensure that Env should be there when the FrameDisplay register is there.
  2513. byteCodeGenerator->AssignFrameDisplayRegister();
  2514. }
  2515. }
  2516. if (top->GetHasArguments())
  2517. {
  2518. Symbol *argSym = top->GetArgumentsSymbol();
  2519. Assert(argSym);
  2520. if (argSym)
  2521. {
  2522. Assert(top->bodyScope->GetScopeSlotCount() == 0);
  2523. Assert(top->argsPlaceHolderSlotCount == 0);
  2524. byteCodeGenerator->AssignRegister(argSym);
  2525. uint i = 0;
  2526. auto setArgScopeSlot = [&](ParseNode *pnodeArg)
  2527. {
  2528. if (pnodeArg->IsVarLetOrConst())
  2529. {
  2530. Symbol* sym = pnodeArg->AsParseNodeVar()->sym;
  2531. if (sym->GetScopeSlot() != Js::Constants::NoProperty)
  2532. {
  2533. top->argsPlaceHolderSlotCount++; // Same name args appeared before
  2534. }
  2535. sym->SetScopeSlot(i);
  2536. }
  2537. else if (pnodeArg->nop == knopParamPattern)
  2538. {
  2539. top->argsPlaceHolderSlotCount++;
  2540. }
  2541. i++;
  2542. };
  2543. // We need to include the rest as well -as it will get slot assigned.
  2544. if (byteCodeGenerator->NeedScopeObjectForArguments(top, pnodeFnc))
  2545. {
  2546. MapFormals(pnodeFnc, setArgScopeSlot);
  2547. if (argSym->NeedsSlotAlloc(byteCodeGenerator, top))
  2548. {
  2549. Assert(argSym->GetScopeSlot() == Js::Constants::NoProperty);
  2550. argSym->SetScopeSlot(i++);
  2551. }
  2552. MapFormalsFromPattern(pnodeFnc, setArgScopeSlot);
  2553. }
  2554. top->paramScope->SetScopeSlotCount(i);
  2555. Assert(top->GetHasHeapArguments());
  2556. if (byteCodeGenerator->NeedScopeObjectForArguments(top, pnodeFnc)
  2557. && !pnodeFnc->HasNonSimpleParameterList())
  2558. {
  2559. top->byteCodeFunction->SetHasImplicitArgIns(false);
  2560. }
  2561. }
  2562. }
  2563. }
  2564. else
  2565. {
  2566. Assert(top->IsGlobalFunction() || pnodeFnc->IsModule());
  2567. // eval is called in strict mode
  2568. bool newScopeForEval = (top->byteCodeFunction->GetIsStrictMode() && (byteCodeGenerator->GetFlags() & fscrEval));
  2569. if (newScopeForEval)
  2570. {
  2571. byteCodeGenerator->SetNeedEnvRegister();
  2572. byteCodeGenerator->AssignFrameObjRegister();
  2573. byteCodeGenerator->AssignFrameDisplayRegister();
  2574. }
  2575. }
  2576. if (top->GetNewTargetSymbol())
  2577. {
  2578. byteCodeGenerator->AssignRegister(top->GetNewTargetSymbol());
  2579. }
  2580. if (top->GetThisSymbol())
  2581. {
  2582. byteCodeGenerator->AssignRegister(top->GetThisSymbol());
  2583. // Indirect eval has a 'this' binding and needs to load from null
  2584. if (top->IsGlobalFunction())
  2585. {
  2586. byteCodeGenerator->AssignNullConstRegister();
  2587. }
  2588. }
  2589. if (top->GetSuperSymbol())
  2590. {
  2591. byteCodeGenerator->AssignRegister(top->GetSuperSymbol());
  2592. }
  2593. if (top->GetSuperConstructorSymbol())
  2594. {
  2595. byteCodeGenerator->AssignRegister(top->GetSuperConstructorSymbol());
  2596. }
  2597. Assert(!funcExprWithName || sym);
  2598. if (funcExprWithName)
  2599. {
  2600. Assert(top->funcExprScope);
  2601. // If the func expr may be accessed via eval, force the func expr scope into an object.
  2602. if (top->GetCallsEval() || top->GetChildCallsEval())
  2603. {
  2604. top->funcExprScope->SetIsObject();
  2605. }
  2606. if (top->funcExprScope->GetIsObject())
  2607. {
  2608. top->funcExprScope->SetLocation(byteCodeGenerator->NextVarRegister());
  2609. }
  2610. }
  2611. }
  2612. byteCodeGenerator->EndBindFunction(funcExprWithName);
  2613. // If the "child" is the global function, we're done.
  2614. if (top->IsGlobalFunction())
  2615. {
  2616. return top;
  2617. }
  2618. if (top->IsBodyAndParamScopeMerged())
  2619. {
  2620. Scope::MergeParamAndBodyScopes(pnodeFnc);
  2621. Scope::RemoveParamScope(pnodeFnc);
  2622. }
  2623. else
  2624. {
  2625. // A param and body scope exist for the same function, they
  2626. // should both either be using scope slots or scope objects.
  2627. Assert_FailFast(top->bodyScope->GetIsObject() == top->paramScope->GetIsObject());
  2628. }
  2629. FuncInfo* const parentFunc = byteCodeGenerator->TopFuncInfo();
  2630. Js::FunctionBody * parentFunctionBody = parentFunc->byteCodeFunction->GetFunctionBody();
  2631. Assert(parentFunctionBody != nullptr);
  2632. bool setHasNonLocalReference = parentFunctionBody->HasAllNonLocalReferenced();
  2633. // This is required for class constructors as will be able to determine the actual home object register only after emitting InitClass
  2634. if (pnodeFnc->HasHomeObj() && pnodeFnc->GetHomeObjLocation() == Js::Constants::NoRegister)
  2635. {
  2636. pnodeFnc->SetHomeObjLocation(parentFunc->AssignUndefinedConstRegister());
  2637. }
  2638. // If we have any deferred child, we need to instantiate the fake global block scope if it is not empty
  2639. if (parentFunc->IsGlobalFunction())
  2640. {
  2641. if (byteCodeGenerator->IsEvalWithNoParentScopeInfo())
  2642. {
  2643. Scope * globalEvalBlockScope = parentFunc->GetGlobalEvalBlockScope();
  2644. if (globalEvalBlockScope->GetHasOwnLocalInClosure())
  2645. {
  2646. globalEvalBlockScope->SetMustInstantiate(true);
  2647. }
  2648. }
  2649. }
  2650. else
  2651. {
  2652. if (setHasNonLocalReference)
  2653. {
  2654. // All locals are already marked as non-locals-referenced. Mark the parent as well.
  2655. if (parentFunctionBody->HasSetIsObject())
  2656. {
  2657. // Updated the current function, as per the previous stored info.
  2658. parentFunc->GetBodyScope()->SetIsObject();
  2659. parentFunc->GetParamScope()->SetIsObject();
  2660. }
  2661. }
  2662. // Propagate HasMaybeEscapedNestedFunc
  2663. if (!byteCodeGenerator->CanStackNestedFunc(top, false) ||
  2664. byteCodeGenerator->NeedObjectAsFunctionScope(top, pnodeFnc))
  2665. {
  2666. parentFunc->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("Child")));
  2667. }
  2668. }
  2669. if (top->GetCallsEval() || top->GetChildCallsEval())
  2670. {
  2671. parentFunc->SetChildCallsEval(true);
  2672. ParseNodeBlock *currentBlock = byteCodeGenerator->GetCurrentBlock();
  2673. if (currentBlock)
  2674. {
  2675. Assert(currentBlock->nop == knopBlock);
  2676. currentBlock->SetChildCallsEval(true);
  2677. }
  2678. parentFunc->SetHasHeapArguments(true);
  2679. setHasNonLocalReference = true;
  2680. parentFunctionBody->SetAllNonLocalReferenced(true);
  2681. Scope * const funcExprScope = top->funcExprScope;
  2682. if (funcExprScope)
  2683. {
  2684. // If we have the body scope as an object, the outer function expression scope also needs to be an object to propagate the name.
  2685. funcExprScope->SetIsObject();
  2686. }
  2687. if (parentFunc->inArgsCount == 1)
  2688. {
  2689. // If no formals to function, no need to create the propertyid array
  2690. byteCodeGenerator->AssignNullConstRegister();
  2691. }
  2692. }
  2693. if (setHasNonLocalReference && !parentFunctionBody->HasDoneAllNonLocalReferenced())
  2694. {
  2695. parentFunc->GetBodyScope()->ForceAllSymbolNonLocalReference(byteCodeGenerator);
  2696. if (!parentFunc->IsGlobalFunction())
  2697. {
  2698. parentFunc->GetParamScope()->ForceAllSymbolNonLocalReference(byteCodeGenerator);
  2699. }
  2700. parentFunctionBody->SetHasDoneAllNonLocalReferenced(true);
  2701. }
  2702. if (pnodeFnc->IsGenerator())
  2703. {
  2704. top->AssignUndefinedConstRegister();
  2705. }
  2706. if ((top->root->IsConstructor() && (top->GetCallsEval() || top->GetChildCallsEval())) || top->IsClassConstructor())
  2707. {
  2708. if (!top->IsBaseClassConstructor())
  2709. {
  2710. // Derived class constructors need to check undefined against explicit return statements.
  2711. top->AssignUndefinedConstRegister();
  2712. }
  2713. }
  2714. AssignFuncSymRegister(pnodeFnc, byteCodeGenerator, top);
  2715. if (pnodeFnc->pnodeBody && pnodeFnc->HasReferenceableBuiltInArguments() && pnodeFnc->UsesArguments() &&
  2716. pnodeFnc->HasHeapArguments())
  2717. {
  2718. bool doStackArgsOpt = top->byteCodeFunction->GetDoBackendArgumentsOptimization();
  2719. bool hasAnyParamInClosure = top->GetHasLocalInClosure() && top->GetParamScope()->GetHasOwnLocalInClosure();
  2720. if ((doStackArgsOpt && top->inArgsCount > 1))
  2721. {
  2722. if (doStackArgsOpt && hasAnyParamInClosure)
  2723. {
  2724. top->SetHasHeapArguments(true, false /*= Optimize arguments in backend*/);
  2725. #ifdef PERF_HINT
  2726. if (PHASE_TRACE1(Js::PerfHintPhase))
  2727. {
  2728. WritePerfHint(PerfHints::HeapArgumentsDueToNonLocalRef, top->GetParsedFunctionBody(), 0);
  2729. }
  2730. #endif
  2731. }
  2732. else if (!top->GetHasLocalInClosure() && !(byteCodeGenerator->GetFlags() & fscrEval) && !top->byteCodeFunction->IsEval())
  2733. {
  2734. //Scope object creation instr will be a MOV NULL instruction in the Lowerer - if we still decide to do StackArgs after Globopt phase.
  2735. //Note that if we're in eval, scoped ldfld/stfld will traverse the whole frame display, including this slot, so it can't be null.
  2736. top->byteCodeFunction->SetDoScopeObjectCreation(false);
  2737. }
  2738. }
  2739. }
  2740. return top;
  2741. }
  2742. void ByteCodeGenerator::ProcessCapturedSym(Symbol *sym)
  2743. {
  2744. // The symbol's home function will tell us which child function we're currently processing.
  2745. // This is the one that captures the symbol, from the declaring function's perspective.
  2746. // So based on that information, note either that, (a.) the symbol is committed to the heap from its
  2747. // inception, (b.) the symbol must be committed when the capturing function is instantiated.
  2748. FuncInfo *funcHome = sym->GetScope()->GetFunc();
  2749. FuncInfo *funcChild = funcHome->GetCurrentChildFunction();
  2750. Assert(sym->NeedsSlotAlloc(this, funcHome) || sym->GetIsGlobal() || sym->GetIsModuleImport() || sym->GetIsModuleExportStorage());
  2751. if (sym->GetScope()->GetScopeType() == ScopeType_FuncExpr)
  2752. {
  2753. if ((funcHome->GetParamScope() && Scope::HasSymbolName(funcHome->GetParamScope(), sym->GetName())) ||
  2754. (funcHome->IsBodyAndParamScopeMerged() && funcHome->GetBodyScope() && Scope::HasSymbolName(funcHome->GetBodyScope(), sym->GetName())))
  2755. {
  2756. // Make sure the function expression scope gets instantiated, since we can't merge the name symbol into another scope.
  2757. // Make it an object, since that's the only case the code gen can currently handle.
  2758. sym->GetScope()->SetIsObject();
  2759. }
  2760. }
  2761. // If this is not a local property, or not all its references can be tracked, or
  2762. // it's not scoped to the function, or we're in debug mode, disable the delayed capture optimization.
  2763. if (funcHome->IsGlobalFunction() ||
  2764. funcHome->GetCallsEval() ||
  2765. funcHome->GetChildCallsEval() ||
  2766. funcChild == nullptr ||
  2767. sym->GetScope() != funcHome->GetBodyScope() ||
  2768. this->IsInDebugMode() ||
  2769. PHASE_OFF(Js::DelayCapturePhase, funcHome->byteCodeFunction))
  2770. {
  2771. sym->SetIsCommittedToSlot();
  2772. }
  2773. if (sym->GetIsCommittedToSlot())
  2774. {
  2775. return;
  2776. }
  2777. AnalysisAssert(funcChild);
  2778. ParseNode *pnodeChild = funcChild->root;
  2779. Assert(pnodeChild && pnodeChild->nop == knopFncDecl);
  2780. if (pnodeChild->AsParseNodeFnc()->IsDeclaration())
  2781. {
  2782. // The capturing function is a declaration but may still be limited to an inner scope.
  2783. Scope *scopeChild = funcHome->GetCurrentChildScope();
  2784. if (scopeChild == sym->GetScope() || scopeChild->GetScopeType() == ScopeType_FunctionBody)
  2785. {
  2786. // The symbol is captured on entry to the scope in which it's declared.
  2787. // (Check the scope type separately so that we get the special parameter list and
  2788. // named function expression cases as well.)
  2789. sym->SetIsCommittedToSlot();
  2790. return;
  2791. }
  2792. }
  2793. // There is a chance we can limit the region in which the symbol lives on the heap.
  2794. // Note which function captures the symbol.
  2795. funcChild->AddCapturedSym(sym);
  2796. }
  2797. void ByteCodeGenerator::ProcessScopeWithCapturedSym(Scope *scope)
  2798. {
  2799. Assert(scope->GetHasOwnLocalInClosure());
  2800. // (Note: if any catch var is closure-captured, we won't merge the catch scope with the function scope.
  2801. // So don't mark the function scope "has local in closure".)
  2802. FuncInfo *func = scope->GetFunc();
  2803. bool notCatch = scope->GetScopeType() != ScopeType_Catch && scope->GetScopeType() != ScopeType_CatchParamPattern;
  2804. if (scope == func->GetBodyScope() || scope == func->GetParamScope() || (scope->GetCanMerge() && notCatch))
  2805. {
  2806. func->SetHasLocalInClosure(true);
  2807. }
  2808. else
  2809. {
  2810. if (scope->HasCrossScopeFuncAssignment())
  2811. {
  2812. func->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("InstantiateScopeWithCrossScopeAssignment")));
  2813. }
  2814. scope->SetMustInstantiate(true);
  2815. }
  2816. }
  2817. void MarkInit(ParseNode* pnode)
  2818. {
  2819. if (pnode->nop == knopList)
  2820. {
  2821. do
  2822. {
  2823. MarkInit(pnode->AsParseNodeBin()->pnode1);
  2824. pnode = pnode->AsParseNodeBin()->pnode2;
  2825. }
  2826. while (pnode->nop == knopList);
  2827. MarkInit(pnode);
  2828. }
  2829. else
  2830. {
  2831. Symbol *sym = nullptr;
  2832. ParseNode *pnodeInit = nullptr;
  2833. if (pnode->nop == knopVarDecl)
  2834. {
  2835. sym = pnode->AsParseNodeVar()->sym;
  2836. pnodeInit = pnode->AsParseNodeVar()->pnodeInit;
  2837. }
  2838. else if (pnode->nop == knopAsg && pnode->AsParseNodeBin()->pnode1->nop == knopName)
  2839. {
  2840. sym = pnode->AsParseNodeBin()->pnode1->AsParseNodeName()->sym;
  2841. pnodeInit = pnode->AsParseNodeBin()->pnode2;
  2842. }
  2843. if (sym && !sym->GetIsUsed() && pnodeInit)
  2844. {
  2845. sym->SetHasInit(true);
  2846. if (sym->HasVisitedCapturingFunc())
  2847. {
  2848. sym->SetHasNonCommittedReference(false);
  2849. }
  2850. }
  2851. }
  2852. }
  2853. void AddFunctionsToScope(ParseNodePtr scope, ByteCodeGenerator * byteCodeGenerator)
  2854. {
  2855. VisitFncDecls(scope, [byteCodeGenerator](ParseNode *fn)
  2856. {
  2857. ParseNode *pnodeName = fn->AsParseNodeFnc()->pnodeName;
  2858. if (pnodeName && pnodeName->nop == knopVarDecl && fn->AsParseNodeFnc()->IsDeclaration())
  2859. {
  2860. const char16 *fnName = pnodeName->AsParseNodeVar()->pid->Psz();
  2861. if (byteCodeGenerator->Trace())
  2862. {
  2863. Output::Print(_u("current context has declared function %s\n"), fnName);
  2864. }
  2865. // In ES6, functions are scoped to the block, which will be the current scope.
  2866. // Pre-ES6, function declarations are scoped to the function body, so get that scope.
  2867. Symbol *sym;
  2868. if (!byteCodeGenerator->GetCurrentScope()->IsGlobalEvalBlockScope())
  2869. {
  2870. sym = byteCodeGenerator->AddSymbolToScope(byteCodeGenerator->GetCurrentScope(), fnName, pnodeName->AsParseNodeVar()->pid->Cch(), pnodeName, STFunction);
  2871. }
  2872. else
  2873. {
  2874. sym = byteCodeGenerator->AddSymbolToFunctionScope(fnName, pnodeName->AsParseNodeVar()->pid->Cch(), pnodeName, STFunction);
  2875. }
  2876. pnodeName->AsParseNodeVar()->sym = sym;
  2877. if (sym->GetScope() != sym->GetScope()->GetFunc()->GetBodyScope() &&
  2878. sym->GetScope() != sym->GetScope()->GetFunc()->GetParamScope())
  2879. {
  2880. sym->SetIsBlockVar(true);
  2881. }
  2882. }
  2883. });
  2884. }
  2885. template <class PrefixFn, class PostfixFn>
  2886. void VisitNestedScopes(ParseNode* pnodeScopeList, ParseNode* pnodeParent, ByteCodeGenerator* byteCodeGenerator,
  2887. PrefixFn prefix, PostfixFn postfix, uint *pIndex, bool breakOnBodyScope = false)
  2888. {
  2889. // Visit all scopes nested in this scope before visiting this function's statements. This way we have all the
  2890. // attributes of all the inner functions before we assign registers within this function.
  2891. // All the attributes we need to propagate downward should already be recorded by the parser.
  2892. // - call to "eval()"
  2893. // - nested in "with"
  2894. FuncInfo * parentFuncInfo = pnodeParent->AsParseNodeFnc()->funcInfo;
  2895. Js::ParseableFunctionInfo* parentFunc = parentFuncInfo->byteCodeFunction;
  2896. ParseNode* pnodeScope;
  2897. uint i = 0;
  2898. // Cache to restore it back once we come out of current function.
  2899. Js::FunctionBody * pLastReuseFunc = byteCodeGenerator->pCurrentFunction;
  2900. for (pnodeScope = pnodeScopeList; pnodeScope;)
  2901. {
  2902. if (breakOnBodyScope && pnodeScope == pnodeParent->AsParseNodeFnc()->pnodeBodyScope)
  2903. {
  2904. break;
  2905. }
  2906. switch (pnodeScope->nop)
  2907. {
  2908. case knopFncDecl:
  2909. {
  2910. ParseNodeFnc * pnodeFnc = pnodeScope->AsParseNodeFnc();
  2911. if (pLastReuseFunc)
  2912. {
  2913. if (!byteCodeGenerator->IsInNonDebugMode())
  2914. {
  2915. // Here we are trying to match the inner sub-tree as well with already created inner function.
  2916. if ((pLastReuseFunc->GetIsGlobalFunc() && parentFunc->GetIsGlobalFunc())
  2917. || (!pLastReuseFunc->GetIsGlobalFunc() && !parentFunc->GetIsGlobalFunc()))
  2918. {
  2919. Assert(pLastReuseFunc->StartInDocument() == pnodeParent->ichMin);
  2920. Assert(pLastReuseFunc->LengthInChars() == pnodeParent->LengthInCodepoints());
  2921. Assert(pLastReuseFunc->GetNestedCount() == parentFunc->GetNestedCount());
  2922. // If the current function is not parsed yet, its function body is not generated yet.
  2923. // Reset pCurrentFunction to null so that it will not be able re-use anything.
  2924. Js::FunctionProxy* proxy = pLastReuseFunc->GetNestedFunctionProxy((*pIndex));
  2925. if (proxy && proxy->IsFunctionBody())
  2926. {
  2927. byteCodeGenerator->pCurrentFunction = proxy->GetFunctionBody();
  2928. }
  2929. else
  2930. {
  2931. byteCodeGenerator->pCurrentFunction = nullptr;
  2932. }
  2933. }
  2934. }
  2935. else if (!parentFunc->GetIsGlobalFunc())
  2936. {
  2937. // In the deferred parsing mode, we will be reusing the only one function (which is asked when on ::Begin) all inner function will be created.
  2938. byteCodeGenerator->pCurrentFunction = nullptr;
  2939. }
  2940. }
  2941. Js::ParseableFunctionInfo::NestedArray * parentNestedArray = parentFunc->GetNestedArray();
  2942. Js::ParseableFunctionInfo* reuseNestedFunc = nullptr;
  2943. if (parentNestedArray)
  2944. {
  2945. Assert(*pIndex < parentNestedArray->nestedCount);
  2946. Js::FunctionInfo * info = parentNestedArray->functionInfoArray[*pIndex];
  2947. if (info && info->HasParseableInfo())
  2948. {
  2949. reuseNestedFunc = info->GetParseableFunctionInfo();
  2950. // If parentFunc was redeferred, try to set pCurrentFunction to this FunctionBody,
  2951. // and cleanup to reparse (as previous cleanup stops at redeferred parentFunc).
  2952. if (!byteCodeGenerator->IsInNonDebugMode()
  2953. && !byteCodeGenerator->pCurrentFunction
  2954. && reuseNestedFunc->IsFunctionBody())
  2955. {
  2956. byteCodeGenerator->pCurrentFunction = reuseNestedFunc->GetFunctionBody();
  2957. }
  2958. }
  2959. }
  2960. PreVisitFunction(pnodeFnc, byteCodeGenerator, reuseNestedFunc);
  2961. FuncInfo *funcInfo = pnodeFnc->funcInfo;
  2962. parentFuncInfo->OnStartVisitFunction(pnodeFnc);
  2963. if (pnodeFnc->pnodeBody)
  2964. {
  2965. if (!byteCodeGenerator->IsInNonDebugMode() && pLastReuseFunc != nullptr && byteCodeGenerator->pCurrentFunction == nullptr)
  2966. {
  2967. // Patch current non-parsed function's FunctionBodyImpl with the new generated function body.
  2968. // So that the function object (pointing to the old function body) can able to get to the new one.
  2969. Js::FunctionProxy* proxy = pLastReuseFunc->GetNestedFunctionProxy((*pIndex));
  2970. if (proxy && !proxy->IsFunctionBody())
  2971. {
  2972. proxy->UpdateFunctionBodyImpl(funcInfo->byteCodeFunction->GetFunctionBody());
  2973. }
  2974. }
  2975. Scope *paramScope = funcInfo->GetParamScope();
  2976. Scope *bodyScope = funcInfo->GetBodyScope();
  2977. BeginVisitBlock(pnodeFnc->pnodeScopes, byteCodeGenerator);
  2978. i = 0;
  2979. ParseNodePtr containerScope = pnodeFnc->pnodeScopes;
  2980. // Push the param scope
  2981. byteCodeGenerator->PushScope(paramScope);
  2982. if (pnodeFnc->HasNonSimpleParameterList() && !funcInfo->IsBodyAndParamScopeMerged())
  2983. {
  2984. // Set param scope as the current child scope.
  2985. funcInfo->SetCurrentChildScope(paramScope);
  2986. Assert(containerScope->nop == knopBlock && containerScope->AsParseNodeBlock()->blockType == Parameter);
  2987. VisitNestedScopes(containerScope->AsParseNodeBlock()->pnodeScopes, pnodeFnc, byteCodeGenerator, prefix, postfix, &i, true);
  2988. MapFormals(pnodeFnc, [&](ParseNode *argNode) { Visit(argNode, byteCodeGenerator, prefix, postfix); });
  2989. }
  2990. // Push the body scope
  2991. byteCodeGenerator->PushScope(bodyScope);
  2992. funcInfo->SetCurrentChildScope(bodyScope);
  2993. PreVisitBlock(pnodeFnc->pnodeBodyScope, byteCodeGenerator);
  2994. AddVarsToScope(pnodeFnc->pnodeVars, byteCodeGenerator);
  2995. if (!pnodeFnc->HasNonSimpleParameterList() || funcInfo->IsBodyAndParamScopeMerged())
  2996. {
  2997. VisitNestedScopes(containerScope, pnodeFnc, byteCodeGenerator, prefix, postfix, &i);
  2998. MapFormals(pnodeFnc, [&](ParseNode *argNode) { Visit(argNode, byteCodeGenerator, prefix, postfix); });
  2999. }
  3000. if (pnodeFnc->HasNonSimpleParameterList())
  3001. {
  3002. byteCodeGenerator->AssignUndefinedConstRegister();
  3003. if (!funcInfo->IsBodyAndParamScopeMerged())
  3004. {
  3005. Assert(pnodeFnc->pnodeBodyScope->scope);
  3006. VisitNestedScopes(pnodeFnc->pnodeBodyScope->pnodeScopes, pnodeFnc, byteCodeGenerator, prefix, postfix, &i);
  3007. }
  3008. }
  3009. BeginVisitBlock(pnodeFnc->pnodeBodyScope, byteCodeGenerator);
  3010. ParseNode* pnode = pnodeFnc->pnodeBody;
  3011. while (pnode->nop == knopList)
  3012. {
  3013. // Check to see whether initializations of locals to "undef" can be skipped.
  3014. // The logic to do this is cheap - omit the init if we see an init with a value
  3015. // on the RHS at the top statement level (i.e., not inside a block, try, loop, etc.)
  3016. // before we see a use. The motivation is to help identify single-def locals in the BE.
  3017. // Note that this can't be done for globals.
  3018. byteCodeGenerator->SetCurrentTopStatement(pnode->AsParseNodeBin()->pnode1);
  3019. Visit(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator, prefix, postfix);
  3020. if (!funcInfo->GetCallsEval() && !funcInfo->GetChildCallsEval() &&
  3021. // So that it will not be marked as init thus it will be added to the diagnostics symbols container.
  3022. !(byteCodeGenerator->ShouldTrackDebuggerMetadata()))
  3023. {
  3024. MarkInit(pnode->AsParseNodeBin()->pnode1);
  3025. }
  3026. pnode = pnode->AsParseNodeBin()->pnode2;
  3027. }
  3028. byteCodeGenerator->SetCurrentTopStatement(pnode);
  3029. Visit(pnode, byteCodeGenerator, prefix, postfix);
  3030. EndVisitBlock(pnodeFnc->pnodeBodyScope, byteCodeGenerator);
  3031. EndVisitBlock(pnodeFnc->pnodeScopes, byteCodeGenerator);
  3032. }
  3033. if (!pnodeFnc->pnodeBody)
  3034. {
  3035. // For defer prase scenario push the scopes here
  3036. byteCodeGenerator->PushScope(funcInfo->GetParamScope());
  3037. byteCodeGenerator->PushScope(funcInfo->GetBodyScope());
  3038. }
  3039. if (!parentFuncInfo->IsFakeGlobalFunction(byteCodeGenerator->GetFlags()))
  3040. {
  3041. pnodeFnc->nestedIndex = *pIndex;
  3042. parentFunc->SetNestedFunc(funcInfo->byteCodeFunction->GetFunctionInfo(), (*pIndex)++, byteCodeGenerator->GetFlags());
  3043. }
  3044. Assert(parentFunc);
  3045. parentFuncInfo->OnEndVisitFunction(pnodeFnc);
  3046. PostVisitFunction(pnodeFnc, byteCodeGenerator);
  3047. pnodeScope = pnodeFnc->pnodeNext;
  3048. byteCodeGenerator->pCurrentFunction = pLastReuseFunc;
  3049. break;
  3050. }
  3051. case knopBlock:
  3052. {
  3053. ParseNodeBlock * pnodeBlockScope = pnodeScope->AsParseNodeBlock();
  3054. PreVisitBlock(pnodeBlockScope, byteCodeGenerator);
  3055. bool isMergedScope;
  3056. parentFuncInfo->OnStartVisitScope(pnodeBlockScope->scope, &isMergedScope);
  3057. VisitNestedScopes(pnodeBlockScope->pnodeScopes, pnodeParent, byteCodeGenerator, prefix, postfix, pIndex);
  3058. parentFuncInfo->OnEndVisitScope(pnodeBlockScope->scope, isMergedScope);
  3059. PostVisitBlock(pnodeBlockScope, byteCodeGenerator);
  3060. pnodeScope = pnodeScope->AsParseNodeBlock()->pnodeNext;
  3061. break;
  3062. }
  3063. case knopCatch:
  3064. {
  3065. ParseNodeCatch * pnodeCatchScope = pnodeScope->AsParseNodeCatch();
  3066. PreVisitCatch(pnodeCatchScope, byteCodeGenerator);
  3067. if (pnodeCatchScope->GetParam()->nop != knopParamPattern)
  3068. {
  3069. Visit(pnodeCatchScope->GetParam(), byteCodeGenerator, prefix, postfix);
  3070. }
  3071. bool isMergedScope;
  3072. parentFuncInfo->OnStartVisitScope(pnodeCatchScope->scope, &isMergedScope);
  3073. VisitNestedScopes(pnodeCatchScope->pnodeScopes, pnodeParent, byteCodeGenerator, prefix, postfix, pIndex);
  3074. parentFuncInfo->OnEndVisitScope(pnodeCatchScope->scope, isMergedScope);
  3075. PostVisitCatch(pnodeCatchScope, byteCodeGenerator);
  3076. pnodeScope = pnodeCatchScope->pnodeNext;
  3077. break;
  3078. }
  3079. case knopWith:
  3080. {
  3081. PreVisitWith(pnodeScope, byteCodeGenerator);
  3082. bool isMergedScope;
  3083. parentFuncInfo->OnStartVisitScope(pnodeScope->AsParseNodeWith()->scope, &isMergedScope);
  3084. VisitNestedScopes(pnodeScope->AsParseNodeWith()->pnodeScopes, pnodeParent, byteCodeGenerator, prefix, postfix, pIndex);
  3085. parentFuncInfo->OnEndVisitScope(pnodeScope->AsParseNodeWith()->scope, isMergedScope);
  3086. PostVisitWith(pnodeScope, byteCodeGenerator);
  3087. pnodeScope = pnodeScope->AsParseNodeWith()->pnodeNext;
  3088. break;
  3089. }
  3090. default:
  3091. AssertMsg(false, "Unexpected opcode in tree of scopes");
  3092. return;
  3093. }
  3094. }
  3095. }
  3096. void PreVisitBlock(ParseNodeBlock *pnodeBlock, ByteCodeGenerator *byteCodeGenerator)
  3097. {
  3098. if (!pnodeBlock->scope &&
  3099. !pnodeBlock->HasBlockScopedContent() &&
  3100. !pnodeBlock->GetCallsEval())
  3101. {
  3102. // Do nothing here if the block doesn't declare anything or call eval (which may declare something).
  3103. return;
  3104. }
  3105. bool isGlobalEvalBlockScope = false;
  3106. FuncInfo *func = byteCodeGenerator->TopFuncInfo();
  3107. if (func->IsGlobalFunction() &&
  3108. func->root->pnodeScopes == pnodeBlock &&
  3109. byteCodeGenerator->IsEvalWithNoParentScopeInfo())
  3110. {
  3111. isGlobalEvalBlockScope = true;
  3112. }
  3113. Assert(!pnodeBlock->scope ||
  3114. isGlobalEvalBlockScope == (pnodeBlock->scope->GetScopeType() == ScopeType_GlobalEvalBlock));
  3115. ArenaAllocator *alloc = byteCodeGenerator->GetAllocator();
  3116. Scope *scope;
  3117. if ((pnodeBlock->blockType == PnodeBlockType::Global && !byteCodeGenerator->IsEvalWithNoParentScopeInfo()) || pnodeBlock->blockType == PnodeBlockType::Function)
  3118. {
  3119. scope = byteCodeGenerator->GetCurrentScope();
  3120. if (pnodeBlock->blockType == PnodeBlockType::Function)
  3121. {
  3122. AnalysisAssert(pnodeBlock->scope);
  3123. if (pnodeBlock->scope->GetScopeType() == ScopeType_Parameter
  3124. && scope->GetScopeType() == ScopeType_FunctionBody)
  3125. {
  3126. scope = scope->GetEnclosingScope();
  3127. }
  3128. }
  3129. pnodeBlock->scope = scope;
  3130. }
  3131. else if (!(pnodeBlock->grfpn & fpnSyntheticNode) || isGlobalEvalBlockScope)
  3132. {
  3133. scope = pnodeBlock->scope;
  3134. if (!scope)
  3135. {
  3136. scope = Anew(alloc, Scope, alloc,
  3137. isGlobalEvalBlockScope? ScopeType_GlobalEvalBlock : ScopeType_Block, true);
  3138. pnodeBlock->scope = scope;
  3139. }
  3140. scope->SetFunc(byteCodeGenerator->TopFuncInfo());
  3141. // For now, prevent block scope from being merged with enclosing function scope.
  3142. // Consider optimizing this.
  3143. scope->SetCanMerge(false);
  3144. if (isGlobalEvalBlockScope)
  3145. {
  3146. scope->SetIsObject();
  3147. }
  3148. byteCodeGenerator->PushScope(scope);
  3149. byteCodeGenerator->PushBlock(pnodeBlock);
  3150. }
  3151. else
  3152. {
  3153. return;
  3154. }
  3155. Assert(scope && scope == pnodeBlock->scope);
  3156. bool isGlobalScope = (scope->GetEnclosingScope() == nullptr);
  3157. Assert(!isGlobalScope || (pnodeBlock->grfpn & fpnSyntheticNode));
  3158. // If it is the global eval block scope, we don't what function decl to be assigned in the block scope.
  3159. // They should already declared in the global function's scope.
  3160. if (!isGlobalEvalBlockScope && !isGlobalScope)
  3161. {
  3162. AddFunctionsToScope(pnodeBlock->pnodeScopes, byteCodeGenerator);
  3163. }
  3164. // We can skip this check by not creating the GlobalEvalBlock above and in Parser::Parse for console eval but that seems to break couple of places
  3165. // as we heavily depend on BlockHasOwnScope function. Once we clean up the creation of GlobalEvalBlock for evals we can clean this as well.
  3166. if (byteCodeGenerator->IsConsoleScopeEval() && isGlobalEvalBlockScope && !isGlobalScope)
  3167. {
  3168. AssertMsg(scope->GetEnclosingScope()->GetScopeType() == ScopeType_Global, "Additional scope between Global and GlobalEvalBlock?");
  3169. scope = scope->GetEnclosingScope();
  3170. isGlobalScope = true;
  3171. }
  3172. auto addSymbolToScope = [scope, byteCodeGenerator, isGlobalScope](ParseNode *pnode)
  3173. {
  3174. Symbol *sym = byteCodeGenerator->AddSymbolToScope(scope, reinterpret_cast<const char16*>(pnode->AsParseNodeVar()->pid->Psz()), pnode->AsParseNodeVar()->pid->Cch(), pnode, STVariable);
  3175. #if DBG_DUMP
  3176. if (sym->GetSymbolType() == STVariable && byteCodeGenerator->Trace())
  3177. {
  3178. Output::Print(_u("current context has declared %s %s of type %s\n"),
  3179. sym->GetDecl()->nop == knopLetDecl ? _u("let") : _u("const"),
  3180. pnode->AsParseNodeVar()->pid->Psz(),
  3181. sym->GetSymbolTypeName());
  3182. }
  3183. #endif
  3184. sym->SetIsGlobal(isGlobalScope);
  3185. sym->SetIsBlockVar(true);
  3186. sym->SetIsConst(pnode->nop == knopConstDecl);
  3187. sym->SetNeedDeclaration(true);
  3188. pnode->AsParseNodeVar()->sym = sym;
  3189. };
  3190. byteCodeGenerator->IterateBlockScopedVariables(pnodeBlock, addSymbolToScope);
  3191. }
  3192. void PostVisitBlock(ParseNodeBlock *pnodeBlock, ByteCodeGenerator *byteCodeGenerator)
  3193. {
  3194. if (!BlockHasOwnScope(pnodeBlock, byteCodeGenerator))
  3195. {
  3196. return;
  3197. }
  3198. Scope *scope = pnodeBlock->scope;
  3199. if (pnodeBlock->GetCallsEval() || pnodeBlock->GetChildCallsEval() || (byteCodeGenerator->GetFlags() & (fscrEval | fscrImplicitThis)))
  3200. {
  3201. bool scopeIsEmpty = scope->IsEmpty();
  3202. scope->SetIsObject();
  3203. scope->SetCapturesAll(true);
  3204. scope->SetMustInstantiate(!scopeIsEmpty);
  3205. }
  3206. if (scope->GetHasOwnLocalInClosure())
  3207. {
  3208. byteCodeGenerator->ProcessScopeWithCapturedSym(scope);
  3209. }
  3210. byteCodeGenerator->PopScope();
  3211. byteCodeGenerator->PopBlock();
  3212. ParseNodeBlock *currentBlock = byteCodeGenerator->GetCurrentBlock();
  3213. if (currentBlock && (pnodeBlock->GetCallsEval() || pnodeBlock->GetChildCallsEval()))
  3214. {
  3215. currentBlock->SetChildCallsEval(true);
  3216. }
  3217. }
  3218. void PreVisitCatch(ParseNodeCatch *pnodeCatch, ByteCodeGenerator *byteCodeGenerator)
  3219. {
  3220. // Push the catch scope and add the catch expression to it.
  3221. byteCodeGenerator->StartBindCatch(pnodeCatch);
  3222. ParseNode * pnodeParam = pnodeCatch->GetParam();
  3223. if (pnodeParam->nop == knopParamPattern)
  3224. {
  3225. ParseNodeParamPattern * pnodeParamPattern = pnodeParam->AsParseNodeParamPattern();
  3226. Parser::MapBindIdentifier(pnodeParamPattern->pnode1, [&](ParseNodePtr item)
  3227. {
  3228. Symbol *sym = item->AsParseNodeVar()->sym;
  3229. #if DBG_DUMP
  3230. if (byteCodeGenerator->Trace())
  3231. {
  3232. Output::Print(_u("current context has declared catch var %s of type %s\n"),
  3233. item->AsParseNodeVar()->pid->Psz(), sym->GetSymbolTypeName());
  3234. }
  3235. #endif
  3236. sym->SetIsCatch(true);
  3237. sym->SetIsBlockVar(true);
  3238. });
  3239. }
  3240. else
  3241. {
  3242. ParseNodeName * pnodeName = pnodeParam->AsParseNodeName();
  3243. Symbol *sym = *pnodeName->GetSymRef();
  3244. Assert(sym->GetScope() == pnodeCatch->scope);
  3245. #if DBG_DUMP
  3246. if (byteCodeGenerator->Trace())
  3247. {
  3248. Output::Print(_u("current context has declared catch var %s of type %s\n"),
  3249. pnodeName->pid->Psz(), sym->GetSymbolTypeName());
  3250. }
  3251. #endif
  3252. sym->SetIsCatch(true);
  3253. pnodeName->sym = sym;
  3254. }
  3255. // This call will actually add the nested function symbols to the enclosing function scope (which is what we want).
  3256. AddFunctionsToScope(pnodeCatch->pnodeScopes, byteCodeGenerator);
  3257. }
  3258. void PostVisitCatch(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  3259. {
  3260. Scope *scope = pnode->AsParseNodeCatch()->scope;
  3261. if (scope->GetHasOwnLocalInClosure())
  3262. {
  3263. byteCodeGenerator->ProcessScopeWithCapturedSym(scope);
  3264. }
  3265. byteCodeGenerator->EndBindCatch();
  3266. }
  3267. void PreVisitWith(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  3268. {
  3269. ArenaAllocator *alloc = byteCodeGenerator->GetAllocator();
  3270. Scope *scope = Anew(alloc, Scope, alloc, ScopeType_With);
  3271. scope->SetFunc(byteCodeGenerator->TopFuncInfo());
  3272. scope->SetIsDynamic(true);
  3273. pnode->AsParseNodeWith()->scope = scope;
  3274. byteCodeGenerator->PushScope(scope);
  3275. }
  3276. void PostVisitWith(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  3277. {
  3278. byteCodeGenerator->PopScope();
  3279. }
  3280. bool IsMathLibraryId(Js::PropertyId propertyId)
  3281. {
  3282. return (propertyId >= Js::PropertyIds::abs) && (propertyId <= Js::PropertyIds::fround);
  3283. }
  3284. bool IsLibraryFunction(ParseNode* expr, Js::ScriptContext* scriptContext)
  3285. {
  3286. if (expr && expr->nop == knopDot)
  3287. {
  3288. ParseNode* lhs = expr->AsParseNodeBin()->pnode1;
  3289. ParseNode* rhs = expr->AsParseNodeBin()->pnode2;
  3290. if ((lhs != nullptr) && (rhs != nullptr) && (lhs->nop == knopName) && (rhs->nop == knopName))
  3291. {
  3292. Symbol* lsym = lhs->AsParseNodeName()->sym;
  3293. if ((lsym == nullptr || lsym->GetIsGlobal()) && lhs->AsParseNodeName()->PropertyIdFromNameNode() == Js::PropertyIds::Math)
  3294. {
  3295. return IsMathLibraryId(rhs->AsParseNodeName()->PropertyIdFromNameNode());
  3296. }
  3297. }
  3298. }
  3299. return false;
  3300. }
  3301. struct SymCheck
  3302. {
  3303. static const int kMaxInvertedSyms = 8;
  3304. Symbol* syms[kMaxInvertedSyms];
  3305. Symbol* permittedSym;
  3306. int symCount;
  3307. bool result;
  3308. bool cond;
  3309. bool AddSymbol(Symbol* sym)
  3310. {
  3311. if (symCount < kMaxInvertedSyms)
  3312. {
  3313. syms[symCount++] = sym;
  3314. return true;
  3315. }
  3316. else
  3317. {
  3318. return false;
  3319. }
  3320. }
  3321. bool MatchSymbol(Symbol* sym)
  3322. {
  3323. if (sym != permittedSym)
  3324. {
  3325. for (int i = 0; i < symCount; i++)
  3326. {
  3327. if (sym == syms[i])
  3328. {
  3329. return true;
  3330. }
  3331. }
  3332. }
  3333. return false;
  3334. }
  3335. void Init()
  3336. {
  3337. symCount = 0;
  3338. result = true;
  3339. }
  3340. };
  3341. void CheckInvertableExpr(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, SymCheck* symCheck)
  3342. {
  3343. if (symCheck->result)
  3344. {
  3345. switch (pnode->nop)
  3346. {
  3347. case knopName:
  3348. if (symCheck->MatchSymbol(pnode->AsParseNodeName()->sym))
  3349. {
  3350. symCheck->result = false;
  3351. }
  3352. break;
  3353. case knopCall:
  3354. {
  3355. ParseNode* callTarget = pnode->AsParseNodeCall()->pnodeTarget;
  3356. if (callTarget != nullptr)
  3357. {
  3358. if (callTarget->nop == knopName)
  3359. {
  3360. Symbol* sym = callTarget->AsParseNodeName()->sym;
  3361. if (sym && sym->SingleDef())
  3362. {
  3363. ParseNode* decl = sym->GetDecl();
  3364. if (decl == nullptr ||
  3365. decl->nop != knopVarDecl ||
  3366. !IsLibraryFunction(decl->AsParseNodeVar()->pnodeInit, byteCodeGenerator->GetScriptContext()))
  3367. {
  3368. symCheck->result = false;
  3369. }
  3370. }
  3371. else
  3372. {
  3373. symCheck->result = false;
  3374. }
  3375. }
  3376. else if (callTarget->nop == knopDot)
  3377. {
  3378. if (!IsLibraryFunction(callTarget, byteCodeGenerator->GetScriptContext()))
  3379. {
  3380. symCheck->result = false;
  3381. }
  3382. }
  3383. }
  3384. else
  3385. {
  3386. symCheck->result = false;
  3387. }
  3388. break;
  3389. }
  3390. case knopDot:
  3391. if (!IsLibraryFunction(pnode, byteCodeGenerator->GetScriptContext()))
  3392. {
  3393. symCheck->result = false;
  3394. }
  3395. break;
  3396. case knopTrue:
  3397. case knopFalse:
  3398. case knopAdd:
  3399. case knopSub:
  3400. case knopDiv:
  3401. case knopMul:
  3402. case knopExpo:
  3403. case knopMod:
  3404. case knopNeg:
  3405. case knopInt:
  3406. case knopFlt:
  3407. case knopLt:
  3408. case knopGt:
  3409. case knopLe:
  3410. case knopGe:
  3411. case knopEq:
  3412. case knopNe:
  3413. break;
  3414. default:
  3415. symCheck->result = false;
  3416. break;
  3417. }
  3418. }
  3419. }
  3420. bool InvertableExpr(SymCheck* symCheck, ParseNode* expr, ByteCodeGenerator* byteCodeGenerator)
  3421. {
  3422. symCheck->result = true;
  3423. symCheck->cond = false;
  3424. symCheck->permittedSym = nullptr;
  3425. VisitIndirect<SymCheck>(expr, byteCodeGenerator, symCheck, &CheckInvertableExpr, nullptr);
  3426. return symCheck->result;
  3427. }
  3428. bool InvertableExprPlus(SymCheck* symCheck, ParseNode* expr, ByteCodeGenerator* byteCodeGenerator, Symbol* permittedSym)
  3429. {
  3430. symCheck->result = true;
  3431. symCheck->cond = true;
  3432. symCheck->permittedSym = permittedSym;
  3433. VisitIndirect<SymCheck>(expr, byteCodeGenerator, symCheck, &CheckInvertableExpr, nullptr);
  3434. return symCheck->result;
  3435. }
  3436. void CheckLocalVarDef(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  3437. {
  3438. Assert(pnode->nop == knopAsg);
  3439. if (pnode->AsParseNodeBin()->pnode1 != nullptr)
  3440. {
  3441. ParseNode *lhs = pnode->AsParseNodeBin()->pnode1;
  3442. if (lhs->nop == knopName)
  3443. {
  3444. Symbol *sym = lhs->AsParseNodeName()->sym;
  3445. if (sym != nullptr)
  3446. {
  3447. sym->RecordDef();
  3448. if (sym->IsUsedInLdElem())
  3449. {
  3450. Ident::TrySetIsUsedInLdElem(pnode->AsParseNodeBin()->pnode2);
  3451. }
  3452. }
  3453. }
  3454. }
  3455. }
  3456. ParseNode* ConstructInvertedStatement(ParseNode* stmt, ByteCodeGenerator* byteCodeGenerator, FuncInfo* funcInfo,
  3457. ParseNodeBin** outerStmtRef)
  3458. {
  3459. if (stmt == nullptr)
  3460. {
  3461. return nullptr;
  3462. }
  3463. ParseNode * cStmt;
  3464. if ((stmt->nop == knopAsg) || (stmt->nop == knopVarDecl))
  3465. {
  3466. ParseNode * rhs = nullptr;
  3467. ParseNode * lhs = nullptr;
  3468. if (stmt->nop == knopAsg)
  3469. {
  3470. rhs = stmt->AsParseNodeBin()->pnode2;
  3471. lhs = stmt->AsParseNodeBin()->pnode1;
  3472. }
  3473. else if (stmt->nop == knopVarDecl)
  3474. {
  3475. rhs = stmt->AsParseNodeVar()->pnodeInit;
  3476. }
  3477. ArenaAllocator * alloc = byteCodeGenerator->GetAllocator();
  3478. ParseNodeVar * loopInvar = Parser::StaticCreateTempNode(rhs, alloc);
  3479. loopInvar->location = funcInfo->NextVarRegister();
  3480. // Can't use a temp register here because the inversion happens at the parse tree level without generating
  3481. // any bytecode yet. All local non-temp registers need to be initialized for jitted loop bodies, and since this is
  3482. // not a user variable, track this register separately to have it be initialized at the top of the function.
  3483. funcInfo->nonUserNonTempRegistersToInitialize.Add(loopInvar->location);
  3484. // add temp node to list of initializers for new outer loop
  3485. if ((*outerStmtRef)->pnode1 == nullptr)
  3486. {
  3487. (*outerStmtRef)->pnode1 = loopInvar;
  3488. }
  3489. else
  3490. {
  3491. ParseNodeBin * listNode = Parser::StaticCreateBinNode(knopList, nullptr, nullptr, alloc);
  3492. (*outerStmtRef)->pnode2 = listNode;
  3493. listNode->pnode1 = loopInvar;
  3494. *outerStmtRef = listNode;
  3495. }
  3496. ParseNodeUni * tempName = Parser::StaticCreateTempRef(loopInvar, alloc);
  3497. if (lhs != nullptr)
  3498. {
  3499. cStmt = Parser::StaticCreateBinNode(knopAsg, lhs, tempName, alloc);
  3500. }
  3501. else
  3502. {
  3503. // Use AddVarDeclNode to add the var to the function.
  3504. // Do not use CreateVarDeclNode which is meant to be used while parsing. It assumes that
  3505. // parser's internal data structures (m_ppnodeVar in particular) is at the "current" location.
  3506. cStmt = byteCodeGenerator->GetParser()->AddVarDeclNode(stmt->AsParseNodeVar()->pid, funcInfo->root);
  3507. cStmt->AsParseNodeVar()->pnodeInit = tempName;
  3508. cStmt->AsParseNodeVar()->sym = stmt->AsParseNodeVar()->sym;
  3509. }
  3510. }
  3511. else
  3512. {
  3513. cStmt = byteCodeGenerator->GetParser()->CopyPnode(stmt);
  3514. }
  3515. return cStmt;
  3516. }
  3517. ParseNodeFor* ConstructInvertedLoop(ParseNode* innerLoop, ParseNode* outerLoop, ByteCodeGenerator* byteCodeGenerator, FuncInfo* funcInfo)
  3518. {
  3519. ArenaAllocator* alloc = byteCodeGenerator->GetAllocator();
  3520. ParseNodeFor * outerLoopC = Parser::StaticCreateNodeT<knopFor>(alloc);
  3521. outerLoopC->pnodeInit = innerLoop->AsParseNodeFor()->pnodeInit;
  3522. outerLoopC->pnodeCond = innerLoop->AsParseNodeFor()->pnodeCond;
  3523. outerLoopC->pnodeIncr = innerLoop->AsParseNodeFor()->pnodeIncr;
  3524. outerLoopC->pnodeBlock = innerLoop->AsParseNodeFor()->pnodeBlock;
  3525. outerLoopC->pnodeInverted = nullptr;
  3526. ParseNodeFor * innerLoopC = Parser::StaticCreateNodeT<knopFor>(alloc);
  3527. innerLoopC->pnodeInit = outerLoop->AsParseNodeFor()->pnodeInit;
  3528. innerLoopC->pnodeCond = outerLoop->AsParseNodeFor()->pnodeCond;
  3529. innerLoopC->pnodeIncr = outerLoop->AsParseNodeFor()->pnodeIncr;
  3530. innerLoopC->pnodeBlock = outerLoop->AsParseNodeFor()->pnodeBlock;
  3531. innerLoopC->pnodeInverted = nullptr;
  3532. ParseNodeBlock * innerBod = Parser::StaticCreateBlockNode(alloc);
  3533. innerLoopC->pnodeBody = innerBod;
  3534. innerBod->scope = innerLoop->AsParseNodeFor()->pnodeBody->AsParseNodeBlock()->scope;
  3535. ParseNodeBlock * outerBod = Parser::StaticCreateBlockNode(alloc);
  3536. outerLoopC->pnodeBody = outerBod;
  3537. outerBod->scope = outerLoop->AsParseNodeFor()->pnodeBody->AsParseNodeBlock()->scope;
  3538. ParseNodeBin * listNode = Parser::StaticCreateBinNode(knopList, nullptr, nullptr, alloc);
  3539. outerBod->pnodeStmt = listNode;
  3540. ParseNode* innerBodOriginal = innerLoop->AsParseNodeFor()->pnodeBody;
  3541. ParseNode* origStmt = innerBodOriginal->AsParseNodeBlock()->pnodeStmt;
  3542. if (origStmt->nop == knopList)
  3543. {
  3544. ParseNode* invertedStmt = nullptr;
  3545. while (origStmt->nop == knopList)
  3546. {
  3547. ParseNode* invertedItem = ConstructInvertedStatement(origStmt->AsParseNodeBin()->pnode1, byteCodeGenerator, funcInfo, &listNode);
  3548. ParseNode * newInvertedStmt = Parser::StaticCreateBinNode(knopList, invertedItem, nullptr, alloc, invertedItem->ichMin, invertedItem->ichLim);
  3549. if (invertedStmt != nullptr)
  3550. {
  3551. invertedStmt = invertedStmt->AsParseNodeBin()->pnode2 = newInvertedStmt;
  3552. }
  3553. else
  3554. {
  3555. invertedStmt = innerBod->pnodeStmt = newInvertedStmt;
  3556. }
  3557. origStmt = origStmt->AsParseNodeBin()->pnode2;
  3558. }
  3559. Assert(invertedStmt != nullptr);
  3560. invertedStmt->AsParseNodeBin()->pnode2 = ConstructInvertedStatement(origStmt, byteCodeGenerator, funcInfo, &listNode);
  3561. }
  3562. else
  3563. {
  3564. innerBod->pnodeStmt = ConstructInvertedStatement(origStmt, byteCodeGenerator, funcInfo, &listNode);
  3565. }
  3566. if (listNode->pnode1 == nullptr)
  3567. {
  3568. listNode->pnode1 = Parser::StaticCreateTempNode(nullptr, alloc);
  3569. }
  3570. listNode->pnode2 = innerLoopC;
  3571. return outerLoopC;
  3572. }
  3573. bool InvertableStmt(ParseNode* stmt, Symbol* outerVar, ParseNode* innerLoop, ParseNode* outerLoop, ByteCodeGenerator* byteCodeGenerator, SymCheck* symCheck)
  3574. {
  3575. if (stmt != nullptr)
  3576. {
  3577. ParseNode* lhs = nullptr;
  3578. ParseNode* rhs = nullptr;
  3579. if (stmt->nop == knopAsg)
  3580. {
  3581. lhs = stmt->AsParseNodeBin()->pnode1;
  3582. rhs = stmt->AsParseNodeBin()->pnode2;
  3583. }
  3584. else if (stmt->nop == knopVarDecl)
  3585. {
  3586. rhs = stmt->AsParseNodeVar()->pnodeInit;
  3587. }
  3588. if (lhs != nullptr)
  3589. {
  3590. if (lhs->nop == knopDot)
  3591. {
  3592. return false;
  3593. }
  3594. if (lhs->nop == knopName)
  3595. {
  3596. if ((lhs->AsParseNodeName()->sym != nullptr) && (lhs->AsParseNodeName()->sym->GetIsGlobal()))
  3597. {
  3598. return false;
  3599. }
  3600. }
  3601. else if (lhs->nop == knopIndex)
  3602. {
  3603. ParseNode* indexed = lhs->AsParseNodeBin()->pnode1;
  3604. ParseNode* index = lhs->AsParseNodeBin()->pnode2;
  3605. if ((index == nullptr) || (indexed == nullptr))
  3606. {
  3607. return false;
  3608. }
  3609. if ((indexed->nop != knopName) || (indexed->AsParseNodeName()->sym == nullptr))
  3610. {
  3611. return false;
  3612. }
  3613. if (!InvertableExprPlus(symCheck, index, byteCodeGenerator, outerVar))
  3614. {
  3615. return false;
  3616. }
  3617. }
  3618. }
  3619. if (rhs != nullptr)
  3620. {
  3621. if (!InvertableExpr(symCheck, rhs, byteCodeGenerator))
  3622. {
  3623. return false;
  3624. }
  3625. }
  3626. else
  3627. {
  3628. if (!InvertableExpr(symCheck, stmt, byteCodeGenerator))
  3629. {
  3630. return false;
  3631. }
  3632. }
  3633. return true;
  3634. }
  3635. return false;
  3636. }
  3637. bool GatherInversionSyms(ParseNode* stmt, Symbol* outerVar, ParseNode* innerLoop, ByteCodeGenerator* byteCodeGenerator, SymCheck* symCheck)
  3638. {
  3639. if (stmt != nullptr)
  3640. {
  3641. ParseNode* lhs = nullptr;
  3642. Symbol* auxSym = nullptr;
  3643. if (stmt->nop == knopAsg)
  3644. {
  3645. lhs = stmt->AsParseNodeBin()->pnode1;
  3646. }
  3647. else if (stmt->nop == knopVarDecl)
  3648. {
  3649. auxSym = stmt->AsParseNodeVar()->sym;
  3650. }
  3651. if (lhs != nullptr)
  3652. {
  3653. if (lhs->nop == knopDot)
  3654. {
  3655. return false;
  3656. }
  3657. if (lhs->nop == knopName)
  3658. {
  3659. ParseNodeName * pnodeNameLhs = lhs->AsParseNodeName();
  3660. if ((pnodeNameLhs->sym == nullptr) || (pnodeNameLhs->sym->GetIsGlobal()))
  3661. {
  3662. return false;
  3663. }
  3664. else
  3665. {
  3666. auxSym = pnodeNameLhs->sym;
  3667. }
  3668. }
  3669. }
  3670. if (auxSym != nullptr)
  3671. {
  3672. return symCheck->AddSymbol(auxSym);
  3673. }
  3674. }
  3675. return true;
  3676. }
  3677. bool InvertableBlock(ParseNode* block, Symbol* outerVar, ParseNode* innerLoop, ParseNode* outerLoop, ByteCodeGenerator* byteCodeGenerator,
  3678. SymCheck* symCheck)
  3679. {
  3680. if (block == nullptr)
  3681. {
  3682. return false;
  3683. }
  3684. if (!symCheck->AddSymbol(outerVar))
  3685. {
  3686. return false;
  3687. }
  3688. if ((innerLoop->AsParseNodeFor()->pnodeBody->nop == knopBlock && innerLoop->AsParseNodeFor()->pnodeBody->AsParseNodeBlock()->HasBlockScopedContent())
  3689. || (outerLoop->AsParseNodeFor()->pnodeBody->nop == knopBlock && outerLoop->AsParseNodeFor()->pnodeBody->AsParseNodeBlock()->HasBlockScopedContent()))
  3690. {
  3691. // we can not invert loops if there are block scoped declarations inside
  3692. return false;
  3693. }
  3694. if ((block != nullptr) && (block->nop == knopBlock))
  3695. {
  3696. ParseNode* stmt = block->AsParseNodeBlock()->pnodeStmt;
  3697. while ((stmt != nullptr) && (stmt->nop == knopList))
  3698. {
  3699. if (!GatherInversionSyms(stmt->AsParseNodeBin()->pnode1, outerVar, innerLoop, byteCodeGenerator, symCheck))
  3700. {
  3701. return false;
  3702. }
  3703. stmt = stmt->AsParseNodeBin()->pnode2;
  3704. }
  3705. if (!GatherInversionSyms(stmt, outerVar, innerLoop, byteCodeGenerator, symCheck))
  3706. {
  3707. return false;
  3708. }
  3709. stmt = block->AsParseNodeBlock()->pnodeStmt;
  3710. while ((stmt != nullptr) && (stmt->nop == knopList))
  3711. {
  3712. if (!InvertableStmt(stmt->AsParseNodeBin()->pnode1, outerVar, innerLoop, outerLoop, byteCodeGenerator, symCheck))
  3713. {
  3714. return false;
  3715. }
  3716. stmt = stmt->AsParseNodeBin()->pnode2;
  3717. }
  3718. if (!InvertableStmt(stmt, outerVar, innerLoop, outerLoop, byteCodeGenerator, symCheck))
  3719. {
  3720. return false;
  3721. }
  3722. return (InvertableExprPlus(symCheck, innerLoop->AsParseNodeFor()->pnodeCond, byteCodeGenerator, nullptr) &&
  3723. InvertableExprPlus(symCheck, outerLoop->AsParseNodeFor()->pnodeCond, byteCodeGenerator, outerVar));
  3724. }
  3725. else
  3726. {
  3727. return false;
  3728. }
  3729. }
  3730. // Start of invert loop optimization.
  3731. // For now, find simple cases (only for loops around single assignment).
  3732. // Returns new AST for inverted loop; also returns in out param
  3733. // side effects level, if any that guards the new AST (old AST will be
  3734. // used if guard fails).
  3735. // Should only be called with loopNode representing top-level statement.
  3736. ParseNodeFor* InvertLoop(ParseNode* outerLoop, ByteCodeGenerator* byteCodeGenerator, FuncInfo* funcInfo)
  3737. {
  3738. if (byteCodeGenerator->GetScriptContext()->optimizationOverrides.GetSideEffects() != Js::SideEffects_None)
  3739. {
  3740. return nullptr;
  3741. }
  3742. SymCheck symCheck;
  3743. symCheck.Init();
  3744. if (outerLoop->nop == knopFor)
  3745. {
  3746. ParseNode* innerLoop = outerLoop->AsParseNodeFor()->pnodeBody;
  3747. if ((innerLoop == nullptr) || (innerLoop->nop != knopBlock))
  3748. {
  3749. return nullptr;
  3750. }
  3751. else
  3752. {
  3753. innerLoop = innerLoop->AsParseNodeBlock()->pnodeStmt;
  3754. }
  3755. if ((innerLoop != nullptr) && (innerLoop->nop == knopFor))
  3756. {
  3757. if ((outerLoop->AsParseNodeFor()->pnodeInit != nullptr) &&
  3758. (outerLoop->AsParseNodeFor()->pnodeInit->nop == knopVarDecl) &&
  3759. (outerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->pnodeInit != nullptr) &&
  3760. (outerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->pnodeInit->nop == knopInt) &&
  3761. (outerLoop->AsParseNodeFor()->pnodeIncr != nullptr) &&
  3762. ((outerLoop->AsParseNodeFor()->pnodeIncr->nop == knopIncPre) || (outerLoop->AsParseNodeFor()->pnodeIncr->nop == knopIncPost)) &&
  3763. (outerLoop->AsParseNodeFor()->pnodeIncr->AsParseNodeUni()->pnode1->nop == knopName) &&
  3764. (outerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->pid == outerLoop->AsParseNodeFor()->pnodeIncr->AsParseNodeUni()->pnode1->AsParseNodeName()->pid) &&
  3765. (innerLoop->AsParseNodeFor()->pnodeIncr != nullptr) &&
  3766. ((innerLoop->AsParseNodeFor()->pnodeIncr->nop == knopIncPre) || (innerLoop->AsParseNodeFor()->pnodeIncr->nop == knopIncPost)) &&
  3767. (innerLoop->AsParseNodeFor()->pnodeInit != nullptr) &&
  3768. (innerLoop->AsParseNodeFor()->pnodeInit->nop == knopVarDecl) &&
  3769. (innerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->pnodeInit != nullptr) &&
  3770. (innerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->pnodeInit->nop == knopInt) &&
  3771. (innerLoop->AsParseNodeFor()->pnodeIncr->AsParseNodeUni()->pnode1->nop == knopName) &&
  3772. (innerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->pid == innerLoop->AsParseNodeFor()->pnodeIncr->AsParseNodeUni()->pnode1->AsParseNodeName()->pid))
  3773. {
  3774. Symbol* outerVar = outerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->sym;
  3775. Symbol* innerVar = innerLoop->AsParseNodeFor()->pnodeInit->AsParseNodeVar()->sym;
  3776. if ((outerVar != nullptr) && (innerVar != nullptr))
  3777. {
  3778. ParseNode* block = innerLoop->AsParseNodeFor()->pnodeBody;
  3779. if (InvertableBlock(block, outerVar, innerLoop, outerLoop, byteCodeGenerator, &symCheck))
  3780. {
  3781. return ConstructInvertedLoop(innerLoop, outerLoop, byteCodeGenerator, funcInfo);
  3782. }
  3783. }
  3784. }
  3785. }
  3786. }
  3787. return nullptr;
  3788. }
  3789. void SetAdditionalBindInfoForVariables(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  3790. {
  3791. Symbol *sym = pnode->AsParseNodeVar()->sym;
  3792. if (sym == nullptr)
  3793. {
  3794. return;
  3795. }
  3796. FuncInfo* func = byteCodeGenerator->TopFuncInfo();
  3797. if (!sym->GetIsGlobal() && !sym->IsArguments() &&
  3798. (sym->GetScope() == func->GetBodyScope() || sym->GetScope() == func->GetParamScope() || sym->GetScope()->GetCanMerge()))
  3799. {
  3800. if (func->GetChildCallsEval())
  3801. {
  3802. func->SetHasLocalInClosure(true);
  3803. }
  3804. else
  3805. {
  3806. sym->RecordDef();
  3807. }
  3808. }
  3809. if (sym->IsUsedInLdElem())
  3810. {
  3811. Ident::TrySetIsUsedInLdElem(pnode->AsParseNodeVar()->pnodeInit);
  3812. }
  3813. // If this decl does an assignment inside a loop body, then there's a chance
  3814. // that a jitted loop body will expect us to begin with a valid value in this var.
  3815. // So mark the sym as used so that we guarantee the var will at least get "undefined".
  3816. if (byteCodeGenerator->IsInLoop() &&
  3817. pnode->AsParseNodeVar()->pnodeInit)
  3818. {
  3819. sym->SetIsUsed(true);
  3820. }
  3821. }
  3822. // bind references to definitions (prefix pass)
  3823. void Bind(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  3824. {
  3825. if (pnode == nullptr)
  3826. {
  3827. return;
  3828. }
  3829. switch (pnode->nop)
  3830. {
  3831. case knopBreak:
  3832. case knopContinue:
  3833. byteCodeGenerator->AddTargetStmt(pnode->AsParseNodeJump()->pnodeTarget);
  3834. break;
  3835. case knopProg:
  3836. {
  3837. FuncInfo* globFuncInfo = byteCodeGenerator->StartBindGlobalStatements(pnode->AsParseNodeProg());
  3838. pnode->AsParseNodeFnc()->funcInfo = globFuncInfo;
  3839. AddFunctionsToScope(pnode->AsParseNodeFnc()->GetTopLevelScope(), byteCodeGenerator);
  3840. AddVarsToScope(pnode->AsParseNodeFnc()->pnodeVars, byteCodeGenerator);
  3841. // There are no args to add, but "eval" gets a this pointer.
  3842. byteCodeGenerator->SetNumberOfInArgs(!!(byteCodeGenerator->GetFlags() & fscrEvalCode));
  3843. if (!globFuncInfo->IsFakeGlobalFunction(byteCodeGenerator->GetFlags()))
  3844. {
  3845. // Global code: the root function is the global function.
  3846. byteCodeGenerator->SetRootFuncInfo(globFuncInfo);
  3847. }
  3848. else if (globFuncInfo->byteCodeFunction)
  3849. {
  3850. // If the current global code wasn't marked to be treated as global code (e.g. from deferred parsing),
  3851. // we don't need to send a register script event for it.
  3852. globFuncInfo->byteCodeFunction->SetIsTopLevel(false);
  3853. }
  3854. if (pnode->AsParseNodeFnc()->CallsEval())
  3855. {
  3856. globFuncInfo->SetCallsEval(true);
  3857. }
  3858. break;
  3859. }
  3860. case knopFncDecl:
  3861. if (pnode->AsParseNodeFnc()->IsCoroutine())
  3862. {
  3863. // Always assume generator functions escape since tracking them requires tracking
  3864. // the resulting generators in addition to the function.
  3865. byteCodeGenerator->FuncEscapes(byteCodeGenerator->TopFuncInfo()->GetBodyScope());
  3866. }
  3867. if (!pnode->AsParseNodeFnc()->IsDeclaration())
  3868. {
  3869. FuncInfo *funcInfo = byteCodeGenerator->TopFuncInfo();
  3870. if (!funcInfo->IsGlobalFunction() || (byteCodeGenerator->GetFlags() & fscrEval))
  3871. {
  3872. // In the case of a nested function expression, assumes that it escapes.
  3873. // We could try to analyze what it touches to be more precise.
  3874. byteCodeGenerator->FuncEscapes(funcInfo->GetBodyScope());
  3875. }
  3876. byteCodeGenerator->ProcessCapturedSyms(pnode);
  3877. }
  3878. else if (byteCodeGenerator->IsInLoop())
  3879. {
  3880. Symbol *funcSym = pnode->AsParseNodeFnc()->GetFuncSymbol();
  3881. if (funcSym)
  3882. {
  3883. Symbol *funcVarSym = funcSym->GetFuncScopeVarSym();
  3884. if (funcVarSym)
  3885. {
  3886. // We're going to write to the funcVarSym when we do the function instantiation,
  3887. // so treat the funcVarSym as used. That way, we know it will get undef-initialized at the
  3888. // top of the function, so a jitted loop body won't have any issue with boxing if
  3889. // the function instantiation isn't executed.
  3890. Assert(funcVarSym != funcSym);
  3891. funcVarSym->SetIsUsed(true);
  3892. }
  3893. }
  3894. }
  3895. break;
  3896. case knopName:
  3897. {
  3898. ParseNodeName * pnodeName = pnode->AsParseNodeName();
  3899. if (pnodeName->sym == nullptr)
  3900. {
  3901. if (pnodeName->grfpn & fpnMemberReference)
  3902. {
  3903. // This is a member name. No binding.
  3904. break;
  3905. }
  3906. Symbol *sym = byteCodeGenerator->FindSymbol(pnodeName->GetSymRef(), pnodeName->pid);
  3907. if (sym)
  3908. {
  3909. // This is a named load, not just a reference, so if it's a nested function note that all
  3910. // the nested scopes escape.
  3911. Assert(!sym->GetDecl() || (pnodeName->GetSymRef() && *pnodeName->GetSymRef()));
  3912. Assert(!sym->GetDecl() || ((*pnodeName->GetSymRef())->GetDecl() == sym->GetDecl()) ||
  3913. ((*pnodeName->GetSymRef())->GetFuncScopeVarSym() == sym));
  3914. pnodeName->sym = sym;
  3915. if (sym->GetSymbolType() == STFunction &&
  3916. (!sym->GetIsGlobal() || (byteCodeGenerator->GetFlags() & fscrEval)))
  3917. {
  3918. byteCodeGenerator->FuncEscapes(sym->GetScope());
  3919. }
  3920. }
  3921. }
  3922. if (pnodeName->sym)
  3923. {
  3924. pnodeName->sym->SetIsUsed(true);
  3925. }
  3926. break;
  3927. }
  3928. case knopMember:
  3929. case knopMemberShort:
  3930. case knopObjectPatternMember:
  3931. case knopGetMember:
  3932. case knopSetMember:
  3933. {
  3934. // lhs is knopStr, rhs is expr
  3935. ParseNode *id = pnode->AsParseNodeBin()->pnode1;
  3936. if (id->nop == knopStr)
  3937. {
  3938. byteCodeGenerator->AssignPropertyId(id->AsParseNodeStr()->pid);
  3939. id->grfpn |= fpnMemberReference;
  3940. }
  3941. break;
  3942. }
  3943. // TODO: convert index over string to Get/Put Value
  3944. case knopIndex:
  3945. BindReference(pnode, byteCodeGenerator);
  3946. break;
  3947. case knopDot:
  3948. BindInstAndMember(pnode, byteCodeGenerator);
  3949. break;
  3950. case knopTryFinally:
  3951. byteCodeGenerator->SetHasFinally(true);
  3952. case knopTryCatch:
  3953. byteCodeGenerator->SetHasTry(true);
  3954. byteCodeGenerator->TopFuncInfo()->byteCodeFunction->SetDontInline(true);
  3955. byteCodeGenerator->AddTargetStmt(pnode->AsParseNodeStmt());
  3956. break;
  3957. case knopAsg:
  3958. BindReference(pnode, byteCodeGenerator);
  3959. CheckLocalVarDef(pnode, byteCodeGenerator);
  3960. break;
  3961. case knopVarDecl:
  3962. // "arguments" symbol or decl w/o RHS may have been bound already; otherwise, do the binding here.
  3963. if (pnode->AsParseNodeVar()->sym == nullptr)
  3964. {
  3965. pnode->AsParseNodeVar()->sym = byteCodeGenerator->FindSymbol(pnode->AsParseNodeVar()->symRef, pnode->AsParseNodeVar()->pid);
  3966. }
  3967. SetAdditionalBindInfoForVariables(pnode, byteCodeGenerator);
  3968. break;
  3969. case knopConstDecl:
  3970. case knopLetDecl:
  3971. // "arguments" symbol or decl w/o RHS may have been bound already; otherwise, do the binding here.
  3972. if (!pnode->AsParseNodeVar()->sym)
  3973. {
  3974. AssertMsg(pnode->AsParseNodeVar()->symRef && *pnode->AsParseNodeVar()->symRef, "'const' and 'let' should be binded when we bind block");
  3975. pnode->AsParseNodeVar()->sym = *pnode->AsParseNodeVar()->symRef;
  3976. }
  3977. SetAdditionalBindInfoForVariables(pnode, byteCodeGenerator);
  3978. break;
  3979. case knopCall:
  3980. case knopTypeof:
  3981. case knopDelete:
  3982. BindReference(pnode, byteCodeGenerator);
  3983. break;
  3984. case knopRegExp:
  3985. pnode->AsParseNodeRegExp()->regexPatternIndex = byteCodeGenerator->TopFuncInfo()->GetParsedFunctionBody()->NewLiteralRegex();
  3986. break;
  3987. case knopComma:
  3988. pnode->AsParseNodeBin()->pnode1->SetNotEscapedUse();
  3989. break;
  3990. case knopBlock:
  3991. {
  3992. for (ParseNode *pnodeScope = pnode->AsParseNodeBlock()->pnodeScopes; pnodeScope; /* no increment */)
  3993. {
  3994. switch (pnodeScope->nop)
  3995. {
  3996. case knopFncDecl:
  3997. if (pnodeScope->AsParseNodeFnc()->IsDeclaration())
  3998. {
  3999. byteCodeGenerator->ProcessCapturedSyms(pnodeScope);
  4000. }
  4001. pnodeScope = pnodeScope->AsParseNodeFnc()->pnodeNext;
  4002. break;
  4003. case knopBlock:
  4004. pnodeScope = pnodeScope->AsParseNodeBlock()->pnodeNext;
  4005. break;
  4006. case knopCatch:
  4007. pnodeScope = pnodeScope->AsParseNodeCatch()->pnodeNext;
  4008. break;
  4009. case knopWith:
  4010. pnodeScope = pnodeScope->AsParseNodeWith()->pnodeNext;
  4011. break;
  4012. }
  4013. }
  4014. break;
  4015. }
  4016. }
  4017. }
  4018. void ByteCodeGenerator::ProcessCapturedSyms(ParseNode *pnode)
  4019. {
  4020. SymbolTable *capturedSyms = pnode->AsParseNodeFnc()->funcInfo->GetCapturedSyms();
  4021. if (capturedSyms)
  4022. {
  4023. FuncInfo *funcInfo = this->TopFuncInfo();
  4024. CapturedSymMap *capturedSymMap = funcInfo->EnsureCapturedSymMap();
  4025. ParseNode *pnodeStmt = this->GetCurrentTopStatement();
  4026. SList<Symbol*> *capturedSymList;
  4027. if (!pnodeStmt->CapturesSyms())
  4028. {
  4029. capturedSymList = Anew(this->alloc, SList<Symbol*>, this->alloc);
  4030. capturedSymMap->Add(pnodeStmt, capturedSymList);
  4031. pnodeStmt->SetCapturesSyms();
  4032. }
  4033. else
  4034. {
  4035. capturedSymList = capturedSymMap->Item(pnodeStmt);
  4036. }
  4037. capturedSyms->Map([&](Symbol *sym)
  4038. {
  4039. if (!sym->GetIsCommittedToSlot() && !sym->HasVisitedCapturingFunc())
  4040. {
  4041. capturedSymList->Prepend(sym);
  4042. sym->SetHasVisitedCapturingFunc();
  4043. }
  4044. });
  4045. }
  4046. }
  4047. void ByteCodeGenerator::FuncEscapes(Scope *scope)
  4048. {
  4049. while (scope)
  4050. {
  4051. Assert(scope->GetFunc());
  4052. scope->GetFunc()->SetEscapes(true);
  4053. scope = scope->GetEnclosingScope();
  4054. }
  4055. if (this->flags & fscrEval)
  4056. {
  4057. // If a function declared inside eval escapes, we'll need
  4058. // to invalidate the caller's cached scope.
  4059. this->funcEscapes = true;
  4060. }
  4061. }
  4062. bool ByteCodeGenerator::HasInterleavingDynamicScope(Symbol * sym) const
  4063. {
  4064. Js::PropertyId unused;
  4065. return this->InDynamicScope() &&
  4066. sym->GetScope() != this->FindScopeForSym(sym->GetScope(), nullptr, &unused, this->TopFuncInfo());
  4067. }
  4068. void CheckMaybeEscapedUse(ParseNode * pnode, ByteCodeGenerator * byteCodeGenerator, bool isCall = false)
  4069. {
  4070. if (pnode == nullptr)
  4071. {
  4072. return;
  4073. }
  4074. FuncInfo * topFunc = byteCodeGenerator->TopFuncInfo();
  4075. if (topFunc->IsGlobalFunction())
  4076. {
  4077. return;
  4078. }
  4079. switch (pnode->nop)
  4080. {
  4081. case knopAsg:
  4082. if (pnode->AsParseNodeBin()->pnode1->nop != knopName)
  4083. {
  4084. break;
  4085. }
  4086. // use of an assignment (e.g. (y = function() {}) + "1"), just make y an escaped use.
  4087. pnode = pnode->AsParseNodeBin()->pnode1;
  4088. isCall = false;
  4089. // fall-through
  4090. case knopName:
  4091. if (!isCall)
  4092. {
  4093. // Mark the name has having escaped use
  4094. if (pnode->AsParseNodeName()->sym)
  4095. {
  4096. pnode->AsParseNodeName()->sym->SetHasMaybeEscapedUse(byteCodeGenerator);
  4097. }
  4098. }
  4099. break;
  4100. case knopFncDecl:
  4101. // A function declaration has an unknown use (not assignment nor call),
  4102. // mark the function as having child escaped
  4103. topFunc->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("UnknownUse")));
  4104. break;
  4105. }
  4106. }
  4107. void CheckFuncAssignment(Symbol * sym, ParseNode * pnode2, ByteCodeGenerator * byteCodeGenerator)
  4108. {
  4109. if (pnode2 == nullptr)
  4110. {
  4111. return;
  4112. }
  4113. switch (pnode2->nop)
  4114. {
  4115. default:
  4116. CheckMaybeEscapedUse(pnode2, byteCodeGenerator);
  4117. break;
  4118. case knopFncDecl:
  4119. {
  4120. FuncInfo * topFunc = byteCodeGenerator->TopFuncInfo();
  4121. if (topFunc->IsGlobalFunction())
  4122. {
  4123. return;
  4124. }
  4125. // Use not as an assignment or assignment to an outer function's sym, or assigned to a formal
  4126. // or assigned to multiple names.
  4127. if (sym == nullptr
  4128. || sym->GetScope()->GetFunc() != topFunc)
  4129. {
  4130. topFunc->SetHasMaybeEscapedNestedFunc(DebugOnly(
  4131. sym == nullptr ? _u("UnknownAssignment") :
  4132. (sym->GetScope()->GetFunc() != topFunc) ? _u("CrossFuncAssignment") :
  4133. _u("SomethingIsWrong!"))
  4134. );
  4135. }
  4136. else
  4137. {
  4138. // TODO-STACK-NESTED-FUNC: Since we only support single def functions, we can still put the
  4139. // nested function on the stack and reuse even if the function goes out of the block scope.
  4140. // However, we cannot allocate frame display or slots on the stack if the function is
  4141. // declared in a loop, because there might be multiple functions referencing different
  4142. // iterations of the scope.
  4143. // For now, just disable everything.
  4144. Scope * funcParentScope = pnode2->AsParseNodeFnc()->funcInfo->GetBodyScope()->GetEnclosingScope();
  4145. while (sym->GetScope() != funcParentScope)
  4146. {
  4147. if (funcParentScope->GetMustInstantiate())
  4148. {
  4149. topFunc->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("CrossScopeAssignment")));
  4150. break;
  4151. }
  4152. funcParentScope->SetHasCrossScopeFuncAssignment();
  4153. funcParentScope = funcParentScope->GetEnclosingScope();
  4154. }
  4155. // Need to always detect interleaving dynamic scope ('with') for assignments
  4156. // as those may end up escaping into the 'with' scope.
  4157. // TODO: the with scope is marked as MustInstantiate late during byte code emit
  4158. // We could detect this using the loop above as well, by marking the with
  4159. // scope as must instantiate early, this is just less risky of a fix for RTM.
  4160. if (byteCodeGenerator->HasInterleavingDynamicScope(sym))
  4161. {
  4162. byteCodeGenerator->TopFuncInfo()->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("InterleavingDynamicScope")));
  4163. }
  4164. sym->SetHasFuncAssignment(byteCodeGenerator);
  4165. }
  4166. }
  4167. break;
  4168. };
  4169. }
  4170. // Assign permanent (non-temp) registers for the function.
  4171. // These include constants (null, 3.7, this) and locals that use registers as their home locations.
  4172. // Assign the location fields of parse nodes whose values are constants/locals with permanent/known registers.
  4173. // Re-usable expression temps are assigned during the final Emit pass.
  4174. void AssignRegisters(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator)
  4175. {
  4176. if (pnode == nullptr)
  4177. {
  4178. return;
  4179. }
  4180. Symbol *sym;
  4181. OpCode nop = pnode->nop;
  4182. switch (nop)
  4183. {
  4184. default:
  4185. {
  4186. uint flags = ParseNode::Grfnop(nop);
  4187. if (flags & fnopUni)
  4188. {
  4189. CheckMaybeEscapedUse(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator);
  4190. }
  4191. else if (flags & fnopBin)
  4192. {
  4193. CheckMaybeEscapedUse(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator);
  4194. CheckMaybeEscapedUse(pnode->AsParseNodeBin()->pnode2, byteCodeGenerator);
  4195. }
  4196. break;
  4197. }
  4198. case knopParamPattern:
  4199. byteCodeGenerator->AssignUndefinedConstRegister();
  4200. CheckMaybeEscapedUse(pnode->AsParseNodeParamPattern()->pnode1, byteCodeGenerator);
  4201. break;
  4202. case knopObjectPattern:
  4203. case knopArrayPattern:
  4204. byteCodeGenerator->AssignUndefinedConstRegister();
  4205. CheckMaybeEscapedUse(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator);
  4206. break;
  4207. case knopDot:
  4208. CheckMaybeEscapedUse(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator);
  4209. break;
  4210. case knopMember:
  4211. case knopMemberShort:
  4212. case knopGetMember:
  4213. case knopSetMember:
  4214. CheckMaybeEscapedUse(pnode->AsParseNodeBin()->pnode2, byteCodeGenerator);
  4215. break;
  4216. case knopAsg:
  4217. {
  4218. Symbol * symName = pnode->AsParseNodeBin()->pnode1->nop == knopName ? pnode->AsParseNodeBin()->pnode1->AsParseNodeName()->sym : nullptr;
  4219. CheckFuncAssignment(symName, pnode->AsParseNodeBin()->pnode2, byteCodeGenerator);
  4220. if (pnode->IsInList())
  4221. {
  4222. // Assignment in array literal
  4223. CheckMaybeEscapedUse(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator);
  4224. }
  4225. if (byteCodeGenerator->IsES6DestructuringEnabled() && (pnode->AsParseNodeBin()->pnode1->nop == knopArrayPattern || pnode->AsParseNodeBin()->pnode1->nop == knopObjectPattern))
  4226. {
  4227. // Destructured arrays may have default values and need undefined.
  4228. byteCodeGenerator->AssignUndefinedConstRegister();
  4229. // Any rest parameter in a destructured array will need a 0 constant.
  4230. byteCodeGenerator->EnregisterConstant(0);
  4231. }
  4232. break;
  4233. }
  4234. case knopEllipsis:
  4235. if (byteCodeGenerator->InDestructuredPattern())
  4236. {
  4237. // Get a register for the rest array counter.
  4238. pnode->location = byteCodeGenerator->NextVarRegister();
  4239. // Any rest parameter in a destructured array will need a 0 constant.
  4240. byteCodeGenerator->EnregisterConstant(0);
  4241. }
  4242. CheckMaybeEscapedUse(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator);
  4243. break;
  4244. case knopQmark:
  4245. CheckMaybeEscapedUse(pnode->AsParseNodeTri()->pnode1, byteCodeGenerator);
  4246. CheckMaybeEscapedUse(pnode->AsParseNodeTri()->pnode2, byteCodeGenerator);
  4247. CheckMaybeEscapedUse(pnode->AsParseNodeTri()->pnode3, byteCodeGenerator);
  4248. break;
  4249. case knopWith:
  4250. pnode->location = byteCodeGenerator->NextVarRegister();
  4251. CheckMaybeEscapedUse(pnode->AsParseNodeWith()->pnodeObj, byteCodeGenerator);
  4252. break;
  4253. case knopComma:
  4254. if (!pnode->IsNotEscapedUse())
  4255. {
  4256. // Only the last expr in comma expr escape. Mark it if it is escapable.
  4257. CheckMaybeEscapedUse(pnode->AsParseNodeBin()->pnode2, byteCodeGenerator);
  4258. }
  4259. break;
  4260. case knopFncDecl:
  4261. if (!byteCodeGenerator->TopFuncInfo()->IsGlobalFunction())
  4262. {
  4263. if (pnode->AsParseNodeFnc()->IsCoroutine())
  4264. {
  4265. // Assume generators always escape; otherwise need to analyze if
  4266. // the return value of calls to generator function, the generator
  4267. // objects, escape.
  4268. FuncInfo* funcInfo = byteCodeGenerator->TopFuncInfo();
  4269. funcInfo->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("Generator")));
  4270. }
  4271. if (pnode->IsInList() && !pnode->IsNotEscapedUse())
  4272. {
  4273. byteCodeGenerator->TopFuncInfo()->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("InList")));
  4274. }
  4275. ParseNodePtr pnodeName = pnode->AsParseNodeFnc()->pnodeName;
  4276. if (pnodeName != nullptr)
  4277. {
  4278. // REVIEW: does this apply now that compat mode is gone?
  4279. // There is a weird case in compat mode where we may not have a sym assigned to a fnc decl's
  4280. // name node if it is a named function declare inside 'with' that also assigned to something else
  4281. // as well. Instead, We generate two knopFncDecl node one for parent function and one for the assignment.
  4282. // Only the top one gets a sym, not the inner one. The assignment in the 'with' will be using the inner
  4283. // one. Also we will detect that the assignment to a variable is an escape inside a 'with'.
  4284. // Since we need the sym in the fnc decl's name, we just detect the escape here as "WithScopeFuncName".
  4285. if (pnodeName->nop == knopVarDecl && pnodeName->AsParseNodeVar()->sym != nullptr)
  4286. {
  4287. // Unlike in CheckFuncAssignment, we don't check for interleaving
  4288. // dynamic scope ('with') here, because we also generate direct assignment for
  4289. // function decl's names
  4290. pnodeName->AsParseNodeVar()->sym->SetHasFuncAssignment(byteCodeGenerator);
  4291. // Function declaration in block scope and non-strict mode has a
  4292. // corresponding var sym that we assign to as well. Need to
  4293. // mark that symbol as has func assignment as well.
  4294. Symbol * functionScopeVarSym = pnodeName->AsParseNodeVar()->sym->GetFuncScopeVarSym();
  4295. if (functionScopeVarSym)
  4296. {
  4297. functionScopeVarSym->SetHasFuncAssignment(byteCodeGenerator);
  4298. }
  4299. }
  4300. else
  4301. {
  4302. // The function has multiple names, or assign to o.x or o::x
  4303. byteCodeGenerator->TopFuncInfo()->SetHasMaybeEscapedNestedFunc(DebugOnly(
  4304. pnodeName->nop == knopList ? _u("MultipleFuncName") :
  4305. pnodeName->nop == knopDot ? _u("PropFuncName") :
  4306. pnodeName->nop == knopVarDecl && pnodeName->AsParseNodeVar()->sym == nullptr ? _u("WithScopeFuncName") :
  4307. _u("WeirdFuncName")
  4308. ));
  4309. }
  4310. }
  4311. }
  4312. break;
  4313. case knopNew:
  4314. CheckMaybeEscapedUse(pnode->AsParseNodeCall()->pnodeTarget, byteCodeGenerator);
  4315. CheckMaybeEscapedUse(pnode->AsParseNodeCall()->pnodeArgs, byteCodeGenerator);
  4316. break;
  4317. case knopThrow:
  4318. CheckMaybeEscapedUse(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator);
  4319. break;
  4320. // REVIEW: Technically, switch expr or case expr doesn't really escape as strict equal
  4321. // doesn't cause the function to escape.
  4322. case knopSwitch:
  4323. CheckMaybeEscapedUse(pnode->AsParseNodeSwitch()->pnodeVal, byteCodeGenerator);
  4324. break;
  4325. case knopCase:
  4326. CheckMaybeEscapedUse(pnode->AsParseNodeCase()->pnodeExpr, byteCodeGenerator);
  4327. break;
  4328. // REVIEW: Technically, the object for GetForInEnumerator doesn't escape, except when cached,
  4329. // which we can make work.
  4330. case knopForIn:
  4331. CheckMaybeEscapedUse(pnode->AsParseNodeForInOrForOf()->pnodeObj, byteCodeGenerator);
  4332. break;
  4333. case knopForOf:
  4334. byteCodeGenerator->AssignNullConstRegister();
  4335. byteCodeGenerator->AssignUndefinedConstRegister();
  4336. CheckMaybeEscapedUse(pnode->AsParseNodeForInOrForOf()->pnodeObj, byteCodeGenerator);
  4337. break;
  4338. case knopTrue:
  4339. pnode->location = byteCodeGenerator->AssignTrueConstRegister();
  4340. break;
  4341. case knopFalse:
  4342. pnode->location = byteCodeGenerator->AssignFalseConstRegister();
  4343. break;
  4344. case knopDecPost:
  4345. case knopIncPost:
  4346. case knopDecPre:
  4347. case knopIncPre:
  4348. byteCodeGenerator->EnregisterConstant(1);
  4349. CheckMaybeEscapedUse(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator);
  4350. break;
  4351. case knopObject:
  4352. byteCodeGenerator->AssignNullConstRegister();
  4353. break;
  4354. case knopClassDecl:
  4355. {
  4356. FuncInfo * topFunc = byteCodeGenerator->TopFuncInfo();
  4357. topFunc->SetHasMaybeEscapedNestedFunc(DebugOnly(_u("Class")));
  4358. // We may need undefined for the 'this', e.g. calling a class expression
  4359. byteCodeGenerator->AssignUndefinedConstRegister();
  4360. break;
  4361. }
  4362. case knopNull:
  4363. pnode->location = byteCodeGenerator->AssignNullConstRegister();
  4364. break;
  4365. case knopCall:
  4366. {
  4367. if (pnode->AsParseNodeCall()->pnodeTarget->nop != knopIndex &&
  4368. pnode->AsParseNodeCall()->pnodeTarget->nop != knopDot)
  4369. {
  4370. byteCodeGenerator->AssignUndefinedConstRegister();
  4371. }
  4372. FuncInfo *funcInfo = byteCodeGenerator->TopFuncInfo();
  4373. if (pnode->AsParseNodeCall()->isEvalCall)
  4374. {
  4375. if (!funcInfo->GetParsedFunctionBody()->IsReparsed())
  4376. {
  4377. Assert(funcInfo->IsGlobalFunction() || funcInfo->GetCallsEval());
  4378. funcInfo->SetCallsEval(true);
  4379. funcInfo->GetParsedFunctionBody()->SetCallsEval(true);
  4380. }
  4381. else
  4382. {
  4383. // On reparsing, load the state from function Body, instead of using the state on the parse node,
  4384. // as they might be different.
  4385. pnode->AsParseNodeCall()->isEvalCall = funcInfo->GetParsedFunctionBody()->GetCallsEval();
  4386. }
  4387. }
  4388. // Don't need to check pnode->AsParseNodeCall()->pnodeTarget even if it is a knopFncDecl,
  4389. // e.g. (function(){})();
  4390. // It is only used as a call, so don't count as an escape.
  4391. // Although not assigned to a slot, we will still able to box it by boxing
  4392. // all the stack function on the interpreter frame or the stack function link list
  4393. // on a jitted frame
  4394. break;
  4395. }
  4396. case knopInt:
  4397. pnode->location = byteCodeGenerator->EnregisterConstant(pnode->AsParseNodeInt()->lw);
  4398. break;
  4399. case knopFlt:
  4400. {
  4401. pnode->location = byteCodeGenerator->EnregisterDoubleConstant(pnode->AsParseNodeFloat()->dbl);
  4402. break;
  4403. }
  4404. case knopStr:
  4405. pnode->location = byteCodeGenerator->EnregisterStringConstant(pnode->AsParseNodeStr()->pid);
  4406. break;
  4407. case knopVarDecl:
  4408. case knopConstDecl:
  4409. case knopLetDecl:
  4410. {
  4411. sym = pnode->AsParseNodeVar()->sym;
  4412. Assert(sym != nullptr);
  4413. Assert(sym->GetScope()->GetEnclosingFunc() == byteCodeGenerator->TopFuncInfo());
  4414. if (pnode->AsParseNodeVar()->isBlockScopeFncDeclVar && sym->GetIsBlockVar())
  4415. {
  4416. break;
  4417. }
  4418. if (!sym->GetIsGlobal())
  4419. {
  4420. FuncInfo *funcInfo = byteCodeGenerator->TopFuncInfo();
  4421. // Check the function assignment for the sym that we have, even if we remap it to function level sym below
  4422. // as we are going assign to the original sym
  4423. CheckFuncAssignment(sym, pnode->AsParseNodeVar()->pnodeInit, byteCodeGenerator);
  4424. // If this is a destructured param case then it is a let binding and we don't have to look for duplicate symbol in the body
  4425. if ((sym->GetIsCatch() && pnode->AsParseNodeVar()->sym->GetScope()->GetScopeType() != ScopeType_CatchParamPattern) || (pnode->nop == knopVarDecl && sym->GetIsBlockVar() && !pnode->AsParseNodeVar()->isBlockScopeFncDeclVar))
  4426. {
  4427. // The LHS of the var decl really binds to the local symbol, not the catch or let symbol.
  4428. // But the assignment will go to the catch or let symbol. Just assign a register to the local
  4429. // so that it can get initialized to undefined.
  4430. #if DBG
  4431. if (!sym->GetIsCatch())
  4432. {
  4433. // Catch cannot be at function scope and let and var at function scope is redeclaration error.
  4434. Assert(funcInfo->bodyScope != sym->GetScope());
  4435. }
  4436. #endif
  4437. auto symName = sym->GetName();
  4438. sym = funcInfo->bodyScope->FindLocalSymbol(symName);
  4439. if (sym == nullptr)
  4440. {
  4441. sym = funcInfo->paramScope->FindLocalSymbol(symName);
  4442. }
  4443. Assert((sym && !sym->GetIsCatch() && !sym->GetIsBlockVar()));
  4444. }
  4445. // Don't give the declared var a register if it's in a closure, because the closure slot
  4446. // is its true "home". (Need to check IsGlobal again as the sym may have changed above.)
  4447. if (!sym->GetIsGlobal() && !sym->IsInSlot(byteCodeGenerator, funcInfo))
  4448. {
  4449. if (PHASE_TRACE(Js::DelayCapturePhase, funcInfo->byteCodeFunction))
  4450. {
  4451. if (sym->NeedsSlotAlloc(byteCodeGenerator, byteCodeGenerator->TopFuncInfo()))
  4452. {
  4453. Output::Print(_u("--- DelayCapture: Delayed capturing symbol '%s' during initialization.\n"),
  4454. sym->GetName().GetBuffer());
  4455. Output::Flush();
  4456. }
  4457. }
  4458. byteCodeGenerator->AssignRegister(sym);
  4459. }
  4460. }
  4461. else
  4462. {
  4463. Assert(byteCodeGenerator->TopFuncInfo()->IsGlobalFunction());
  4464. }
  4465. break;
  4466. }
  4467. case knopFor:
  4468. if ((pnode->AsParseNodeFor()->pnodeBody != nullptr) && (pnode->AsParseNodeFor()->pnodeBody->nop == knopBlock) &&
  4469. (pnode->AsParseNodeFor()->pnodeBody->AsParseNodeBlock()->pnodeStmt != nullptr) &&
  4470. (pnode->AsParseNodeFor()->pnodeBody->AsParseNodeBlock()->pnodeStmt->nop == knopFor) &&
  4471. (!byteCodeGenerator->IsInDebugMode()))
  4472. {
  4473. FuncInfo *funcInfo = byteCodeGenerator->TopFuncInfo();
  4474. pnode->AsParseNodeFor()->pnodeInverted = InvertLoop(pnode, byteCodeGenerator, funcInfo);
  4475. }
  4476. else
  4477. {
  4478. pnode->AsParseNodeFor()->pnodeInverted = nullptr;
  4479. }
  4480. break;
  4481. case knopName:
  4482. sym = pnode->AsParseNodeName()->sym;
  4483. if (sym == nullptr)
  4484. {
  4485. Assert(pnode->AsParseNodeName()->pid->GetPropertyId() != Js::Constants::NoProperty);
  4486. // Referring to 'this' with no var decl needs to load 'this' root value via LdThis from null
  4487. if (ByteCodeGenerator::IsThis(pnode) && !byteCodeGenerator->TopFuncInfo()->GetThisSymbol() && !(byteCodeGenerator->GetFlags() & fscrEval))
  4488. {
  4489. byteCodeGenerator->AssignNullConstRegister();
  4490. byteCodeGenerator->AssignThisConstRegister();
  4491. }
  4492. }
  4493. else
  4494. {
  4495. // Note: don't give a register to a local if it's in a closure, because then the closure
  4496. // is its true home.
  4497. if (!sym->GetIsGlobal() &&
  4498. !sym->GetIsMember() &&
  4499. byteCodeGenerator->TopFuncInfo() == sym->GetScope()->GetEnclosingFunc() &&
  4500. !sym->IsInSlot(byteCodeGenerator, byteCodeGenerator->TopFuncInfo()) &&
  4501. !sym->HasVisitedCapturingFunc())
  4502. {
  4503. if (PHASE_TRACE(Js::DelayCapturePhase, byteCodeGenerator->TopFuncInfo()->byteCodeFunction))
  4504. {
  4505. if (sym->NeedsSlotAlloc(byteCodeGenerator, byteCodeGenerator->TopFuncInfo()))
  4506. {
  4507. Output::Print(_u("--- DelayCapture: Delayed capturing symbol '%s'.\n"),
  4508. sym->GetName().GetBuffer());
  4509. Output::Flush();
  4510. }
  4511. }
  4512. // Local symbol being accessed in its own frame. Even if "with" or event
  4513. // handler semantics make the binding ambiguous, it has a home location,
  4514. // so assign it.
  4515. byteCodeGenerator->AssignRegister(sym);
  4516. // If we're in something like a "with" we'll need a scratch register to hold
  4517. // the multiple possible values of the property.
  4518. if (!byteCodeGenerator->HasInterleavingDynamicScope(sym))
  4519. {
  4520. // We're not in a dynamic scope, or our home scope is nested within the dynamic scope, so we
  4521. // don't have to do dynamic binding. Just use the home location for this reference.
  4522. pnode->location = sym->GetLocation();
  4523. }
  4524. }
  4525. }
  4526. if (pnode->IsInList() && !pnode->IsNotEscapedUse())
  4527. {
  4528. // A node that is in a list is assumed to be escape, unless marked otherwise.
  4529. // This includes array literal list/object literal list
  4530. CheckMaybeEscapedUse(pnode, byteCodeGenerator);
  4531. }
  4532. break;
  4533. case knopProg:
  4534. if (!byteCodeGenerator->HasParentScopeInfo())
  4535. {
  4536. // If we're compiling a nested deferred function, don't pop the scope stack,
  4537. // because we just want to leave it as-is for the emit pass.
  4538. PostVisitFunction(pnode->AsParseNodeFnc(), byteCodeGenerator);
  4539. }
  4540. break;
  4541. case knopReturn:
  4542. {
  4543. ParseNode *pnodeExpr = pnode->AsParseNodeReturn()->pnodeExpr;
  4544. CheckMaybeEscapedUse(pnodeExpr, byteCodeGenerator);
  4545. break;
  4546. }
  4547. case knopStrTemplate:
  4548. {
  4549. ParseNode* pnodeExprs = pnode->AsParseNodeStrTemplate()->pnodeSubstitutionExpressions;
  4550. if (pnodeExprs != nullptr)
  4551. {
  4552. while (pnodeExprs->nop == knopList)
  4553. {
  4554. Assert(pnodeExprs->AsParseNodeBin()->pnode1 != nullptr);
  4555. Assert(pnodeExprs->AsParseNodeBin()->pnode2 != nullptr);
  4556. CheckMaybeEscapedUse(pnodeExprs->AsParseNodeBin()->pnode1, byteCodeGenerator);
  4557. pnodeExprs = pnodeExprs->AsParseNodeBin()->pnode2;
  4558. }
  4559. // Also check the final element in the list
  4560. CheckMaybeEscapedUse(pnodeExprs, byteCodeGenerator);
  4561. }
  4562. if (pnode->AsParseNodeStrTemplate()->isTaggedTemplate)
  4563. {
  4564. pnode->location = byteCodeGenerator->EnregisterStringTemplateCallsiteConstant(pnode);
  4565. }
  4566. break;
  4567. }
  4568. case knopExportDefault:
  4569. {
  4570. ParseNode* expr = pnode->AsParseNodeExportDefault()->pnodeExpr;
  4571. if (expr != nullptr)
  4572. {
  4573. CheckMaybeEscapedUse(expr, byteCodeGenerator);
  4574. }
  4575. break;
  4576. }
  4577. case knopYieldLeaf:
  4578. byteCodeGenerator->AssignUndefinedConstRegister();
  4579. break;
  4580. case knopYield:
  4581. CheckMaybeEscapedUse(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator);
  4582. break;
  4583. case knopYieldStar:
  4584. byteCodeGenerator->AssignNullConstRegister();
  4585. byteCodeGenerator->AssignUndefinedConstRegister();
  4586. CheckMaybeEscapedUse(pnode->AsParseNodeUni()->pnode1, byteCodeGenerator);
  4587. break;
  4588. }
  4589. }
  4590. // TODO[ianhall]: ApplyEnclosesArgs should be in ByteCodeEmitter.cpp but that becomes complicated because it depends on VisitIndirect
  4591. void PostCheckApplyEnclosesArgs(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, ApplyCheck* applyCheck);
  4592. void CheckApplyEnclosesArgs(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, ApplyCheck* applyCheck);
  4593. bool ApplyEnclosesArgs(ParseNode* fncDecl, ByteCodeGenerator* byteCodeGenerator)
  4594. {
  4595. if (byteCodeGenerator->IsInDebugMode())
  4596. {
  4597. // Inspection of the arguments object will be messed up if we do ApplyArgs.
  4598. return false;
  4599. }
  4600. if (!fncDecl->HasVarArguments()
  4601. && fncDecl->AsParseNodeFnc()->pnodeParams == nullptr
  4602. && fncDecl->AsParseNodeFnc()->pnodeRest == nullptr
  4603. && fncDecl->AsParseNodeFnc()->nestedCount == 0)
  4604. {
  4605. ApplyCheck applyCheck;
  4606. applyCheck.matches = true;
  4607. applyCheck.sawApply = false;
  4608. applyCheck.insideApplyCall = false;
  4609. VisitIndirect<ApplyCheck>(fncDecl->AsParseNodeFnc()->pnodeBody, byteCodeGenerator, &applyCheck, &CheckApplyEnclosesArgs, &PostCheckApplyEnclosesArgs);
  4610. return applyCheck.matches&&applyCheck.sawApply;
  4611. }
  4612. return false;
  4613. }
  4614. // TODO[ianhall]: VisitClearTmpRegs should be in ByteCodeEmitter.cpp but that becomes complicated because it depends on VisitIndirect
  4615. void ClearTmpRegs(ParseNode* pnode, ByteCodeGenerator* byteCodeGenerator, FuncInfo* emitFunc);
  4616. void VisitClearTmpRegs(ParseNode * pnode, ByteCodeGenerator * byteCodeGenerator, FuncInfo * funcInfo)
  4617. {
  4618. VisitIndirect<FuncInfo>(pnode, byteCodeGenerator, funcInfo, &ClearTmpRegs, nullptr);
  4619. }
  4620. Js::FunctionBody * ByteCodeGenerator::MakeGlobalFunctionBody(ParseNode *pnode)
  4621. {
  4622. Js::FunctionBody * func;
  4623. func =
  4624. Js::FunctionBody::NewFromRecycler(
  4625. scriptContext,
  4626. Js::Constants::GlobalFunction,
  4627. Js::Constants::GlobalFunctionLength,
  4628. 0,
  4629. pnode->AsParseNodeFnc()->nestedCount,
  4630. m_utf8SourceInfo,
  4631. m_utf8SourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId,
  4632. pnode->AsParseNodeFnc()->functionId,
  4633. Js::FunctionInfo::Attributes::None,
  4634. Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue
  4635. #ifdef PERF_COUNTERS
  4636. , false /* is function from deferred deserialized proxy */
  4637. #endif
  4638. );
  4639. func->SetIsGlobalFunc(true);
  4640. scriptContext->GetLibrary()->RegisterDynamicFunctionReference(func);
  4641. return func;
  4642. }
  4643. bool ByteCodeGenerator::NeedScopeObjectForArguments(FuncInfo *funcInfo, ParseNodeFnc *pnodeFnc) const
  4644. {
  4645. // We can avoid creating a scope object with arguments present if:
  4646. bool dontNeedScopeObject =
  4647. // We have arguments, and
  4648. funcInfo->GetHasHeapArguments()
  4649. // Either we are in strict mode, or have strict mode formal semantics from a non-simple parameter list, and
  4650. && (funcInfo->GetIsStrictMode()
  4651. || pnodeFnc->HasNonSimpleParameterList())
  4652. // We're not in eval or event handler, which will force the scope(s) to be objects
  4653. && !(this->flags & (fscrEval | fscrImplicitThis))
  4654. // Neither of the scopes are objects
  4655. && !funcInfo->paramScope->GetIsObject()
  4656. && !funcInfo->bodyScope->GetIsObject();
  4657. return funcInfo->GetHasHeapArguments()
  4658. // Regardless of the conditions above, we won't need a scope object if there aren't any formals.
  4659. && (pnodeFnc->pnodeParams != nullptr || pnodeFnc->pnodeRest != nullptr)
  4660. && !dontNeedScopeObject;
  4661. }
  4662. Js::FunctionBody *ByteCodeGenerator::EnsureFakeGlobalFuncForUndefer(ParseNode *pnode)
  4663. {
  4664. Js::FunctionBody *func = scriptContext->GetLibrary()->GetFakeGlobalFuncForUndefer();
  4665. if (!func)
  4666. {
  4667. func = this->MakeGlobalFunctionBody(pnode);
  4668. scriptContext->GetLibrary()->SetFakeGlobalFuncForUndefer(func);
  4669. }
  4670. if (pnode->AsParseNodeFnc()->GetStrictMode() != 0)
  4671. {
  4672. func->SetIsStrictMode();
  4673. }
  4674. return func;
  4675. }