| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "JsrtPch.h"
- #include "JsrtInternal.h"
- #include "JsrtExternalObject.h"
- #include "JsrtExternalArrayBuffer.h"
- #include "jsrtHelper.h"
- #include "JsrtSourceHolder.h"
- #include "ByteCode/ByteCodeSerializer.h"
- #include "Common/ByteSwap.h"
- #include "Library/DataView.h"
- #include "Base/ThreadContextTlsEntry.h"
- #include "Codex/Utf8Helper.h"
- // Parser Includes
- #include "cmperr.h" // For ERRnoMemory
- #include "screrror.h" // For CompileScriptException
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- #include "TestHooksRt.h"
- #endif
- CHAKRA_API RunScriptWithParserStateCore(
- _In_ DWORD dwBgParseCookie,
- _In_ JsValueRef script,
- _In_ JsSourceContext sourceContext,
- _In_ WCHAR *url,
- _In_ JsParseScriptAttributes parseAttributes,
- _In_ JsValueRef parserState,
- _In_ bool parseOnly,
- _Out_ JsValueRef *result
- );
- struct CodexHeapAllocatorInterface
- {
- public:
- static void* allocate(size_t size)
- {
- return HeapNewArray(char, size);
- }
- static void free(void* ptr, size_t count)
- {
- HeapDeleteArray(count, (char*) ptr);
- }
- };
- JsErrorCode CheckContext(JsrtContext *currentContext, bool verifyRuntimeState,
- bool allowInObjectBeforeCollectCallback)
- {
- if (currentContext == nullptr)
- {
- return JsErrorNoCurrentContext;
- }
- // We don't need parameter check if it's checked in previous wrapper.
- if (verifyRuntimeState)
- {
- Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
- Assert(scriptContext != nullptr);
- Recycler *recycler = scriptContext->GetRecycler();
- ThreadContext *threadContext = scriptContext->GetThreadContext();
- if (recycler && recycler->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (!allowInObjectBeforeCollectCallback &&
- recycler && recycler->IsInObjectBeforeCollectCallback())
- {
- return JsErrorInObjectBeforeCollectCallback;
- }
- else if (threadContext->IsExecutionDisabled())
- {
- return JsErrorInDisabledState;
- }
- else if (scriptContext->IsInProfileCallback())
- {
- return JsErrorInProfileCallback;
- }
- else if (threadContext->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- // Make sure we don't have an outstanding exception.
- if (scriptContext->GetThreadContext()->GetRecordedException() != nullptr)
- {
- return JsErrorInExceptionState;
- }
- }
- return JsNoError;
- }
- /////////////////////
- #if ENABLE_TTD
- void CALLBACK OnScriptLoad_TTDCallback(FinalizableObject* jsrtCtx, Js::FunctionBody* body, Js::Utf8SourceInfo* utf8SourceInfo, CompileScriptException* compileException, bool notify)
- {
- ((JsrtContext*)jsrtCtx)->OnScriptLoad_TTDCallback(body, utf8SourceInfo, compileException, notify);
- }
- uint32 CALLBACK OnBPRegister_TTDCallback(void* runtimeRcvr, int64 bpID, Js::ScriptContext* scriptContext, Js::Utf8SourceInfo* utf8SourceInfo, uint32 line, uint32 column, BOOL* isNewBP)
- {
- return ((JsrtRuntime*)runtimeRcvr)->BPRegister_TTD(bpID, scriptContext, utf8SourceInfo, line, column, isNewBP);
- }
- void CALLBACK OnBPDelete_TTDCallback(void* runtimeRcvr, uint32 bpID)
- {
- ((JsrtRuntime*)runtimeRcvr)->BPDelete_TTD(bpID);
- }
- void CALLBACK OnBPClearDocument_TTDCallback(void* runtimeRcvr)
- {
- ((JsrtRuntime*)runtimeRcvr)->BPClearDocument_TTD();
- }
- #endif
- //A create context function that we can funnel to for regular and record or debug aware creation
- JsErrorCode CreateContextCore(_In_ JsRuntimeHandle runtimeHandle, _In_ TTDRecorder& _actionEntryPopper, _In_ bool inRecordMode, _In_ bool activelyRecording, _In_ bool inReplayMode, _Out_ JsContextRef *newContext)
- {
- JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext * threadContext = runtime->GetThreadContext();
- if(threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if(threadContext->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- ThreadContextScope scope(threadContext);
- if(!scope.IsValid())
- {
- return JsErrorWrongThread;
- }
- #if ENABLE_TTD
- TTD::NSLogEvents::EventLogEntry* createEvent = nullptr;
- if(activelyRecording)
- {
- createEvent = threadContext->TTDLog->RecordJsRTCreateScriptContext(_actionEntryPopper);
- }
- #endif
- JsrtContext * context = JsrtContext::New(runtime);
- #if ENABLE_TTD
- if(inRecordMode | inReplayMode)
- {
- Js::ScriptContext* scriptContext = context->GetScriptContext();
- HostScriptContextCallbackFunctor callbackFunctor((FinalizableObject*)context, (void*)runtime, &OnScriptLoad_TTDCallback, &OnBPRegister_TTDCallback, &OnBPDelete_TTDCallback, &OnBPClearDocument_TTDCallback);
- #if ENABLE_TTD_DIAGNOSTICS_TRACING
- bool noNative = true;
- bool doDebug = true;
- #else
- bool noNative = TTD_FORCE_NOJIT_MODE || threadContext->TTDLog->IsDebugModeFlagSet();
- bool doDebug = TTD_FORCE_DEBUG_MODE || threadContext->TTDLog->IsDebugModeFlagSet();
- #endif
- threadContext->TTDLog->PushMode(TTD::TTDMode::ExcludedExecutionTTAction);
- if(inRecordMode)
- {
- threadContext->TTDContext->AddNewScriptContextRecord(context, scriptContext, callbackFunctor, noNative, doDebug);
- }
- else
- {
- threadContext->TTDContext->AddNewScriptContextReplay(context, scriptContext, callbackFunctor, noNative, doDebug);
- }
- threadContext->TTDLog->SetModeFlagsOnContext(scriptContext);
- threadContext->TTDLog->PopMode(TTD::TTDMode::ExcludedExecutionTTAction);
- }
- #endif
- #ifdef ENABLE_SCRIPT_DEBUGGING
- JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
- if(jsrtDebugManager != nullptr)
- {
- // JsDiagStartDebugging was called
- threadContext->GetDebugManager()->SetLocalsDisplayFlags(Js::DebugManager::LocalsDisplayFlags::LocalsDisplayFlags_NoGroupMethods);
- Js::ScriptContext* scriptContext = context->GetScriptContext();
- Js::DebugContext* debugContext = scriptContext->GetDebugContext();
- debugContext->SetHostDebugContext(jsrtDebugManager);
- if (!jsrtDebugManager->IsDebugEventCallbackSet())
- {
- // JsDiagStopDebugging was called so we need to be in SourceRunDownMode
- debugContext->SetDebuggerMode(Js::DebuggerMode::SourceRundown);
- }
- else
- {
- // Set Debugging mode
- scriptContext->InitializeDebugging();
- Js::ProbeContainer* probeContainer = debugContext->GetProbeContainer();
- probeContainer->InitializeInlineBreakEngine(jsrtDebugManager);
- probeContainer->InitializeDebuggerScriptOptionCallback(jsrtDebugManager);
- }
- }
- #endif
- #if ENABLE_TTD
- if(activelyRecording)
- {
- threadContext->TTDLog->RecordJsRTCreateScriptContextResult(createEvent, context->GetScriptContext());
- }
- #endif
- *newContext = (JsContextRef)context;
- return JsNoError;
- }
- #if ENABLE_TTD
- void CALLBACK CreateExternalObject_TTDCallback(Js::ScriptContext* ctx, Js::Var prototype, Js::Var* object)
- {
- TTDAssert(object != nullptr, "This should always be a valid location");
- Js::RecyclableObject * prototypeObject = nullptr;
- if (prototype != JS_INVALID_REFERENCE)
- {
- prototypeObject = Js::VarTo<Js::RecyclableObject>(prototype);
- }
- *object = JsrtExternalObject::Create(nullptr, 0, nullptr, prototypeObject, ctx, nullptr);
- }
- void CALLBACK TTDDummyPromiseContinuationCallback(JsValueRef task, void *callbackState)
- {
- TTDAssert(false, "This should never actually be invoked!!!");
- }
- void CALLBACK CreateJsRTContext_TTDCallback(void* runtimeHandle, Js::ScriptContext** result)
- {
- JsContextRef newContext = nullptr;
- *result = nullptr;
- TTDRecorder dummyActionEntryPopper;
- JsErrorCode err = CreateContextCore(static_cast<JsRuntimeHandle>(runtimeHandle), dummyActionEntryPopper, false /*inRecordMode*/, false /*activelyRecording*/, true /*inReplayMode*/, &newContext);
- TTDAssert(err == JsNoError, "Shouldn't fail on us!!!");
- *result = static_cast<JsrtContext*>(newContext)->GetScriptContext();
- (*result)->GetLibrary()->SetNativeHostPromiseContinuationFunction((Js::JavascriptLibrary::PromiseContinuationCallback)TTDDummyPromiseContinuationCallback, nullptr);
- //To ensure we have a valid context active (when we next try and inflate into this context) set this as active by convention
- JsrtContext::TrySetCurrent(static_cast<JsrtContext*>(newContext));
- }
- void CALLBACK ReleaseJsRTContext_TTDCallback(FinalizableObject* jsrtCtx)
- {
- static_cast<JsrtContext*>(jsrtCtx)->GetScriptContext()->GetThreadContext()->GetRecycler()->RootRelease(jsrtCtx);
- JsrtContext::OnReplayDisposeContext_TTDCallback(jsrtCtx);
- }
- void CALLBACK SetActiveJsRTContext_TTDCallback(void* runtimeHandle, Js::ScriptContext* ctx)
- {
- JsrtRuntime * runtime = JsrtRuntime::FromHandle(static_cast<JsRuntimeHandle>(runtimeHandle));
- ThreadContext * threadContext = runtime->GetThreadContext();
- threadContext->TTDContext->SetActiveScriptContext(ctx);
- JsrtContext* runtimeCtx = (JsrtContext*)threadContext->TTDContext->GetRuntimeContextForScriptContext(ctx);
- JsrtContext::TrySetCurrent(runtimeCtx);
- }
- #endif
- //A create runtime function that we can funnel to for regular and record or debug aware creation
- JsErrorCode CreateRuntimeCore(_In_ JsRuntimeAttributes attributes,
- _In_opt_ const char* optTTUri, size_t optTTUriCount, bool isRecord, bool isReplay, bool isDebug,
- _In_ UINT32 snapInterval, _In_ UINT32 snapHistoryLength,
- _In_opt_ TTDOpenResourceStreamCallback openResourceStream, _In_opt_ JsTTDReadBytesFromStreamCallback readBytesFromStream,
- _In_opt_ JsTTDWriteBytesToStreamCallback writeBytesToStream, _In_opt_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream,
- _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtimeHandle)
- {
- VALIDATE_ENTER_CURRENT_THREAD();
- PARAM_NOT_NULL(runtimeHandle);
- *runtimeHandle = nullptr;
- JsErrorCode runtimeResult = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- const JsRuntimeAttributes JsRuntimeAttributesAll =
- (JsRuntimeAttributes)(
- JsRuntimeAttributeDisableBackgroundWork |
- JsRuntimeAttributeAllowScriptInterrupt |
- JsRuntimeAttributeEnableIdleProcessing |
- JsRuntimeAttributeDisableEval |
- JsRuntimeAttributeDisableNativeCodeGeneration |
- JsRuntimeAttributeDisableExecutablePageAllocation |
- JsRuntimeAttributeEnableExperimentalFeatures |
- JsRuntimeAttributeDispatchSetExceptionsToDebugger |
- JsRuntimeAttributeDisableFatalOnOOM
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- | JsRuntimeAttributeSerializeLibraryByteCode
- #endif
- );
- Assert((attributes & ~JsRuntimeAttributesAll) == 0);
- if ((attributes & ~JsRuntimeAttributesAll) != 0)
- {
- return JsErrorInvalidArgument;
- }
- CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 0, nullptr);
- AllocationPolicyManager * policyManager = HeapNew(AllocationPolicyManager, (attributes & JsRuntimeAttributeDisableBackgroundWork) == 0);
- bool enableExperimentalFeatures = (attributes & JsRuntimeAttributeEnableExperimentalFeatures) != 0;
- ThreadContext * threadContext = HeapNew(ThreadContext, policyManager, threadService, enableExperimentalFeatures);
- if (((attributes & JsRuntimeAttributeDisableBackgroundWork) != 0)
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- && !Js::Configuration::Global.flags.ConcurrentRuntime
- #endif
- )
- {
- threadContext->OptimizeForManyInstances(true);
- #if ENABLE_NATIVE_CODEGEN
- threadContext->EnableBgJit(false);
- #endif
- }
- if (!threadContext->IsRentalThreadingEnabledInJSRT()
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- || Js::Configuration::Global.flags.DisableRentalThreading
- #endif
- )
- {
- threadContext->SetIsThreadBound();
- }
- if (attributes & JsRuntimeAttributeAllowScriptInterrupt)
- {
- threadContext->SetThreadContextFlag(ThreadContextFlagCanDisableExecution);
- }
- if (attributes & JsRuntimeAttributeDisableEval)
- {
- threadContext->SetThreadContextFlag(ThreadContextFlagEvalDisabled);
- }
- if (attributes & JsRuntimeAttributeDisableNativeCodeGeneration)
- {
- threadContext->SetThreadContextFlag(ThreadContextFlagNoJIT);
- }
- if (attributes & JsRuntimeAttributeDisableExecutablePageAllocation)
- {
- threadContext->SetThreadContextFlag(ThreadContextFlagNoJIT);
- threadContext->SetThreadContextFlag(ThreadContextFlagNoDynamicThunks);
- }
- if (attributes & JsRuntimeAttributeDisableFatalOnOOM)
- {
- threadContext->SetThreadContextFlag(ThreadContextFlagDisableFatalOnOOM);
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.PrimeRecycler)
- {
- threadContext->EnsureRecycler()->Prime();
- }
- #endif
- bool enableIdle = (attributes & JsRuntimeAttributeEnableIdleProcessing) == JsRuntimeAttributeEnableIdleProcessing;
- bool dispatchExceptions = (attributes & JsRuntimeAttributeDispatchSetExceptionsToDebugger) == JsRuntimeAttributeDispatchSetExceptionsToDebugger;
- JsrtRuntime * runtime = HeapNew(JsrtRuntime, threadContext, enableIdle, dispatchExceptions);
- threadContext->SetCurrentThreadId(ThreadContext::NoThread);
- *runtimeHandle = runtime->ToHandle();
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- runtime->SetSerializeByteCodeForLibrary((attributes & JsRuntimeAttributeSerializeLibraryByteCode) != 0);
- #endif
- return JsNoError;
- });
- #if ENABLE_TTD
- if(runtimeResult != JsNoError)
- {
- return runtimeResult;
- }
- if(isRecord | isReplay | isDebug)
- {
- ThreadContext* threadContext = JsrtRuntime::FromHandle(*runtimeHandle)->GetThreadContext();
- if(isRecord && isReplay)
- {
- return JsErrorInvalidArgument; //A runtime can only be in 1 mode
- }
- if(isReplay && optTTUri == nullptr)
- {
- return JsErrorInvalidArgument; //We must have a location to store data into
- }
- runtimeResult = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- //Make sure the thread context recycler is allocated before we do anything else
- ThreadContextScope scope(threadContext);
- threadContext->EnsureRecycler();
- threadContext->InitTimeTravel(threadContext, *runtimeHandle, snapInterval, max<uint32>(2, snapHistoryLength));
- threadContext->InitHostFunctionsAndTTData(isRecord, isReplay, isDebug, optTTUriCount, optTTUri,
- openResourceStream, readBytesFromStream, writeBytesToStream, flushAndCloseStream,
- &CreateExternalObject_TTDCallback, &CreateJsRTContext_TTDCallback, &ReleaseJsRTContext_TTDCallback, &SetActiveJsRTContext_TTDCallback);
- return JsNoError;
- });
- }
- #endif
- return runtimeResult;
- }
- /////////////////////
- CHAKRA_API JsCreateRuntime(_In_ JsRuntimeAttributes attributes, _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtimeHandle)
- {
- return CreateRuntimeCore(attributes,
- nullptr /*optRecordUri*/, 0 /*optRecordUriCount */, false /*isRecord*/, false /*isReplay*/, false /*isDebug*/,
- UINT_MAX /*optSnapInterval*/, UINT_MAX /*optLogLength*/,
- nullptr, nullptr, nullptr, nullptr, /*TTD IO handlers*/
- threadService, runtimeHandle);
- }
- template <CollectionFlags flags>
- JsErrorCode JsCollectGarbageCommon(JsRuntimeHandle runtimeHandle)
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
- if (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (threadContext->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- ThreadContextScope scope(threadContext);
- if (!scope.IsValid())
- {
- return JsErrorWrongThread;
- }
- Recycler* recycler = threadContext->EnsureRecycler();
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (flags & CollectOverride_SkipStack)
- {
- Recycler::AutoEnterExternalStackSkippingGCMode autoGC(recycler);
- recycler->CollectNow<flags>();
- }
- else
- #endif
- {
- recycler->CollectNow<flags>();
- }
- return JsNoError;
- });
- }
- CHAKRA_API JsCollectGarbage(_In_ JsRuntimeHandle runtimeHandle)
- {
- return JsCollectGarbageCommon<CollectNowExhaustive>(runtimeHandle);
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- CHAKRA_API JsPrivateCollectGarbageSkipStack(_In_ JsRuntimeHandle runtimeHandle)
- {
- return JsCollectGarbageCommon<CollectNowExhaustiveSkipStack>(runtimeHandle);
- }
- CHAKRA_API JsPrivateDetachArrayBuffer(_In_ JsValueRef ref, _Out_ void** detachedState)
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- VALIDATE_JSREF(ref);
- *detachedState = Js::JavascriptOperators::DetachVarAndGetState(ref, false /*queueForDelayFree*/);
- return JsNoError;
- });
- }
- CHAKRA_API JsPrivateFreeDetachedArrayBuffer(_In_ void* detachedState)
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- auto state = reinterpret_cast<Js::ArrayBufferDetachedStateBase*>(detachedState);
- state->CleanUp();
- return JsNoError;
- });
- }
- #endif
- CHAKRA_API JsDisposeRuntime(_In_ JsRuntimeHandle runtimeHandle)
- {
- return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext * threadContext = runtime->GetThreadContext();
- ThreadContextScope scope(threadContext);
- // We should not dispose if the runtime is being used.
- if (!scope.IsValid() ||
- scope.WasInUse() ||
- (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress()))
- {
- return JsErrorRuntimeInUse;
- }
- else if (threadContext->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- // Invoke and clear the callbacks while the contexts and runtime are still available
- {
- Recycler* recycler = threadContext->GetRecycler();
- if (recycler != nullptr)
- {
- recycler->ClearObjectBeforeCollectCallbacks();
- }
- }
- #ifdef ENABLE_SCRIPT_DEBUGGING
- if (runtime->GetJsrtDebugManager() != nullptr)
- {
- runtime->GetJsrtDebugManager()->ClearDebuggerObjects();
- }
- #endif
- Js::ScriptContext *scriptContext;
- for (scriptContext = threadContext->GetScriptContextList(); scriptContext; scriptContext = scriptContext->next)
- {
- #ifdef ENABLE_SCRIPT_DEBUGGING
- if (runtime->GetJsrtDebugManager() != nullptr)
- {
- runtime->GetJsrtDebugManager()->ClearDebugDocument(scriptContext);
- }
- #endif
- scriptContext->MarkForClose();
- }
- // Close any open Contexts.
- // We need to do this before recycler shutdown, because ScriptEngine->Close won't work then.
- runtime->CloseContexts();
- #ifdef ENABLE_SCRIPT_DEBUGGING
- runtime->DeleteJsrtDebugManager();
- #endif
- #if defined(CHECK_MEMORY_LEAK) || defined(LEAK_REPORT)
- bool doFinalGC = false;
- #if defined(LEAK_REPORT)
- if (Js::Configuration::Global.flags.IsEnabled(Js::LeakReportFlag))
- {
- doFinalGC = true;
- }
- #endif
- #if defined(CHECK_MEMORY_LEAK)
- if (Js::Configuration::Global.flags.CheckMemoryLeak)
- {
- doFinalGC = true;
- }
- #endif
- if (doFinalGC)
- {
- Recycler *recycler = threadContext->GetRecycler();
- if (recycler)
- {
- recycler->EnsureNotCollecting();
- recycler->CollectNow<CollectNowFinalGC>();
- Assert(!recycler->CollectionInProgress());
- }
- }
- #endif
- runtime->SetBeforeCollectCallback(nullptr, nullptr);
- threadContext->CloseForJSRT();
- HeapDelete(threadContext);
- HeapDelete(runtime);
- scope.Invalidate();
- return JsNoError;
- });
- }
- CHAKRA_API JsAddRef(_In_ JsRef ref, _Out_opt_ unsigned int *count)
- {
- VALIDATE_JSREF(ref);
- if (count != nullptr)
- {
- *count = 0;
- }
- if (Js::TaggedNumber::Is(ref))
- {
- // The count is always one because these are never collected
- if (count)
- {
- *count = 1;
- }
- return JsNoError;
- }
- if (JsrtContext::Is(ref))
- {
- return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode
- {
- Recycler * recycler = static_cast<JsrtContext *>(ref)->GetRuntime()->GetThreadContext()->GetRecycler();
- recycler->RootAddRef(ref, count);
- return JsNoError;
- });
- }
- else
- {
- ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
- if (threadContext == nullptr)
- {
- return JsErrorNoCurrentContext;
- }
- Recycler * recycler = threadContext->GetRecycler();
- return GlobalAPIWrapper([&] (TTDRecorder& _actionEntryPopper) -> JsErrorCode
- {
- // Note, some references may live in arena-allocated memory, so we need to do this check
- if (!recycler->IsValidObject(ref))
- {
- return JsNoError;
- }
- #if ENABLE_TTD
- unsigned int lCount = 0;
- recycler->RootAddRef(ref, &lCount);
- if (count != nullptr)
- {
- *count = lCount;
- }
- if((lCount == 1) && (threadContext->IsRuntimeInTTDMode()) && (!threadContext->TTDLog->IsPropertyRecordRef(ref)))
- {
- Js::RecyclableObject* obj = Js::VarTo<Js::RecyclableObject>(ref);
- if(obj->GetScriptContext()->IsTTDRecordModeEnabled())
- {
- if(obj->GetScriptContext()->ShouldPerformRecordAction())
- {
- threadContext->TTDLog->RecordJsRTAddRootRef(_actionEntryPopper, (Js::Var)ref);
- }
- threadContext->TTDContext->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(obj), obj);
- }
- }
- #else
- recycler->RootAddRef(ref, count);
- #endif
- return JsNoError;
- });
- }
- }
- CHAKRA_API JsRelease(_In_ JsRef ref, _Out_opt_ unsigned int *count)
- {
- VALIDATE_JSREF(ref);
- if (count != nullptr)
- {
- *count = 0;
- }
- if (Js::TaggedNumber::Is(ref))
- {
- // The count is always one because these are never collected
- if (count)
- {
- *count = 1;
- }
- return JsNoError;
- }
- if (JsrtContext::Is(ref))
- {
- return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode
- {
- Recycler * recycler = static_cast<JsrtContext *>(ref)->GetRuntime()->GetThreadContext()->GetRecycler();
- recycler->RootRelease(ref, count);
- return JsNoError;
- });
- }
- else
- {
- ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
- if (threadContext == nullptr)
- {
- return JsErrorNoCurrentContext;
- }
- Recycler * recycler = threadContext->GetRecycler();
- return GlobalAPIWrapper([&](TTDRecorder& _actionEntryPopper) -> JsErrorCode
- {
- // Note, some references may live in arena-allocated memory, so we need to do this check
- if (!recycler->IsValidObject(ref))
- {
- return JsNoError;
- }
- recycler->RootRelease(ref, count);
- return JsNoError;
- });
- }
- }
- CHAKRA_API JsSetObjectBeforeCollectCallback(_In_ JsRef ref, _In_opt_ void *callbackState, _In_ JsObjectBeforeCollectCallback objectBeforeCollectCallback)
- {
- VALIDATE_JSREF(ref);
- if (Js::TaggedNumber::Is(ref))
- {
- return JsErrorInvalidArgument;
- }
- if (JsrtContext::Is(ref))
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- ThreadContext* threadContext = static_cast<JsrtContext *>(ref)->GetRuntime()->GetThreadContext();
- Recycler * recycler = threadContext->GetRecycler();
- recycler->SetObjectBeforeCollectCallback(ref, reinterpret_cast<Recycler::ObjectBeforeCollectCallback>(objectBeforeCollectCallback), callbackState,
- reinterpret_cast<Recycler::ObjectBeforeCollectCallbackWrapper>(JsrtCallbackState::ObjectBeforeCallectCallbackWrapper), threadContext);
- return JsNoError;
- });
- }
- else
- {
- ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
- if (threadContext == nullptr)
- {
- return JsErrorNoCurrentContext;
- }
- Recycler * recycler = threadContext->GetRecycler();
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- if (!recycler->IsValidObject(ref))
- {
- return JsErrorInvalidArgument;
- }
- recycler->SetObjectBeforeCollectCallback(ref, reinterpret_cast<Recycler::ObjectBeforeCollectCallback>(objectBeforeCollectCallback), callbackState,
- reinterpret_cast<Recycler::ObjectBeforeCollectCallbackWrapper>(JsrtCallbackState::ObjectBeforeCallectCallbackWrapper), threadContext);
- return JsNoError;
- });
- }
- }
- CHAKRA_API JsCreateContext(_In_ JsRuntimeHandle runtimeHandle, _Out_ JsContextRef *newContext)
- {
- return GlobalAPIWrapper([&](TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PARAM_NOT_NULL(newContext);
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- bool inRecord = false;
- bool activelyRecording = false;
- bool inReplay = false;
- #if ENABLE_TTD
- JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext * threadContext = runtime->GetThreadContext();
- if(threadContext->IsRuntimeInTTDMode() && threadContext->TTDContext->GetActiveScriptContext() != nullptr)
- {
- Js::ScriptContext* currentCtx = threadContext->TTDContext->GetActiveScriptContext();
- inRecord = currentCtx->IsTTDRecordModeEnabled();
- activelyRecording = currentCtx->ShouldPerformRecordAction();
- inReplay = currentCtx->IsTTDReplayModeEnabled();
- }
- #endif
- return CreateContextCore(runtimeHandle, _actionEntryPopper, inRecord, activelyRecording, inReplay, newContext);
- });
- }
- CHAKRA_API JsGetCurrentContext(_Out_ JsContextRef *currentContext)
- {
- PARAM_NOT_NULL(currentContext);
- BEGIN_JSRT_NO_EXCEPTION
- {
- *currentContext = (JsContextRef)JsrtContext::GetCurrent();
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsSetCurrentContext(_In_opt_ JsContextRef newContext)
- {
- VALIDATE_ENTER_CURRENT_THREAD();
- return GlobalAPIWrapper([&] (TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- Recycler* recycler = currentContext != nullptr ? currentContext->GetScriptContext()->GetRecycler() : nullptr;
- #if ENABLE_TTD
- Js::ScriptContext* newScriptContext = newContext != nullptr ? static_cast<JsrtContext*>(newContext)->GetScriptContext() : nullptr;
- Js::ScriptContext* oldScriptContext = currentContext != nullptr ? static_cast<JsrtContext*>(currentContext)->GetScriptContext() : nullptr;
- if(newScriptContext == nullptr)
- {
- if(oldScriptContext == nullptr)
- {
- ; //if newScriptContext and oldScriptContext are null then we don't worry about doing anything
- }
- else
- {
- if(oldScriptContext->IsTTDRecordModeEnabled())
- {
- //already know newScriptContext != oldScriptContext so don't check again
- if(oldScriptContext->ShouldPerformRecordAction())
- {
- oldScriptContext->GetThreadContext()->TTDLog->RecordJsRTSetCurrentContext(_actionEntryPopper, nullptr);
- }
- oldScriptContext->GetThreadContext()->TTDContext->SetActiveScriptContext(nullptr);
- }
- }
- }
- else
- {
- if(newScriptContext->IsTTDRecordModeEnabled())
- {
- if(newScriptContext != oldScriptContext && newScriptContext->ShouldPerformRecordAction())
- {
- newScriptContext->GetThreadContext()->TTDLog->RecordJsRTSetCurrentContext(_actionEntryPopper, newScriptContext->GetGlobalObject());
- }
- newScriptContext->GetThreadContext()->TTDContext->SetActiveScriptContext(newScriptContext);
- }
- }
- #endif
- if (currentContext && recycler->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (currentContext && currentContext->GetRuntime()->GetThreadContext()->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- if (!JsrtContext::TrySetCurrent((JsrtContext *)newContext))
- {
- return JsErrorWrongThread;
- }
- return JsNoError;
- });
- }
- CHAKRA_API JsGetContextOfObject(_In_ JsValueRef object, _Out_ JsContextRef *context)
- {
- VALIDATE_JSREF(object);
- PARAM_NOT_NULL(context);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!Js::VarIs<Js::RecyclableObject>(object))
- {
- RETURN_NO_EXCEPTION(JsErrorArgumentNotObject);
- }
- Js::RecyclableObject* obj = Js::VarTo<Js::RecyclableObject>(object);
- *context = (JsContextRef)obj->GetScriptContext()->GetLibrary()->GetJsrtContext();
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsGetContextData(_In_ JsContextRef context, _Out_ void **data)
- {
- VALIDATE_JSREF(context);
- PARAM_NOT_NULL(data);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!JsrtContext::Is(context))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- *data = static_cast<JsrtContext *>(context)->GetExternalData();
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsSetContextData(_In_ JsContextRef context, _In_ void *data)
- {
- VALIDATE_JSREF(context);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!JsrtContext::Is(context))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- static_cast<JsrtContext *>(context)->SetExternalData(data);
- }
- END_JSRT_NO_EXCEPTION
- }
- void HandleScriptCompileError(Js::ScriptContext * scriptContext, CompileScriptException * se, const WCHAR * sourceUrl)
- {
- HRESULT hr = se->ei.scode;
- if (hr == E_OUTOFMEMORY || hr == VBSERR_OutOfMemory || hr == ERRnoMemory)
- {
- Js::Throw::OutOfMemory();
- }
- else if (hr == E_ABORT)
- {
- Js::JavascriptOperators::ScriptAbort();
- }
- Js::JavascriptError* error = Js::JavascriptError::CreateFromCompileScriptException(scriptContext, se, sourceUrl);
- Js::JavascriptExceptionObject * exceptionObject = RecyclerNew(scriptContext->GetRecycler(),
- Js::JavascriptExceptionObject, error, scriptContext, nullptr);
- scriptContext->GetThreadContext()->SetRecordedException(exceptionObject);
- }
- CHAKRA_API JsGetUndefinedValue(_Out_ JsValueRef *undefinedValue)
- {
- return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(undefinedValue);
- *undefinedValue = scriptContext->GetLibrary()->GetUndefined();
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- CHAKRA_API JsGetNullValue(_Out_ JsValueRef *nullValue)
- {
- return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(nullValue);
- *nullValue = scriptContext->GetLibrary()->GetNull();
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- CHAKRA_API JsGetTrueValue(_Out_ JsValueRef *trueValue)
- {
- return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(trueValue);
- *trueValue = scriptContext->GetLibrary()->GetTrue();
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- CHAKRA_API JsGetFalseValue(_Out_ JsValueRef *falseValue)
- {
- return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(falseValue);
- *falseValue = scriptContext->GetLibrary()->GetFalse();
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- CHAKRA_API JsBoolToBoolean(_In_ bool value, _Out_ JsValueRef *booleanValue)
- {
- return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateBoolean, value);
- PARAM_NOT_NULL(booleanValue);
- *booleanValue = value ? scriptContext->GetLibrary()->GetTrue() : scriptContext->GetLibrary()->GetFalse();
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, booleanValue);
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- CHAKRA_API JsBooleanToBool(_In_ JsValueRef value, _Out_ bool *boolValue)
- {
- VALIDATE_JSREF(value);
- PARAM_NOT_NULL(boolValue);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!Js::VarIs<Js::JavascriptBoolean>(value))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- *boolValue = Js::VarTo<Js::JavascriptBoolean>(value)->GetValue() ? true : false;
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsConvertValueToBoolean(_In_ JsValueRef value, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToBooleanConversion, (Js::Var)value);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- PARAM_NOT_NULL(result);
- if (Js::JavascriptConversion::ToBool((Js::Var)value, scriptContext))
- {
- *result = scriptContext->GetLibrary()->GetTrue();
- }
- else
- {
- *result = scriptContext->GetLibrary()->GetFalse();
- }
- //It is either true or false which we always track so no need to store result identity
- return JsNoError;
- });
- }
- CHAKRA_API JsGetValueType(_In_ JsValueRef value, _Out_ JsValueType *type)
- {
- VALIDATE_JSREF(value);
- PARAM_NOT_NULL(type);
- BEGIN_JSRT_NO_EXCEPTION
- {
- Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(value);
- switch (typeId)
- {
- case Js::TypeIds_Undefined:
- *type = JsUndefined;
- break;
- case Js::TypeIds_Null:
- *type = JsNull;
- break;
- case Js::TypeIds_Boolean:
- *type = JsBoolean;
- break;
- case Js::TypeIds_Integer:
- case Js::TypeIds_Number:
- case Js::TypeIds_Int64Number:
- case Js::TypeIds_UInt64Number:
- *type = JsNumber;
- break;
- case Js::TypeIds_String:
- *type = JsString;
- break;
- case Js::TypeIds_Function:
- *type = JsFunction;
- break;
- case Js::TypeIds_Error:
- *type = JsError;
- break;
- case Js::TypeIds_Array:
- case Js::TypeIds_NativeIntArray:
- #if ENABLE_COPYONACCESS_ARRAY
- case Js::TypeIds_CopyOnAccessNativeIntArray:
- #endif
- case Js::TypeIds_NativeFloatArray:
- case Js::TypeIds_ES5Array:
- *type = JsArray;
- break;
- case Js::TypeIds_Symbol:
- *type = JsSymbol;
- break;
- case Js::TypeIds_ArrayBuffer:
- *type = JsArrayBuffer;
- break;
- case Js::TypeIds_DataView:
- *type = JsDataView;
- break;
- default:
- if (Js::TypedArrayBase::Is(typeId))
- {
- *type = JsTypedArray;
- }
- else
- {
- *type = JsObject;
- }
- break;
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsDoubleToNumber(_In_ double dbl, _Out_ JsValueRef *asValue)
- {
- PARAM_NOT_NULL(asValue);
- //If number is not heap allocated then we don't need to record/track the creation for time-travel
- if (Js::JavascriptNumber::TryToVarFastWithCheck(dbl, asValue))
- {
- return JsNoError;
- }
- return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateNumber, dbl);
- *asValue = Js::JavascriptNumber::ToVarNoCheck(dbl, scriptContext);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, asValue);
- return JsNoError;
- });
- }
- CHAKRA_API JsIntToNumber(_In_ int intValue, _Out_ JsValueRef *asValue)
- {
- PARAM_NOT_NULL(asValue);
- //If number is not heap allocated then we don't need to record/track the creation for time-travel
- if (Js::JavascriptNumber::TryToVarFast(intValue, asValue))
- {
- return JsNoError;
- }
- return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- #if !INT32VAR
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateInteger, intValue);
- #endif
- *asValue = Js::JavascriptNumber::ToVar(intValue, scriptContext);
- #if !INT32VAR
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, asValue);
- #endif
- return JsNoError;
- });
- }
- CHAKRA_API JsNumberToDouble(_In_ JsValueRef value, _Out_ double *asDouble)
- {
- VALIDATE_JSREF(value);
- PARAM_NOT_NULL(asDouble);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (Js::TaggedInt::Is(value))
- {
- *asDouble = Js::TaggedInt::ToDouble(value);
- }
- else if (Js::JavascriptNumber::Is_NoTaggedIntCheck(value))
- {
- *asDouble = Js::JavascriptNumber::GetValue(value);
- }
- else
- {
- *asDouble = 0;
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsNumberToInt(_In_ JsValueRef value, _Out_ int *asInt)
- {
- VALIDATE_JSREF(value);
- PARAM_NOT_NULL(asInt);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (Js::TaggedInt::Is(value))
- {
- *asInt = Js::TaggedInt::ToInt32(value);
- }
- else if (Js::JavascriptNumber::Is_NoTaggedIntCheck(value))
- {
- *asInt = Js::JavascriptConversion::ToInt32(Js::JavascriptNumber::GetValue(value));
- }
- else
- {
- *asInt = 0;
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsConvertValueToNumber(_In_ JsValueRef value, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToNumberConversion, (Js::Var)value);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- PARAM_NOT_NULL(result);
- *result = (JsValueRef)Js::JavascriptOperators::ToNumber((Js::Var)value, scriptContext);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- CHAKRA_API JsGetStringLength(_In_ JsValueRef value, _Out_ int *length)
- {
- VALIDATE_JSREF(value);
- PARAM_NOT_NULL(length);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!Js::VarIs<Js::JavascriptString>(value))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- *length = Js::VarTo<Js::JavascriptString>(value)->GetLengthAsSignedInt();
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsPointerToString(_In_reads_(stringLength) const WCHAR *stringValue, _In_ size_t stringLength, _Out_ JsValueRef *string)
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue, stringLength);
- PARAM_NOT_NULL(stringValue);
- PARAM_NOT_NULL(string);
- if (!Js::IsValidCharCount(stringLength))
- {
- Js::JavascriptError::ThrowOutOfMemoryError(scriptContext);
- }
- *string = Js::JavascriptString::NewCopyBuffer(stringValue, static_cast<charcount_t>(stringLength), scriptContext);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, string);
- return JsNoError;
- });
- }
- // TODO: The annotation of stringPtr is wrong. Need to fix definition in chakrart.h
- // The warning is '*stringPtr' could be '0' : this does not adhere to the specification for the function 'JsStringToPointer'.
- #pragma warning(suppress:6387)
- CHAKRA_API JsStringToPointer(_In_ JsValueRef stringValue, _Outptr_result_buffer_(*stringLength) const WCHAR **stringPtr, _Out_ size_t *stringLength)
- {
- VALIDATE_JSREF(stringValue);
- PARAM_NOT_NULL(stringPtr);
- *stringPtr = nullptr;
- PARAM_NOT_NULL(stringLength);
- *stringLength = 0;
- if (!Js::VarIs<Js::JavascriptString>(stringValue))
- {
- return JsErrorInvalidArgument;
- }
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- Js::JavascriptString *jsString = Js::VarTo<Js::JavascriptString>(stringValue);
- *stringPtr = jsString->GetSz();
- *stringLength = jsString->GetLength();
- return JsNoError;
- });
- }
- CHAKRA_API JsConvertValueToString(_In_ JsValueRef value, _Out_ JsValueRef *result)
- {
- PARAM_NOT_NULL(result);
- *result = nullptr;
- if (value != nullptr && Js::VarIs<Js::JavascriptString>(value))
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToStringConversion, (Js::Var)value);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- *result = value;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToStringConversion, (Js::Var)value);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- *result = (JsValueRef) Js::JavascriptConversion::ToString((Js::Var)value, scriptContext);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- CHAKRA_API JsGetGlobalObject(_Out_ JsValueRef *globalObject)
- {
- return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(globalObject);
- *globalObject = (JsValueRef)scriptContext->GetGlobalObject();
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- CHAKRA_API JsCreateObject(_Out_ JsValueRef *object)
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateBasicObject);
- PARAM_NOT_NULL(object);
- *object = scriptContext->GetLibrary()->CreateObject();
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateExternalObjectWithPrototype(_In_opt_ void *data,
- _In_opt_ JsFinalizeCallback finalizeCallback,
- _In_opt_ JsValueRef prototype,
- _Out_ JsValueRef *object)
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateExternalObject, prototype);
- PARAM_NOT_NULL(object);
- Js::RecyclableObject * prototypeObject = nullptr;
- if (prototype != JS_INVALID_REFERENCE)
- {
- VALIDATE_INCOMING_OBJECT(prototype, scriptContext);
- prototypeObject = Js::VarTo<Js::RecyclableObject>(prototype);
- }
- *object = JsrtExternalObject::Create(data, 0, finalizeCallback, prototypeObject, scriptContext, nullptr);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateExternalObject(_In_opt_ void *data, _In_opt_ JsFinalizeCallback finalizeCallback, _Out_ JsValueRef *object)
- {
- return JsCreateExternalObjectWithPrototype(data, finalizeCallback, JS_INVALID_REFERENCE, object);
- }
- CHAKRA_API JsConvertValueToObject(_In_ JsValueRef value, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToObjectConversion, (Js::Var)value);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- PARAM_NOT_NULL(result);
- *result = (JsValueRef)Js::JavascriptOperators::ToObject((Js::Var)value, scriptContext);
- Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- CHAKRA_API JsGetPrototype(_In_ JsValueRef object, _Out_ JsValueRef *prototypeObject)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetPrototype, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- PARAM_NOT_NULL(prototypeObject);
- *prototypeObject = (JsValueRef)Js::JavascriptOperators::OP_GetPrototype(object, scriptContext);
- Assert(*prototypeObject == nullptr || !Js::CrossSite::NeedMarshalVar(*prototypeObject, scriptContext));
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, prototypeObject);
- return JsNoError;
- });
- }
- CHAKRA_API JsSetPrototype(_In_ JsValueRef object, _In_ JsValueRef prototypeObject)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetPrototype, object, prototypeObject);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_OBJECT_OR_NULL(prototypeObject, scriptContext);
- // We're not allowed to set this.
- if (object == scriptContext->GetLibrary()->GetObjectPrototype())
- {
- return JsErrorInvalidArgument;
- }
- Js::JavascriptObject::ChangePrototype(Js::VarTo<Js::RecyclableObject>(object), Js::VarTo<Js::RecyclableObject>(prototypeObject), true, scriptContext);
- return JsNoError;
- });
- }
- CHAKRA_API JsInstanceOf(_In_ JsValueRef object, _In_ JsValueRef constructor, _Out_ bool *result) {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTInstanceOf, object, constructor);
- VALIDATE_INCOMING_REFERENCE(object, scriptContext);
- VALIDATE_INCOMING_REFERENCE(constructor, scriptContext);
- PARAM_NOT_NULL(result);
- Js::Var value = Js::JavascriptOperators::OP_IsInst(object, constructor, scriptContext, nullptr);
- *result = !!Js::VarTo<Js::JavascriptBoolean>(value)->GetValue();
- return JsNoError;
- });
- }
- CHAKRA_API JsGetExtensionAllowed(_In_ JsValueRef object, _Out_ bool *value)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- PARAM_NOT_NULL(value);
- *value = false;
- *value = Js::VarTo<Js::RecyclableObject>(object)->IsExtensible() != 0;
- return JsNoError;
- });
- }
- CHAKRA_API JsPreventExtension(_In_ JsValueRef object)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- Js::VarTo<Js::RecyclableObject>(object)->PreventExtensions();
- return JsNoError;
- });
- }
- CHAKRA_API JsHasOwnPropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
- _In_ const Js::PropertyRecord * propertyRecord, _Out_ bool *hasOwnProperty, _In_opt_ Js::PropertyString * propString)
- {
- *hasOwnProperty = Js::JavascriptOperators::OP_HasOwnProperty(object,
- propertyRecord->GetPropertyId(), scriptContext, propString) != 0;
- return JsNoError;
- }
- CHAKRA_API JsHasOwnProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId,
- _Out_ bool *hasOwnProperty)
- {
- return ContextAPIWrapper<true>([&](Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasOwnProperty, (const Js::PropertyRecord *)propertyId, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- PARAM_NOT_NULL(hasOwnProperty);
- *hasOwnProperty = false;
- return JsHasOwnPropertyCommon(scriptContext, object,
- (const Js::PropertyRecord *)propertyId, hasOwnProperty, nullptr);
- });
- }
- #ifdef _CHAKRACOREBUILD
- static JsErrorCode InternalGetPropertyRecord(Js::ScriptContext * scriptContext,
- Js::RecyclableObject * key, _Out_ const Js::PropertyRecord ** propertyRecord)
- {
- Assert(propertyRecord != nullptr);
- *propertyRecord = nullptr;
- switch(key->GetTypeId())
- {
- case Js::TypeIds_String:
- scriptContext->GetOrAddPropertyRecord(Js::VarTo<Js::JavascriptString>(key),
- (Js::PropertyRecord const **)propertyRecord);
- break;
- case Js::TypeIds_Symbol:
- *propertyRecord = Js::VarTo<Js::JavascriptSymbol>(key)->GetValue();
- break;
- default:
- return JsErrorInvalidArgument;
- };
- return JsNoError;
- }
- CHAKRA_API JsObjectHasOwnProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ bool *hasOwnProperty)
- {
- return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
- PARAM_NOT_NULL(hasOwnProperty);
- *hasOwnProperty = false;
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(propertyId), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- return JsHasOwnPropertyCommon(scriptContext, object, propertyRecord, hasOwnProperty, Js::VarIs<Js::PropertyString>(propertyId) ? (Js::PropertyString*)propertyId : nullptr);
- });
- }
- #endif
- static JsErrorCode JsGetPropertyCommon(Js::ScriptContext * scriptContext,
- _In_ Js::RecyclableObject * object,
- _In_ const Js::PropertyRecord * propertyRecord, _Out_ JsValueRef *value)
- {
- AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
- *value = Js::JavascriptOperators::GetPropertyNoCache(object, propertyRecord->GetPropertyId(), scriptContext);
- Assert(*value == nullptr || !Js::CrossSite::NeedMarshalVar(*value, scriptContext));
- return JsNoError;
- }
- CHAKRA_API JsGetProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *value)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetProperty, (const Js::PropertyRecord *)propertyId, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- PARAM_NOT_NULL(value);
- *value = nullptr;
- Js::RecyclableObject * instance = Js::VarTo<Js::RecyclableObject>(object);
- JsErrorCode err = JsGetPropertyCommon(scriptContext, instance, (const Js::PropertyRecord *)propertyId,
- value);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value);
- return err;
- });
- }
- #ifdef _CHAKRACOREBUILD
- CHAKRA_API JsObjectGetProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ JsValueRef *value)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
- PARAM_NOT_NULL(value);
- *value = nullptr;
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(propertyId), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- Assert(propertyRecord != nullptr);
- Js::RecyclableObject * instance = Js::VarTo<Js::RecyclableObject>(object);
- return JsGetPropertyCommon(scriptContext, instance, propertyRecord, value);
- });
- }
- #endif
- static JsErrorCode JsGetOwnPropertyDescriptorCommon(Js::ScriptContext * scriptContext,
- _In_ JsValueRef object, _In_ const Js::PropertyRecord * propertyRecord, _Out_ JsValueRef *propertyDescriptor)
- {
- AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
- Js::PropertyDescriptor propertyDescriptorValue;
- if (Js::JavascriptOperators::GetOwnPropertyDescriptor(Js::VarTo<Js::RecyclableObject>(object),
- propertyRecord->GetPropertyId(), scriptContext, &propertyDescriptorValue))
- {
- *propertyDescriptor = Js::JavascriptOperators::FromPropertyDescriptor(propertyDescriptorValue, scriptContext);
- }
- else
- {
- *propertyDescriptor = scriptContext->GetLibrary()->GetUndefined();
- }
- Assert(*propertyDescriptor == nullptr || !Js::CrossSite::NeedMarshalVar(*propertyDescriptor, scriptContext));
- return JsNoError;
- }
- CHAKRA_API JsGetOwnPropertyDescriptor(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *propertyDescriptor)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetOwnPropertyInfo, (const Js::PropertyRecord *)propertyId, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- PARAM_NOT_NULL(propertyDescriptor);
- *propertyDescriptor = nullptr;
- JsErrorCode err = JsGetOwnPropertyDescriptorCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
- propertyDescriptor);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, propertyDescriptor);
- return err;
- });
- }
- #ifdef _CHAKRACOREBUILD
- CHAKRA_API JsObjectGetOwnPropertyDescriptor(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ JsValueRef *propertyDescriptor)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
- PARAM_NOT_NULL(propertyDescriptor);
- *propertyDescriptor = nullptr;
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(propertyId), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- Assert(propertyRecord != nullptr);
- return JsGetOwnPropertyDescriptorCommon(scriptContext, object, propertyRecord, propertyDescriptor);
- });
- }
- #endif
- static JsErrorCode JsSetPropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
- _In_ const Js::PropertyRecord * propertyRecord, _In_ JsValueRef value, _In_ bool useStrictRules)
- {
- AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
- Js::JavascriptOperators::OP_SetProperty(object, propertyRecord->GetPropertyId(),
- value, scriptContext, nullptr, useStrictRules ? Js::PropertyOperation_StrictMode : Js::PropertyOperation_None);
- return JsNoError;
- }
- CHAKRA_API JsSetProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _In_ JsValueRef value, _In_ bool useStrictRules)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetProperty, object, (const Js::PropertyRecord *)propertyId, value, useStrictRules);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- return JsSetPropertyCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
- value, useStrictRules);
- });
- }
- #ifdef _CHAKRACOREBUILD
- CHAKRA_API JsObjectSetProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _In_ JsValueRef value, _In_ bool useStrictRules)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(propertyId), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- Assert(propertyRecord != nullptr);
- return JsSetPropertyCommon(scriptContext, object, propertyRecord, value, useStrictRules);
- });
- }
- #endif
- CHAKRA_API JsHasProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ bool *hasProperty)
- {
- VALIDATE_JSREF(object);
- if (!Js::JavascriptOperators::IsObject(object)) return JsErrorArgumentNotObject;
- auto internalHasProperty = [&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasProperty, (Js::PropertyRecord *)propertyId, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- PARAM_NOT_NULL(hasProperty);
- *hasProperty = false;
- Js::RecyclableObject * instance = Js::VarTo<Js::RecyclableObject>(object);
- *hasProperty = Js::JavascriptOperators::HasProperty(instance, ((Js::PropertyRecord *)propertyId)->GetPropertyId()) != 0;
- return JsNoError;
- };
- Js::RecyclableObject* robject = Js::VarTo<Js::RecyclableObject>(object);
- Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(robject);
- while (typeId != Js::TypeIds_Null && typeId != Js::TypeIds_Proxy)
- {
- robject = robject->GetPrototype();
- typeId = Js::JavascriptOperators::GetTypeId(robject);
- }
- if (typeId == Js::TypeIds_Proxy)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>(internalHasProperty);
- }
- #ifdef _CHAKRACOREBUILD
- else if (typeId == Js::TypeIds_Object)
- {
- // CEOs can also have traps so we would want the Enter/Leave semantics for those.
- Js::CustomExternalWrapperObject * externalWrapper = Js::JavascriptOperators::TryFromVar<Js::CustomExternalWrapperObject>(object);
- if (externalWrapper)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>(internalHasProperty);
- }
- }
- #endif
- return ContextAPINoScriptWrapper(internalHasProperty);
- }
- #ifdef _CHAKRACOREBUILD
- CHAKRA_API JsObjectHasProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ bool *hasProperty)
- {
- VALIDATE_JSREF(object);
- if (!Js::JavascriptOperators::IsObject(object)) return JsErrorArgumentNotObject;
- auto internalHasProperty = [&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
- PARAM_NOT_NULL(hasProperty);
- *hasProperty = false;
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(propertyId), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- Js::RecyclableObject * instance = Js::VarTo<Js::RecyclableObject>(object);
- *hasProperty = Js::JavascriptOperators::HasProperty(instance, propertyRecord->GetPropertyId()) != 0;
- return JsNoError;
- };
- Js::RecyclableObject* robject = Js::VarTo<Js::RecyclableObject>(object);
- Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(robject);
- while (typeId != Js::TypeIds_Null && typeId != Js::TypeIds_Proxy)
- {
- robject = robject->GetPrototype();
- typeId = Js::JavascriptOperators::GetTypeId(robject);
- }
- if (typeId == Js::TypeIds_Proxy)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>(internalHasProperty);
- }
- else if (typeId == Js::TypeIds_Object)
- {
- // CEOs can also have traps so we would want the Enter/Leave semantics for those.
- Js::CustomExternalWrapperObject * externalWrapper = Js::JavascriptOperators::TryFromVar<Js::CustomExternalWrapperObject>(object);
- if (externalWrapper)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>(internalHasProperty);
- }
- }
- return ContextAPINoScriptWrapper(internalHasProperty);
- }
- #endif
- static JsErrorCode JsDeletePropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
- _In_ const Js::PropertyRecord * propertyRecord, _In_ bool useStrictRules, _Out_ JsValueRef *result)
- {
- AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
- *result = Js::JavascriptOperators::OP_DeleteProperty((Js::Var)object,
- propertyRecord->GetPropertyId(),
- scriptContext, useStrictRules ? Js::PropertyOperation_StrictMode : Js::PropertyOperation_None);
- Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
- return JsNoError;
- }
- CHAKRA_API JsDeleteProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId,
- _In_ bool useStrictRules, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTDeleteProperty, object, (const Js::PropertyRecord *)propertyId, useStrictRules);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- PARAM_NOT_NULL(result);
- *result = nullptr;
- JsErrorCode err = JsDeletePropertyCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
- useStrictRules, result);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return err;
- });
- }
- #ifdef _CHAKRACOREBUILD
- CHAKRA_API JsObjectDeleteProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId,
- _In_ bool useStrictRules, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
- PARAM_NOT_NULL(result);
- *result = nullptr;
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(propertyId), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- Assert(propertyRecord != nullptr);
- return JsDeletePropertyCommon(scriptContext, object, propertyRecord,
- useStrictRules, result);
- });
- }
- #endif
- static JsErrorCode JsDefinePropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
- _In_ const Js::PropertyRecord *propertyRecord, _In_ JsValueRef propertyDescriptor,
- _Out_ bool *result)
- {
- AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
- Js::PropertyDescriptor propertyDescriptorValue;
- if (!Js::JavascriptOperators::ToPropertyDescriptor(propertyDescriptor, &propertyDescriptorValue, scriptContext))
- {
- return JsErrorInvalidArgument;
- }
- *result = Js::JavascriptOperators::DefineOwnPropertyDescriptor(
- Js::VarTo<Js::RecyclableObject>(object), propertyRecord->GetPropertyId(),
- propertyDescriptorValue, true, scriptContext) != 0;
- return JsNoError;
- }
- CHAKRA_API JsDefineProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId,
- _In_ JsValueRef propertyDescriptor, _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTDefineProperty, object, (const Js::PropertyRecord *)propertyId, propertyDescriptor);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- VALIDATE_INCOMING_OBJECT(propertyDescriptor, scriptContext);
- PARAM_NOT_NULL(result);
- *result = false;
- return JsDefinePropertyCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
- propertyDescriptor, result);
- });
- }
- #ifdef _CHAKRACOREBUILD
- CHAKRA_API
- JsObjectDefinePropertyFull(
- _In_ JsValueRef object,
- _In_ JsValueRef key,
- _In_opt_ JsValueRef value,
- _In_opt_ JsValueRef getter,
- _In_opt_ JsValueRef setter,
- _In_ bool writable,
- _In_ bool enumerable,
- _In_ bool configurable,
- _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(key, scriptContext);
- PARAM_NOT_NULL(result);
- *result = false;
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(key), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- Js::PropertyDescriptor propertyDescriptor;
- if (value)
- {
- propertyDescriptor.SetValue(value);
- }
- if (getter)
- {
- propertyDescriptor.SetGetter(getter);
- }
- if (setter)
- {
- propertyDescriptor.SetSetter(setter);
- }
- if (writable)
- {
- propertyDescriptor.SetWritable(writable);
- }
- if (enumerable)
- {
- propertyDescriptor.SetEnumerable(enumerable);
- }
- if (configurable)
- {
- propertyDescriptor.SetConfigurable(configurable);
- }
- *result = Js::JavascriptOperators::DefineOwnPropertyDescriptor(
- Js::VarTo<Js::RecyclableObject>(object), propertyRecord->GetPropertyId(),
- propertyDescriptor, true, scriptContext) != 0;
- return JsNoError;
- });
- }
- CHAKRA_API JsObjectDefineProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId,
- _In_ JsValueRef propertyDescriptor, _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
- TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
- VALIDATE_INCOMING_OBJECT(propertyDescriptor, scriptContext);
- PARAM_NOT_NULL(result);
- *result = false;
- const Js::PropertyRecord *propertyRecord = nullptr;
- JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
- Js::VarTo<Js::RecyclableObject>(propertyId), &propertyRecord);
- if (errorValue != JsNoError)
- {
- return errorValue;
- }
- return JsDefinePropertyCommon(scriptContext, object, propertyRecord, propertyDescriptor, result);
- });
- }
- #endif
- CHAKRA_API JsGetOwnPropertyNames(_In_ JsValueRef object, _Out_ JsValueRef *propertyNames)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetOwnPropertyNamesInfo, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- PARAM_NOT_NULL(propertyNames);
- *propertyNames = nullptr;
- *propertyNames = Js::JavascriptOperators::GetOwnPropertyNames(object, scriptContext);
- Assert(*propertyNames == nullptr || !Js::CrossSite::NeedMarshalVar(*propertyNames, scriptContext));
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, propertyNames);
- return JsNoError;
- });
- }
- CHAKRA_API JsGetOwnPropertySymbols(_In_ JsValueRef object, _Out_ JsValueRef *propertySymbols)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetOwnPropertySymbolsInfo, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- PARAM_NOT_NULL(propertySymbols);
- *propertySymbols = Js::JavascriptOperators::GetOwnPropertySymbols(object, scriptContext);
- Assert(*propertySymbols == nullptr || !Js::CrossSite::NeedMarshalVar(*propertySymbols, scriptContext));
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, propertySymbols);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateArray(_In_ unsigned int length, _Out_ JsValueRef *result)
- {
- return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateBasicArray, length);
- PARAM_NOT_NULL(result);
- *result = nullptr;
- *result = scriptContext->GetLibrary()->CreateArray(length);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateArrayBuffer(_In_ unsigned int byteLength, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateArrayBuffer, byteLength);
- PARAM_NOT_NULL(result);
- Js::JavascriptLibrary* library = scriptContext->GetLibrary();
- *result = library->CreateArrayBuffer(byteLength);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateExternalArrayBuffer(_Pre_maybenull_ _Pre_writable_byte_size_(byteLength) void *data, _In_ unsigned int byteLength,
- _In_opt_ JsFinalizeCallback finalizeCallback, _In_opt_ void *callbackState, _Out_ JsValueRef *result)
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateExternalArrayBuffer, reinterpret_cast<BYTE*>(data), byteLength);
- PARAM_NOT_NULL(result);
- if (data == nullptr && byteLength > 0)
- {
- return JsErrorInvalidArgument;
- }
- Js::JavascriptLibrary* library = scriptContext->GetLibrary();
- *result = Js::JsrtExternalArrayBuffer::New(
- reinterpret_cast<BYTE*>(data),
- byteLength,
- finalizeCallback,
- callbackState,
- library->GetArrayBufferType());
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateTypedArray(_In_ JsTypedArrayType arrayType, _In_ JsValueRef baseArray, _In_ unsigned int byteOffset,
- _In_ unsigned int elementLength, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- if (baseArray != JS_INVALID_REFERENCE)
- {
- VALIDATE_INCOMING_REFERENCE(baseArray, scriptContext);
- }
- PARAM_NOT_NULL(result);
- Js::JavascriptLibrary* library = scriptContext->GetLibrary();
- const bool fromArrayBuffer = (baseArray != JS_INVALID_REFERENCE && Js::VarIs<Js::ArrayBuffer>(baseArray));
- if (byteOffset != 0 && !fromArrayBuffer)
- {
- return JsErrorInvalidArgument;
- }
- if (elementLength != 0 && !(baseArray == JS_INVALID_REFERENCE || fromArrayBuffer))
- {
- return JsErrorInvalidArgument;
- }
- Js::JavascriptFunction* constructorFunc = nullptr;
- Js::Var values[4] =
- {
- library->GetUndefined(),
- baseArray != nullptr ? baseArray : Js::JavascriptNumber::ToVar(elementLength, scriptContext)
- };
- if (fromArrayBuffer)
- {
- values[2] = Js::JavascriptNumber::ToVar(byteOffset, scriptContext);
- values[3] = Js::JavascriptNumber::ToVar(elementLength, scriptContext);
- }
- Js::CallInfo info(Js::CallFlags_New, fromArrayBuffer ? 4 : 2);
- Js::Arguments args(info, values);
- switch (arrayType)
- {
- case JsArrayTypeInt8:
- constructorFunc = library->GetInt8ArrayConstructor();
- break;
- case JsArrayTypeUint8:
- constructorFunc = library->GetUint8ArrayConstructor();
- break;
- case JsArrayTypeUint8Clamped:
- constructorFunc = library->GetUint8ClampedArrayConstructor();
- break;
- case JsArrayTypeInt16:
- constructorFunc = library->GetInt16ArrayConstructor();
- break;
- case JsArrayTypeUint16:
- constructorFunc = library->GetUint16ArrayConstructor();
- break;
- case JsArrayTypeInt32:
- constructorFunc = library->GetInt32ArrayConstructor();
- break;
- case JsArrayTypeUint32:
- constructorFunc = library->GetUint32ArrayConstructor();
- break;
- case JsArrayTypeFloat32:
- constructorFunc = library->GetFloat32ArrayConstructor();
- break;
- case JsArrayTypeFloat64:
- constructorFunc = library->GetFloat64ArrayConstructor();
- break;
- default:
- return JsErrorInvalidArgument;
- }
- BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
- {
- *result = Js::JavascriptFunction::CallAsConstructor(constructorFunc, /* overridingNewTarget = */nullptr, args, scriptContext);
- }
- END_SAFE_REENTRANT_CALL
- JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateDataView(_In_ JsValueRef arrayBuffer, _In_ unsigned int byteOffset, _In_ unsigned int byteLength, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_REFERENCE(arrayBuffer, scriptContext);
- PARAM_NOT_NULL(result);
- if (!Js::VarIs<Js::ArrayBuffer>(arrayBuffer))
- {
- return JsErrorInvalidArgument;
- }
- Js::JavascriptLibrary* library = scriptContext->GetLibrary();
- *result = library->CreateDataView(Js::VarTo<Js::ArrayBuffer>(arrayBuffer), byteOffset, byteLength);
- JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
- return JsNoError;
- });
- }
- C_ASSERT(JsArrayTypeUint8 - Js::TypeIds_Uint8Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- C_ASSERT(JsArrayTypeUint8Clamped - Js::TypeIds_Uint8ClampedArray == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- C_ASSERT(JsArrayTypeInt16 - Js::TypeIds_Int16Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- C_ASSERT(JsArrayTypeUint16 - Js::TypeIds_Uint16Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- C_ASSERT(JsArrayTypeInt32 - Js::TypeIds_Int32Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- C_ASSERT(JsArrayTypeUint32 - Js::TypeIds_Uint32Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- C_ASSERT(JsArrayTypeFloat32 - Js::TypeIds_Float32Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- C_ASSERT(JsArrayTypeFloat64 - Js::TypeIds_Float64Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
- inline JsTypedArrayType GetTypedArrayType(Js::TypeId typeId)
- {
- Assert(Js::TypedArrayBase::Is(typeId));
- return static_cast<JsTypedArrayType>(typeId + (JsArrayTypeInt8 - Js::TypeIds_Int8Array));
- }
- CHAKRA_API JsGetTypedArrayInfo(_In_ JsValueRef typedArray, _Out_opt_ JsTypedArrayType *arrayType, _Out_opt_ JsValueRef *arrayBuffer,
- _Out_opt_ unsigned int *byteOffset, _Out_opt_ unsigned int *byteLength)
- {
- VALIDATE_JSREF(typedArray);
- BEGIN_JSRT_NO_EXCEPTION
- {
- const Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(typedArray);
- if (!Js::TypedArrayBase::Is(typeId))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- if (arrayType != nullptr) {
- *arrayType = GetTypedArrayType(typeId);
- }
- Js::TypedArrayBase* typedArrayBase = Js::VarTo<Js::TypedArrayBase>(typedArray);
- if (arrayBuffer != nullptr) {
- *arrayBuffer = typedArrayBase->GetArrayBuffer();
- }
- if (byteOffset != nullptr) {
- *byteOffset = typedArrayBase->GetByteOffset();
- }
- if (byteLength != nullptr) {
- *byteLength = typedArrayBase->GetByteLength();
- }
- }
- #if ENABLE_TTD
- Js::ScriptContext* scriptContext = Js::VarTo<Js::RecyclableObject>(typedArray)->GetScriptContext();
- if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext) && arrayBuffer != nullptr)
- {
- scriptContext->GetThreadContext()->TTDLog->RecordJsRTGetTypedArrayInfo(typedArray, *arrayBuffer);
- }
- #endif
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsGetArrayBufferStorage(_In_ JsValueRef instance, _Outptr_result_bytebuffer_(*bufferLength) BYTE **buffer,
- _Out_ unsigned int *bufferLength)
- {
- VALIDATE_JSREF(instance);
- PARAM_NOT_NULL(buffer);
- PARAM_NOT_NULL(bufferLength);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!Js::VarIs<Js::ArrayBuffer>(instance))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- Js::ArrayBuffer* arrayBuffer = Js::VarTo<Js::ArrayBuffer>(instance);
- *buffer = arrayBuffer->GetBuffer();
- *bufferLength = arrayBuffer->GetByteLength();
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsGetTypedArrayStorage(_In_ JsValueRef instance, _Outptr_result_bytebuffer_(*bufferLength) BYTE **buffer,
- _Out_ unsigned int *bufferLength, _Out_opt_ JsTypedArrayType *typedArrayType, _Out_opt_ int *elementSize)
- {
- VALIDATE_JSREF(instance);
- PARAM_NOT_NULL(buffer);
- PARAM_NOT_NULL(bufferLength);
- BEGIN_JSRT_NO_EXCEPTION
- {
- const Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(instance);
- if (!Js::TypedArrayBase::Is(typeId))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- Js::TypedArrayBase* typedArrayBase = Js::VarTo<Js::TypedArrayBase>(instance);
- *buffer = typedArrayBase->GetByteBuffer();
- *bufferLength = typedArrayBase->GetByteLength();
- if (typedArrayType)
- {
- *typedArrayType = GetTypedArrayType(typeId);
- }
- if (elementSize)
- {
- switch (typeId)
- {
- case Js::TypeIds_Int8Array:
- *elementSize = sizeof(int8);
- break;
- case Js::TypeIds_Uint8Array:
- *elementSize = sizeof(uint8);
- break;
- case Js::TypeIds_Uint8ClampedArray:
- *elementSize = sizeof(uint8);
- break;
- case Js::TypeIds_Int16Array:
- *elementSize = sizeof(int16);
- break;
- case Js::TypeIds_Uint16Array:
- *elementSize = sizeof(uint16);
- break;
- case Js::TypeIds_Int32Array:
- *elementSize = sizeof(int32);
- break;
- case Js::TypeIds_Uint32Array:
- *elementSize = sizeof(uint32);
- break;
- case Js::TypeIds_Float32Array:
- *elementSize = sizeof(float);
- break;
- case Js::TypeIds_Float64Array:
- *elementSize = sizeof(double);
- break;
- default:
- AssertMsg(FALSE, "invalid typed array type");
- *elementSize = 1;
- RETURN_NO_EXCEPTION(JsErrorFatal);
- }
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsGetDataViewStorage(_In_ JsValueRef instance, _Outptr_result_bytebuffer_(*bufferLength) BYTE **buffer, _Out_ unsigned int *bufferLength)
- {
- VALIDATE_JSREF(instance);
- PARAM_NOT_NULL(buffer);
- PARAM_NOT_NULL(bufferLength);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!Js::VarIs<Js::DataView>(instance))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- Js::DataView* dataView = Js::VarTo<Js::DataView>(instance);
- *buffer = dataView->GetArrayBuffer()->GetBuffer() + dataView->GetByteOffset();
- *bufferLength = dataView->GetLength();
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsCreateSymbol(_In_ JsValueRef description, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateSymbol, description);
- PARAM_NOT_NULL(result);
- *result = nullptr;
- Js::JavascriptString* descriptionString;
- if (description != JS_INVALID_REFERENCE)
- {
- VALIDATE_INCOMING_REFERENCE(description, scriptContext);
- descriptionString = Js::JavascriptConversion::ToString(description, scriptContext);
- }
- else
- {
- descriptionString = scriptContext->GetLibrary()->GetEmptyString();
- }
- *result = scriptContext->GetLibrary()->CreateSymbol(descriptionString);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- CHAKRA_API JsHasIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index, _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_REFERENCE(index, scriptContext);
- PARAM_NOT_NULL(result);
- *result = false;
- *result = Js::JavascriptOperators::OP_HasItem((Js::Var)object, (Js::Var)index, scriptContext) != 0;
- return JsNoError;
- });
- }
- CHAKRA_API JsGetIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetIndex, index, object);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_REFERENCE(index, scriptContext);
- PARAM_NOT_NULL(result);
- *result = nullptr;
- *result = (JsValueRef)Js::JavascriptOperators::OP_GetElementI((Js::Var)object, (Js::Var)index, scriptContext);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- CHAKRA_API JsSetIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index, _In_ JsValueRef value)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetIndex, object, index, value);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_REFERENCE(index, scriptContext);
- VALIDATE_INCOMING_REFERENCE(value, scriptContext);
- Js::JavascriptOperators::OP_SetElementI((Js::Var)object, (Js::Var)index, (Js::Var)value, scriptContext);
- return JsNoError;
- });
- }
- CHAKRA_API JsDeleteIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- VALIDATE_INCOMING_REFERENCE(index, scriptContext);
- Js::JavascriptOperators::OP_DeleteElementI((Js::Var)object, (Js::Var)index, scriptContext);
- return JsNoError;
- });
- }
- template <class T, bool clamped = false> struct TypedArrayTypeTraits { static const JsTypedArrayType cTypedArrayType; };
- template<> struct TypedArrayTypeTraits<int8> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeInt8; };
- template<> struct TypedArrayTypeTraits<uint8, false> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint8; };
- template<> struct TypedArrayTypeTraits<uint8, true> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint8Clamped; };
- template<> struct TypedArrayTypeTraits<int16> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeInt16; };
- template<> struct TypedArrayTypeTraits<uint16> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint16; };
- template<> struct TypedArrayTypeTraits<int32> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeInt32; };
- template<> struct TypedArrayTypeTraits<uint32> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint32; };
- template<> struct TypedArrayTypeTraits<float> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeFloat32; };
- template<> struct TypedArrayTypeTraits<double> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeFloat64; };
- template <class T, bool clamped = false>
- Js::ArrayObject* CreateTypedArray(Js::ScriptContext *scriptContext, void* data, unsigned int length)
- {
- Js::JavascriptLibrary* library = scriptContext->GetLibrary();
- Js::ArrayBufferBase* arrayBuffer = RecyclerNew(
- scriptContext->GetRecycler(),
- Js::ExternalArrayBuffer,
- reinterpret_cast<BYTE*>(data),
- length * sizeof(T),
- library->GetArrayBufferType());
- return static_cast<Js::ArrayObject*>(Js::TypedArray<T, clamped>::Create(arrayBuffer, 0, length, library));
- }
- template <class T, bool clamped = false>
- void GetObjectArrayData(Js::ArrayObject* objectArray, void** data, JsTypedArrayType* arrayType, uint* length)
- {
- Js::TypedArray<T, clamped>* typedArray = Js::VarTo<Js::TypedArray<T, clamped>>(objectArray);
- *data = typedArray->GetArrayBuffer()->GetBuffer();
- *arrayType = TypedArrayTypeTraits<T, clamped>::cTypedArrayType;
- *length = typedArray->GetLength();
- }
- CHAKRA_API JsSetIndexedPropertiesToExternalData(
- _In_ JsValueRef object,
- _In_ void* data,
- _In_ JsTypedArrayType arrayType,
- _In_ unsigned int elementLength)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_OBJECT(object, scriptContext);
- // Don't support doing this on array or array-like object
- Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(object);
- if (!Js::DynamicType::Is(typeId)
- || Js::DynamicObject::IsAnyArrayTypeId(typeId)
- || (typeId >= Js::TypeIds_TypedArrayMin && typeId <= Js::TypeIds_TypedArrayMax)
- || typeId == Js::TypeIds_ArrayBuffer
- || typeId == Js::TypeIds_DataView
- || Js::VarTo<Js::RecyclableObject>(object)->IsExternal()
- )
- {
- return JsErrorInvalidArgument;
- }
- if (data == nullptr && elementLength > 0)
- {
- return JsErrorInvalidArgument;
- }
- Js::ArrayObject* newTypedArray = nullptr;
- switch (arrayType)
- {
- case JsArrayTypeInt8:
- newTypedArray = CreateTypedArray<int8>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeUint8:
- newTypedArray = CreateTypedArray<uint8>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeUint8Clamped:
- newTypedArray = CreateTypedArray<uint8, true>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeInt16:
- newTypedArray = CreateTypedArray<int16>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeUint16:
- newTypedArray = CreateTypedArray<uint16>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeInt32:
- newTypedArray = CreateTypedArray<int32>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeUint32:
- newTypedArray = CreateTypedArray<uint32>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeFloat32:
- newTypedArray = CreateTypedArray<float>(scriptContext, data, elementLength);
- break;
- case JsArrayTypeFloat64:
- newTypedArray = CreateTypedArray<double>(scriptContext, data, elementLength);
- break;
- default:
- return JsErrorInvalidArgument;
- }
- Js::DynamicObject* dynamicObject = Js::VarTo<Js::DynamicObject>(object);
- dynamicObject->SetObjectArray(newTypedArray);
- return JsNoError;
- });
- }
- CHAKRA_API JsHasIndexedPropertiesExternalData(_In_ JsValueRef object, _Out_ bool *value)
- {
- VALIDATE_JSREF(object);
- PARAM_NOT_NULL(value);
- BEGIN_JSRT_NO_EXCEPTION
- {
- *value = false;
- if (Js::DynamicType::Is(Js::JavascriptOperators::GetTypeId(object)))
- {
- Js::DynamicObject* dynamicObject = Js::UnsafeVarTo<Js::DynamicObject>(object);
- Js::ArrayObject* objectArray = dynamicObject->GetObjectArray();
- *value = (objectArray && !Js::DynamicObject::IsAnyArray(objectArray));
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsGetIndexedPropertiesExternalData(
- _In_ JsValueRef object,
- _Out_ void** buffer,
- _Out_ JsTypedArrayType* arrayType,
- _Out_ unsigned int* elementLength)
- {
- VALIDATE_JSREF(object);
- PARAM_NOT_NULL(buffer);
- PARAM_NOT_NULL(arrayType);
- PARAM_NOT_NULL(elementLength);
- BEGIN_JSRT_NO_EXCEPTION
- {
- if (!Js::DynamicType::Is(Js::JavascriptOperators::GetTypeId(object)))
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- *buffer = nullptr;
- *arrayType = JsTypedArrayType();
- *elementLength = 0;
- Js::DynamicObject* dynamicObject = Js::UnsafeVarTo<Js::DynamicObject>(object);
- Js::ArrayObject* objectArray = dynamicObject->GetObjectArray();
- if (!objectArray)
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- switch (Js::JavascriptOperators::GetTypeId(objectArray))
- {
- case Js::TypeIds_Int8Array:
- GetObjectArrayData<int8>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Uint8Array:
- GetObjectArrayData<uint8>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Uint8ClampedArray:
- GetObjectArrayData<uint8, true>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Int16Array:
- GetObjectArrayData<int16>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Uint16Array:
- GetObjectArrayData<uint16>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Int32Array:
- GetObjectArrayData<int32>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Uint32Array:
- GetObjectArrayData<uint32>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Float32Array:
- GetObjectArrayData<float>(objectArray, buffer, arrayType, elementLength);
- break;
- case Js::TypeIds_Float64Array:
- GetObjectArrayData<double>(objectArray, buffer, arrayType, elementLength);
- break;
- default:
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsLessThan(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTLessThan, object1, object2, false);
- VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
- VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
- PARAM_NOT_NULL(result);
- *result = Js::JavascriptOperators::Less((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
- return JsNoError;
- });
- }
- CHAKRA_API JsLessThanOrEqual(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTLessThan, object1, object2, true);
- VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
- VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
- PARAM_NOT_NULL(result);
- *result = Js::JavascriptOperators::LessEqual((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
- return JsNoError;
- });
- }
- CHAKRA_API JsEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTEquals, object1, object2, false);
- VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
- VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
- PARAM_NOT_NULL(result);
- *result = Js::JavascriptOperators::Equal((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
- return JsNoError;
- });
- }
- CHAKRA_API JsStrictEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTEquals, object1, object2, true);
- VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
- VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
- PARAM_NOT_NULL(result);
- *result = Js::JavascriptOperators::StrictEqual((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
- return JsNoError;
- });
- }
- CHAKRA_API JsHasExternalData(_In_ JsValueRef object, _Out_ bool *value)
- {
- VALIDATE_JSREF(object);
- PARAM_NOT_NULL(value);
- BEGIN_JSRT_NO_EXCEPTION
- {
- while (Js::VarIs<Js::JavascriptProxy>(object))
- {
- object = Js::UnsafeVarTo<Js::JavascriptProxy>(object);
- }
- *value = (Js::VarIs<JsrtExternalObject>(object)
- #ifdef _CHAKRACOREBUILD
- || Js::VarIs<Js::CustomExternalWrapperObject>(object)
- #endif
- );
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsGetExternalData(_In_ JsValueRef object, _Out_ void **data)
- {
- VALIDATE_JSREF(object);
- PARAM_NOT_NULL(data);
- BEGIN_JSRT_NO_EXCEPTION
- {
- while (Js::VarIs<Js::JavascriptProxy>(object))
- {
- object = Js::UnsafeVarTo<Js::JavascriptProxy>(object)->GetTarget();
- }
- if (Js::VarIs<JsrtExternalObject>(object))
- {
- *data = Js::UnsafeVarTo<JsrtExternalObject>(object)->GetSlotData();
- }
- #ifdef _CHAKRACOREBUILD
- else if (Js::VarIs<Js::CustomExternalWrapperObject>(object))
- {
- *data = Js::UnsafeVarTo<Js::CustomExternalWrapperObject>(object)->GetSlotData();
- }
- #endif
- else
- {
- *data = nullptr;
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsSetExternalData(_In_ JsValueRef object, _In_opt_ void *data)
- {
- VALIDATE_JSREF(object);
- BEGIN_JSRT_NO_EXCEPTION
- {
- while (Js::VarIs<Js::JavascriptProxy>(object))
- {
- object = Js::UnsafeVarTo<Js::JavascriptProxy>(object)->GetTarget();
- }
- if (Js::VarIs<JsrtExternalObject>(object))
- {
- Js::UnsafeVarTo<JsrtExternalObject>(object)->SetSlotData(data);
- }
- #ifdef _CHAKRACOREBUILD
- else if (Js::VarIs<Js::CustomExternalWrapperObject>(object))
- {
- Js::UnsafeVarTo<Js::CustomExternalWrapperObject>(object)->SetSlotData(data);
- }
- #endif
- else
- {
- RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
- }
- }
- END_JSRT_NO_EXCEPTION
- }
- CHAKRA_API JsCallFunction(_In_ JsValueRef function, _In_reads_(cargs) JsValueRef *args, _In_ ushort cargs, _Out_opt_ JsValueRef *result)
- {
- if(result != nullptr)
- {
- *result = nullptr;
- }
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- #if ENABLE_TTD
- TTD::TTDJsRTFunctionCallActionPopperRecorder callInfoPopper;
- if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
- {
- TTD::NSLogEvents::EventLogEntry* callEvent = scriptContext->GetThreadContext()->TTDLog->RecordJsRTCallFunction(_actionEntryPopper, scriptContext->GetThreadContext()->TTDRootNestingCount, function, cargs, args);
- callInfoPopper.InitializeForRecording(scriptContext, scriptContext->GetThreadContext()->TTDLog->GetCurrentWallTime(), callEvent);
- if(scriptContext->GetThreadContext()->TTDRootNestingCount == 0)
- {
- TTD::EventLog* elog = scriptContext->GetThreadContext()->TTDLog;
- elog->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
- TTD::ExecutionInfoManager* emanager = scriptContext->GetThreadContext()->TTDExecutionInfo;
- if(emanager != nullptr)
- {
- emanager->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
- }
- }
- }
- #endif
- VALIDATE_INCOMING_FUNCTION(function, scriptContext);
- if(cargs == 0 || args == nullptr)
- {
- return JsErrorInvalidArgument;
- }
- for(int index = 0; index < cargs; index++)
- {
- VALIDATE_INCOMING_REFERENCE(args[index], scriptContext);
- }
- Js::JavascriptFunction *jsFunction = Js::VarTo<Js::JavascriptFunction>(function);
- Js::CallInfo callInfo(cargs);
- Js::Arguments jsArgs(callInfo, reinterpret_cast<Js::Var *>(args));
- Js::Var varResult = jsFunction->CallRootFunction(jsArgs, scriptContext, true);
- if(result != nullptr)
- {
- *result = varResult;
- Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
- }
- #if ENABLE_TTD
- if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
- {
- _actionEntryPopper.SetResult(result);
- }
- #endif
- return JsNoError;
- });
- }
- CHAKRA_API JsConstructObject(_In_ JsValueRef function, _In_reads_(cargs) JsValueRef *args, _In_ ushort cargs, _Out_ JsValueRef *result)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTConstructCall, function, cargs, args);
- VALIDATE_INCOMING_FUNCTION(function, scriptContext);
- PARAM_NOT_NULL(result);
- *result = nullptr;
- if (cargs == 0 || args == nullptr)
- {
- return JsErrorInvalidArgument;
- }
- for (int index = 0; index < cargs; index++)
- {
- VALIDATE_INCOMING_REFERENCE(args[index], scriptContext);
- }
- Js::JavascriptFunction *jsFunction = Js::VarTo<Js::JavascriptFunction>(function);
- Js::CallInfo callInfo(Js::CallFlags::CallFlags_New, cargs);
- Js::Arguments jsArgs(callInfo, reinterpret_cast<Js::Var *>(args));
- //
- //TODO: we will want to look at this at some point -- either treat as "top-level" call or maybe constructors are fast so we can just jump back to previous "real" code
- //TTDAssert(!Js::VarIs<Js::ScriptFunction>(jsFunction) || execContext->GetThreadContext()->TTDRootNestingCount != 0, "This will cause user code to execute and we need to add support for that as a top-level call source!!!!");
- //
- BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
- {
- *result = Js::JavascriptFunction::CallAsConstructor(jsFunction, /* overridingNewTarget = */nullptr, jsArgs, scriptContext);
- }
- END_SAFE_REENTRANT_CALL
- Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
- return JsNoError;
- });
- }
- #ifndef _CHAKRACOREBUILD
- typedef struct JsNativeFunctionInfo
- {
- JsValueRef thisArg;
- JsValueRef newTargetArg;
- bool isConstructCall;
- }JsNativeFunctionInfo;
- typedef _Ret_maybenull_ JsValueRef(CHAKRA_CALLBACK * JsEnhancedNativeFunction)(_In_ JsValueRef callee, _In_ JsValueRef *arguments, _In_ unsigned short argumentCount, _In_ JsNativeFunctionInfo *info, _In_opt_ void *callbackState);
- #endif
- typedef struct JsNativeFunctionWrapperHolder
- {
- FieldNoBarrier(void *) callbackState;
- FieldNoBarrier(JsNativeFunction) nativeFunction;
- }JsNativeFunctionWrapperHolder;
- JsValueRef CALLBACK JsNativeFunctionWrapper(JsValueRef callee, JsValueRef *arguments, unsigned short argumentCount, JsNativeFunctionInfo *info, void *wrapperData)
- {
- JsNativeFunctionWrapperHolder *wrapperHolder = static_cast<JsNativeFunctionWrapperHolder*>(wrapperData);
- JsValueRef result = wrapperHolder->nativeFunction(callee, info->isConstructCall, arguments, argumentCount, wrapperHolder->callbackState);
- return result;
- }
- template <bool wrapNativeFunction, class T>
- JsErrorCode JsCreateEnhancedFunctionHelper(_In_ T nativeFunction, _In_opt_ JsValueRef metadata, _In_opt_ void *callbackState, _Out_ JsValueRef *function)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateFunction, metadata);
- PARAM_NOT_NULL(nativeFunction);
- PARAM_NOT_NULL(function);
- *function = nullptr;
- Js::StdCallJavascriptMethod method;
- if (wrapNativeFunction)
- {
- JsNativeFunctionWrapperHolder *wrapperHolder = RecyclerNewStruct(scriptContext->GetRecycler(), JsNativeFunctionWrapperHolder);
- wrapperHolder->callbackState = callbackState;
- wrapperHolder->nativeFunction = (JsNativeFunction)nativeFunction;
- callbackState = wrapperHolder;
- method = (Js::StdCallJavascriptMethod)JsNativeFunctionWrapper;
- }
- else
- {
- method = (Js::StdCallJavascriptMethod)nativeFunction;
- }
- if (metadata != JS_INVALID_REFERENCE)
- {
- VALIDATE_INCOMING_REFERENCE(metadata, scriptContext);
- metadata = Js::JavascriptConversion::ToString(metadata, scriptContext);
- }
- else
- {
- metadata = scriptContext->GetLibrary()->GetEmptyString();
- }
- Js::JavascriptExternalFunction *externalFunction = scriptContext->GetLibrary()->CreateStdCallExternalFunction(method, metadata, callbackState);
- *function = (JsValueRef)externalFunction;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, function);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateEnhancedFunction(_In_ JsEnhancedNativeFunction nativeFunction, _In_opt_ JsValueRef metadata, _In_opt_ void *callbackState, _Out_ JsValueRef *function)
- {
- return JsCreateEnhancedFunctionHelper<false>(nativeFunction, metadata, callbackState, function);
- }
- CHAKRA_API JsCreateFunction(_In_ JsNativeFunction nativeFunction, _In_opt_ void *callbackState, _Out_ JsValueRef *function)
- {
- return JsCreateEnhancedFunctionHelper<true>(nativeFunction, JS_INVALID_REFERENCE, callbackState, function);
- }
- CHAKRA_API JsCreateNamedFunction(_In_ JsValueRef name, _In_ JsNativeFunction nativeFunction, _In_opt_ void *callbackState, _Out_ JsValueRef *function)
- {
- return JsCreateEnhancedFunctionHelper<true>(nativeFunction, name, callbackState, function);
- }
- void SetErrorMessage(Js::ScriptContext *scriptContext, Js::JavascriptError *newError, JsValueRef message)
- {
- // ECMA262 #sec-error-message
- if (!Js::JavascriptOperators::IsUndefined(message))
- {
- Js::JavascriptString *messageStr = nullptr;
- if (Js::VarIs<Js::JavascriptString>(message))
- {
- messageStr = Js::VarTo<Js::JavascriptString>(message);
- }
- else
- {
- messageStr = Js::JavascriptConversion::ToString(message, scriptContext);
- }
- Js::PropertyDescriptor desc;
- desc.SetValue(messageStr);
- desc.SetWritable(true);
- desc.SetEnumerable(false);
- desc.SetConfigurable(true);
- Js::JavascriptOperators::SetPropertyDescriptor(newError, Js::PropertyIds::message, desc);
- }
- }
- CHAKRA_API JsCreateError(_In_ JsValueRef message, _Out_ JsValueRef *error)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateError, message);
- VALIDATE_INCOMING_REFERENCE(message, scriptContext);
- PARAM_NOT_NULL(error);
- *error = nullptr;
- Js::JavascriptError *newError = scriptContext->GetLibrary()->CreateError();
- SetErrorMessage(scriptContext, newError, message);
- *error = newError;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateRangeError(_In_ JsValueRef message, _Out_ JsValueRef *error)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateRangeError, message);
- VALIDATE_INCOMING_REFERENCE(message, scriptContext);
- PARAM_NOT_NULL(error);
- *error = nullptr;
- Js::JavascriptError *newError = scriptContext->GetLibrary()->CreateRangeError();
- SetErrorMessage(scriptContext, newError, message);
- *error = newError;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateReferenceError(_In_ JsValueRef message, _Out_ JsValueRef *error)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateReferenceError, message);
- VALIDATE_INCOMING_REFERENCE(message, scriptContext);
- PARAM_NOT_NULL(error);
- *error = nullptr;
- Js::JavascriptError *newError = scriptContext->GetLibrary()->CreateReferenceError();
- SetErrorMessage(scriptContext, newError, message);
- *error = newError;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateSyntaxError(_In_ JsValueRef message, _Out_ JsValueRef *error)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateSyntaxError, message);
- VALIDATE_INCOMING_REFERENCE(message, scriptContext);
- PARAM_NOT_NULL(error);
- *error = nullptr;
- Js::JavascriptError *newError = scriptContext->GetLibrary()->CreateSyntaxError();
- SetErrorMessage(scriptContext, newError, message);
- *error = newError;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateTypeError(_In_ JsValueRef message, _Out_ JsValueRef *error)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateTypeError, message);
- VALIDATE_INCOMING_REFERENCE(message, scriptContext);
- PARAM_NOT_NULL(error);
- *error = nullptr;
- Js::JavascriptError *newError = scriptContext->GetLibrary()->CreateTypeError();
- SetErrorMessage(scriptContext, newError, message);
- *error = newError;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
- return JsNoError;
- });
- }
- CHAKRA_API JsCreateURIError(_In_ JsValueRef message, _Out_ JsValueRef *error)
- {
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateURIError, message);
- VALIDATE_INCOMING_REFERENCE(message, scriptContext);
- PARAM_NOT_NULL(error);
- *error = nullptr;
- Js::JavascriptError *newError = scriptContext->GetLibrary()->CreateURIError();
- SetErrorMessage(scriptContext, newError, message);
- *error = newError;
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
- return JsNoError;
- });
- }
- CHAKRA_API JsHasException(_Out_ bool *hasException)
- {
- PARAM_NOT_NULL(hasException);
- *hasException = false;
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- if (currentContext == nullptr)
- {
- return JsErrorNoCurrentContext;
- }
- Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
- Assert(scriptContext != nullptr);
- Recycler *recycler = scriptContext->GetRecycler();
- ThreadContext *threadContext = scriptContext->GetThreadContext();
- #ifndef JSRT_VERIFY_RUNTIME_STATE
- if (recycler && recycler->IsInObjectBeforeCollectCallback())
- {
- return JsErrorInObjectBeforeCollectCallback;
- }
- #endif
- if (recycler && recycler->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (threadContext->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- if (threadContext->IsExecutionDisabled())
- {
- return JsErrorInDisabledState;
- }
- *hasException = scriptContext->HasRecordedException();
- return JsNoError;
- }
- CHAKRA_API JsGetAndClearException(_Out_ JsValueRef *exception)
- {
- PARAM_NOT_NULL(exception);
- *exception = nullptr;
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- if (currentContext == nullptr)
- {
- return JsErrorNoCurrentContext;
- }
- Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
- Assert(scriptContext != nullptr);
- if (scriptContext->GetRecycler() && scriptContext->GetRecycler()->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (scriptContext->GetThreadContext()->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- if (scriptContext->GetThreadContext()->IsExecutionDisabled())
- {
- return JsErrorInDisabledState;
- }
- HRESULT hr = S_OK;
- Js::JavascriptExceptionObject *recordedException = nullptr;
- BEGIN_TRANSLATE_OOM_TO_HRESULT
- if (scriptContext->HasRecordedException())
- {
- recordedException = scriptContext->GetAndClearRecordedException();
- }
- END_TRANSLATE_OOM_TO_HRESULT(hr)
- if (hr == E_OUTOFMEMORY)
- {
- recordedException = scriptContext->GetThreadContext()->GetRecordedException();
- }
- if (recordedException == nullptr)
- {
- return JsErrorInvalidArgument;
- }
- *exception = recordedException->GetThrownObject(nullptr);
- #if ENABLE_TTD
- if(hr != E_OUTOFMEMORY)
- {
- TTD::TTDJsRTActionResultAutoRecorder _actionEntryPopper;
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetAndClearException);
- PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, exception);
- }
- #endif
- if (*exception == nullptr)
- {
- return JsErrorInvalidArgument;
- }
- return JsNoError;
- }
- CHAKRA_API JsSetException(_In_ JsValueRef exception)
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- JsrtContext * context = JsrtContext::GetCurrent();
- JsrtRuntime * runtime = context->GetRuntime();
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetException, exception, runtime->DispatchExceptions());
- VALIDATE_INCOMING_REFERENCE(exception, scriptContext);
- Js::JavascriptExceptionObject *exceptionObject;
- exceptionObject = RecyclerNew(scriptContext->GetRecycler(), Js::JavascriptExceptionObject, exception, scriptContext, nullptr);
- scriptContext->RecordException(exceptionObject, runtime->DispatchExceptions());
- return JsNoError;
- });
- }
- CHAKRA_API JsGetRuntimeMemoryUsage(_In_ JsRuntimeHandle runtimeHandle, _Out_ size_t * memoryUsage)
- {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- PARAM_NOT_NULL(memoryUsage);
- *memoryUsage = 0;
- ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
- AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
- *memoryUsage = allocPolicyManager->GetUsage();
- return JsNoError;
- }
- CHAKRA_API JsSetRuntimeMemoryLimit(_In_ JsRuntimeHandle runtimeHandle, _In_ size_t memoryLimit)
- {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
- AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
- allocPolicyManager->SetLimit(memoryLimit);
- return JsNoError;
- }
- CHAKRA_API JsGetRuntimeMemoryLimit(_In_ JsRuntimeHandle runtimeHandle, _Out_ size_t * memoryLimit)
- {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- PARAM_NOT_NULL(memoryLimit);
- *memoryLimit = 0;
- ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
- AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
- *memoryLimit = allocPolicyManager->GetLimit();
- return JsNoError;
- }
- C_ASSERT(JsMemoryAllocate == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryAllocate);
- C_ASSERT(JsMemoryFree == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryFree);
- C_ASSERT(JsMemoryFailure == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryFailure);
- C_ASSERT(JsMemoryFailure == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryMax);
- CHAKRA_API JsSetRuntimeMemoryAllocationCallback(_In_ JsRuntimeHandle runtime, _In_opt_ void *callbackState, _In_ JsMemoryAllocationCallback allocationCallback)
- {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtime);
- ThreadContext* threadContext = JsrtRuntime::FromHandle(runtime)->GetThreadContext();
- AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
- allocPolicyManager->SetMemoryAllocationCallback(callbackState, (AllocationPolicyManager::PageAllocatorMemoryAllocationCallback)allocationCallback);
- return JsNoError;
- }
- CHAKRA_API JsSetRuntimeBeforeCollectCallback(_In_ JsRuntimeHandle runtime, _In_opt_ void *callbackState, _In_ JsBeforeCollectCallback beforeCollectCallback)
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtime);
- JsrtRuntime::FromHandle(runtime)->SetBeforeCollectCallback(beforeCollectCallback, callbackState);
- return JsNoError;
- });
- }
- CHAKRA_API JsDisableRuntimeExecution(_In_ JsRuntimeHandle runtimeHandle)
- {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
- if (!threadContext->TestThreadContextFlag(ThreadContextFlagCanDisableExecution))
- {
- return JsErrorCannotDisableExecution;
- }
- if (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (threadContext->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- threadContext->DisableExecution();
- return JsNoError;
- }
- CHAKRA_API JsEnableRuntimeExecution(_In_ JsRuntimeHandle runtimeHandle)
- {
- return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
- if (!threadContext->TestThreadContextFlag(ThreadContextFlagCanDisableExecution))
- {
- return JsNoError;
- }
- if (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (threadContext->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- ThreadContextScope scope(threadContext);
- if (!scope.IsValid())
- {
- return JsErrorWrongThread;
- }
- threadContext->EnableExecution();
- return JsNoError;
- });
- }
- CHAKRA_API JsIsRuntimeExecutionDisabled(_In_ JsRuntimeHandle runtimeHandle, _Out_ bool *isDisabled)
- {
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- PARAM_NOT_NULL(isDisabled);
- *isDisabled = false;
- ThreadContext* threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
- *isDisabled = threadContext->IsExecutionDisabled();
- return JsNoError;
- }
- inline JsErrorCode JsGetPropertyIdFromNameInternal(_In_z_ const WCHAR *name, size_t cPropertyNameLength, _Out_ JsPropertyIdRef *propertyId)
- {
- return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext * scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(name);
- PARAM_NOT_NULL(propertyId);
- *propertyId = nullptr;
- if (cPropertyNameLength <= INT_MAX)
- {
- scriptContext->GetOrAddPropertyRecord(name, static_cast<int>(cPropertyNameLength), (Js::PropertyRecord const **)propertyId);
- return JsNoError;
- }
- else
- {
- return JsErrorOutOfMemory;
- }
- });
- }
- CHAKRA_API JsGetPropertyIdFromName(_In_z_ const WCHAR *name, _Out_ JsPropertyIdRef *propertyId)
- {
- return JsGetPropertyIdFromNameInternal(name, wcslen(name), propertyId);
- }
- CHAKRA_API JsGetPropertyIdFromSymbol(_In_ JsValueRef symbol, _Out_ JsPropertyIdRef *propertyId)
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetPropertyIdFromSymbol, symbol);
- VALIDATE_INCOMING_REFERENCE(symbol, scriptContext);
- PARAM_NOT_NULL(propertyId);
- *propertyId = nullptr;
- if (!Js::VarIs<Js::JavascriptSymbol>(symbol))
- {
- return JsErrorPropertyNotSymbol;
- }
- *propertyId = (JsPropertyIdRef)Js::VarTo<Js::JavascriptSymbol>(symbol)->GetValue();
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- CHAKRA_API JsGetSymbolFromPropertyId(_In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *symbol)
- {
- return ContextAPINoScriptWrapper([&](Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- PARAM_NOT_NULL(symbol);
- *symbol = nullptr;
- Js::PropertyRecord const * propertyRecord = (Js::PropertyRecord const *)propertyId;
- if (!propertyRecord->IsSymbol())
- {
- return JsErrorPropertyNotSymbol;
- }
- *symbol = scriptContext->GetSymbol(propertyRecord);
- return JsNoError;
- });
- }
- #pragma prefast(suppress:6101, "Prefast doesn't see through the lambda")
- CHAKRA_API JsGetPropertyNameFromId(_In_ JsPropertyIdRef propertyId, _Outptr_result_z_ const WCHAR **name)
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- PARAM_NOT_NULL(name);
- *name = nullptr;
- Js::PropertyRecord const * propertyRecord = (Js::PropertyRecord const *)propertyId;
- if (propertyRecord->IsSymbol())
- {
- return JsErrorPropertyNotString;
- }
- *name = propertyRecord->GetBuffer();
- return JsNoError;
- });
- }
- CHAKRA_API JsGetPropertyIdType(_In_ JsPropertyIdRef propertyId, _Out_ JsPropertyIdType* propertyIdType)
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- VALIDATE_INCOMING_PROPERTYID(propertyId);
- Js::PropertyRecord const * propertyRecord = (Js::PropertyRecord const *)propertyId;
- if (propertyRecord->IsSymbol())
- {
- *propertyIdType = JsPropertyIdTypeSymbol;
- }
- else
- {
- *propertyIdType = JsPropertyIdTypeString;
- }
- return JsNoError;
- });
- }
- CHAKRA_API JsGetRuntime(_In_ JsContextRef context, _Out_ JsRuntimeHandle *runtime)
- {
- VALIDATE_JSREF(context);
- PARAM_NOT_NULL(runtime);
- *runtime = nullptr;
- if (!JsrtContext::Is(context))
- {
- return JsErrorInvalidArgument;
- }
- *runtime = static_cast<JsrtContext *>(context)->GetRuntime();
- return JsNoError;
- }
- CHAKRA_API JsIdle(_Out_opt_ unsigned int *nextIdleTick)
- {
- PARAM_NOT_NULL(nextIdleTick);
- return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext * scriptContext) -> JsErrorCode {
- *nextIdleTick = 0;
- if (scriptContext->GetThreadContext()->GetRecycler() && scriptContext->GetThreadContext()->GetRecycler()->IsHeapEnumInProgress())
- {
- return JsErrorHeapEnumInProgress;
- }
- else if (scriptContext->GetThreadContext()->IsInThreadServiceCallback())
- {
- return JsErrorInThreadServiceCallback;
- }
- JsrtContext * context = JsrtContext::GetCurrent();
- JsrtRuntime * runtime = context->GetRuntime();
- if (!runtime->UseIdle())
- {
- return JsErrorIdleNotEnabled;
- }
- unsigned int ticks = runtime->Idle();
- *nextIdleTick = ticks;
- return JsNoError;
- });
- }
- CHAKRA_API JsSetPromiseContinuationCallback(_In_opt_ JsPromiseContinuationCallback promiseContinuationCallback, _In_opt_ void *callbackState)
- {
- return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext * scriptContext) -> JsErrorCode {
- scriptContext->GetLibrary()->SetNativeHostPromiseContinuationFunction((Js::JavascriptLibrary::PromiseContinuationCallback)promiseContinuationCallback, callbackState);
- return JsNoError;
- },
- /*allowInObjectBeforeCollectCallback*/true);
- }
- JsErrorCode RunScriptCore(JsValueRef scriptSource, const byte *script, size_t cb,
- LoadScriptFlag loadScriptFlag, JsSourceContext sourceContext,
- const WCHAR *sourceUrl, bool parseOnly, JsParseScriptAttributes parseAttributes,
- bool isSourceModule, JsValueRef *result)
- {
- Js::JavascriptFunction *scriptFunction;
- CompileScriptException se;
- JsErrorCode errorCode = ContextAPINoScriptWrapper([&](Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PARAM_NOT_NULL(script);
- PARAM_NOT_NULL(sourceUrl);
- SourceContextInfo * sourceContextInfo = scriptContext->GetSourceContextInfo(sourceContext, nullptr);
- if (sourceContextInfo == nullptr)
- {
- sourceContextInfo = scriptContext->CreateSourceContextInfo(sourceContext, sourceUrl, wcslen(sourceUrl), nullptr);
- }
- const int chsize = (loadScriptFlag & LoadScriptFlag_Utf8Source) ?
- sizeof(utf8char_t) : sizeof(WCHAR);
- SRCINFO si = {
- /* sourceContextInfo */ sourceContextInfo,
- /* dlnHost */ 0,
- /* ulColumnHost */ 0,
- /* lnMinHost */ 0,
- /* ichMinHost */ 0,
- /* ichLimHost */ static_cast<ULONG>(cb / chsize), // OK to truncate since this is used to limit sourceText in debugDocument/compilation errors.
- /* ulCharOffset */ 0,
- /* mod */ kmodGlobal,
- /* grfsi */ 0
- };
- Js::Utf8SourceInfo* utf8SourceInfo = nullptr;
- if (result != nullptr)
- {
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Expression);
- }
- bool isLibraryCode = (parseAttributes & JsParseScriptAttributeLibraryCode) == JsParseScriptAttributeLibraryCode;
- bool isStrictMode = (parseAttributes & JsParseScriptAttributeStrictMode) == JsParseScriptAttributeStrictMode;
- if (isLibraryCode)
- {
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_LibraryCode);
- }
- if (isSourceModule)
- {
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Module);
- }
- if (isStrictMode)
- {
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_StrictMode);
- }
- #if ENABLE_TTD
- TTD::NSLogEvents::EventLogEntry* parseEvent = nullptr;
- if (PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
- {
- parseEvent = scriptContext->GetThreadContext()->TTDLog->RecordJsRTCodeParse(_actionEntryPopper,
- loadScriptFlag, ((loadScriptFlag & LoadScriptFlag_Utf8Source) == LoadScriptFlag_Utf8Source),
- script, (uint32)cb, sourceContext, sourceUrl);
- }
- #endif
- scriptFunction = scriptContext->LoadScript(script, cb,
- &si, &se, &utf8SourceInfo,
- Js::Constants::GlobalCode, loadScriptFlag, scriptSource);
- #if ENABLE_TTD
- if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
- {
- _actionEntryPopper.SetResult((Js::Var*)&scriptFunction);
- }
- //
- //TODO: We may (probably?) want to use the debugger source rundown functionality here instead
- //
- if (scriptFunction != nullptr && scriptContext->IsTTDRecordModeEnabled())
- {
- //Make sure we have the body and text information available
- Js::FunctionBody* globalBody = TTD::JsSupport::ForceAndGetFunctionBody(scriptFunction->GetParseableFunctionInfo());
- const TTD::NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo* tbfi = scriptContext->GetThreadContext()->TTDLog->AddScriptLoad(globalBody, kmodGlobal, sourceContext, script, (uint32)cb, loadScriptFlag);
- if(parseEvent != nullptr)
- {
- TTD::NSLogEvents::JsRTCodeParseAction_SetBodyCtrId(parseEvent, tbfi->TopLevelBase.TopLevelBodyCtr);
- }
- //walk global body to (1) add functions to pin set (2) build parent map
- BEGIN_JS_RUNTIME_CALL(scriptContext);
- {
- scriptContext->TTDContextInfo->ProcessFunctionBodyOnLoad(globalBody, nullptr);
- scriptContext->TTDContextInfo->RegisterLoadedScript(globalBody, tbfi->TopLevelBase.TopLevelBodyCtr);
- }
- END_JS_RUNTIME_CALL(scriptContext);
- }
- #endif
- JsrtContext * context = JsrtContext::GetCurrent();
- context->OnScriptLoad(scriptFunction, utf8SourceInfo, &se);
- return JsNoError;
- });
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- return ContextAPIWrapper<false>([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- if (scriptFunction == nullptr)
- {
- PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
- HandleScriptCompileError(scriptContext, &se, sourceUrl);
- return JsErrorScriptCompile;
- }
- if (parseOnly)
- {
- PARAM_NOT_NULL(result);
- *result = scriptFunction;
- }
- else
- {
- Js::Arguments args(0, nullptr);
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- Js::Var varThis;
- if (PHASE_FORCE1(Js::EvalCompilePhase))
- {
- varThis = Js::JavascriptOperators::OP_GetThis(scriptContext->GetLibrary()->GetUndefined(), kmodGlobal, scriptContext);
- args.Info.Flags = (Js::CallFlags)Js::CallFlags::CallFlags_Eval;
- args.Info.Count = 1;
- args.Values = &varThis;
- }
- #endif
- #if ENABLE_TTD
- TTD::TTDJsRTFunctionCallActionPopperRecorder callInfoPopper;
- if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
- {
- TTD::NSLogEvents::EventLogEntry* callEvent = scriptContext->GetThreadContext()->TTDLog->RecordJsRTCallFunction(_actionEntryPopper, scriptContext->GetThreadContext()->TTDRootNestingCount, scriptFunction, args.Info.Count, args.Values);
- callInfoPopper.InitializeForRecording(scriptContext, scriptContext->GetThreadContext()->TTDLog->GetCurrentWallTime(), callEvent);
- if(scriptContext->GetThreadContext()->TTDRootNestingCount == 0)
- {
- TTD::EventLog* elog = scriptContext->GetThreadContext()->TTDLog;
- elog->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
- TTD::ExecutionInfoManager* emanager = scriptContext->GetThreadContext()->TTDExecutionInfo;
- if(emanager != nullptr)
- {
- emanager->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
- }
- }
- }
- #endif
- Js::Var varResult = scriptFunction->CallRootFunction(args, scriptContext, true);
- if (result != nullptr)
- {
- *result = varResult;
- }
- #if ENABLE_TTD
- if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
- {
- _actionEntryPopper.SetResult(result);
- }
- #endif
- }
- return JsNoError;
- });
- }
- JsErrorCode RunScriptCore(const char *script, JsSourceContext sourceContext,
- const char *sourceUrl, bool parseOnly, JsParseScriptAttributes parseAttributes,
- bool isSourceModule, JsValueRef *result)
- {
- utf8::NarrowToWide url((LPCSTR)sourceUrl);
- if (!url)
- {
- return JsErrorOutOfMemory;
- }
- return RunScriptCore(nullptr, reinterpret_cast<const byte*>(script), strlen(script),
- LoadScriptFlag_Utf8Source, sourceContext, url, parseOnly, parseAttributes,
- isSourceModule, result);
- }
- JsErrorCode RunScriptCore(const WCHAR *script, JsSourceContext sourceContext,
- const WCHAR *sourceUrl, bool parseOnly, JsParseScriptAttributes parseAttributes,
- bool isSourceModule, JsValueRef *result)
- {
- return RunScriptCore(nullptr, reinterpret_cast<const byte*>(script),
- wcslen(script) * sizeof(WCHAR),
- LoadScriptFlag_None, sourceContext, sourceUrl, parseOnly,
- parseAttributes, isSourceModule, result);
- }
- #ifdef _WIN32
- CHAKRA_API JsParseScript(_In_z_ const WCHAR * script, _In_ JsSourceContext sourceContext,
- _In_z_ const WCHAR *sourceUrl, _Out_ JsValueRef * result)
- {
- return RunScriptCore(script, sourceContext, sourceUrl, true,
- JsParseScriptAttributeNone, false /*isModule*/, result);
- }
- CHAKRA_API JsParseScriptWithAttributes(
- _In_z_ const WCHAR *script,
- _In_ JsSourceContext sourceContext,
- _In_z_ const WCHAR *sourceUrl,
- _In_ JsParseScriptAttributes parseAttributes,
- _Out_ JsValueRef *result)
- {
- return RunScriptCore(script, sourceContext, sourceUrl, true,
- parseAttributes, false /*isModule*/, result);
- }
- CHAKRA_API JsRunScript(_In_z_ const WCHAR * script, _In_ JsSourceContext sourceContext,
- _In_z_ const WCHAR *sourceUrl, _Out_ JsValueRef * result)
- {
- return RunScriptCore(script, sourceContext, sourceUrl, false,
- JsParseScriptAttributeNone, false /*isModule*/, result);
- }
- CHAKRA_API JsExperimentalApiRunModule(_In_z_ const WCHAR * script,
- _In_ JsSourceContext sourceContext, _In_z_ const WCHAR *sourceUrl,
- _Out_ JsValueRef * result)
- {
- return RunScriptCore(script, sourceContext, sourceUrl, false,
- JsParseScriptAttributeNone, true, result);
- }
- #endif
- JsErrorCode GetScriptBufferDetails(
- _In_ JsValueRef scriptVal,
- _In_ JsParseScriptAttributes parseAttributes,
- _Out_ LoadScriptFlag* scriptFlag,
- _Out_ size_t* cb,
- _Out_ const byte** script)
- {
- PARAM_NOT_NULL(scriptFlag);
- PARAM_NOT_NULL(cb);
- PARAM_NOT_NULL(script);
- *scriptFlag = LoadScriptFlag_None;
- *cb = 0;
- *script = nullptr;
- const bool isExternalArray = Js::VarIs<Js::ArrayBuffer>(scriptVal);
- const bool isString = !isExternalArray && Js::VarIs<Js::JavascriptString>(scriptVal);
- if (!isExternalArray && !isString)
- {
- return JsErrorInvalidArgument;
- }
- const bool isUtf8 = !isString && !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded);
- *script = isExternalArray ?
- ((Js::ExternalArrayBuffer*)(scriptVal))->GetBuffer() :
- (const byte*)((Js::JavascriptString*)(scriptVal))->GetSz();
- *cb = isExternalArray ?
- ((Js::ExternalArrayBuffer*)(scriptVal))->GetByteLength() :
- ((Js::JavascriptString*)(scriptVal))->GetSizeInBytes();
- if (isExternalArray && isUtf8)
- {
- *scriptFlag = (LoadScriptFlag)(LoadScriptFlag_ExternalArrayBuffer | LoadScriptFlag_Utf8Source);
- }
- else if (isUtf8)
- {
- *scriptFlag = (LoadScriptFlag)(LoadScriptFlag_Utf8Source);
- }
- else
- {
- *scriptFlag = LoadScriptFlag_None;
- }
- return JsNoError;
- }
- JsErrorCode JsSerializeScriptCore(const byte *script, size_t cb,
- LoadScriptFlag loadScriptFlag, BYTE *functionTable, int functionTableSize,
- unsigned char *buffer, unsigned int *bufferSize, JsValueRef scriptSource)
- {
- Js::JavascriptFunction *function;
- CompileScriptException se;
- JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(script);
- PARAM_NOT_NULL(bufferSize);
- if (*bufferSize > 0)
- {
- PARAM_NOT_NULL(buffer);
- ZeroMemory(buffer, *bufferSize);
- }
- if (scriptContext->IsScriptContextInDebugMode())
- {
- return JsErrorCannotSerializeDebugScript;
- }
- SourceContextInfo * sourceContextInfo = scriptContext->GetSourceContextInfo(JS_SOURCE_CONTEXT_NONE, nullptr);
- Assert(sourceContextInfo != nullptr);
- sourceContextInfo->nextLocalFunctionId = 0;
- const int chsize = (loadScriptFlag & LoadScriptFlag_Utf8Source) ? sizeof(utf8char_t) : sizeof(WCHAR);
- SRCINFO si = {
- /* sourceContextInfo */ sourceContextInfo,
- /* dlnHost */ 0,
- /* ulColumnHost */ 0,
- /* lnMinHost */ 0,
- /* ichMinHost */ 0,
- /* ichLimHost */ static_cast<ULONG>(cb / chsize), // OK to truncate since this is used to limit sourceText in debugDocument/compilation errors.
- /* ulCharOffset */ 0,
- /* mod */ kmodGlobal,
- /* grfsi */ 0
- };
- bool isSerializeByteCodeForLibrary = false;
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- isSerializeByteCodeForLibrary = JsrtContext::GetCurrent()->GetRuntime()->IsSerializeByteCodeForLibrary();
- #endif
- Js::Utf8SourceInfo* sourceInfo = nullptr;
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_disableDeferredParse);
- if (isSerializeByteCodeForLibrary)
- {
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_isByteCodeBufferForLibrary);
- }
- else
- {
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Expression);
- }
- function = scriptContext->LoadScript(script, cb, &si, &se, &sourceInfo,
- Js::Constants::GlobalCode, loadScriptFlag, scriptSource);
- return JsNoError;
- });
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode {
- if (function == nullptr)
- {
- HandleScriptCompileError(scriptContext, &se);
- return JsErrorScriptCompile;
- }
- // Could we have a deserialized function in this case?
- // If we are going to serialize it, a check isn't to expensive
- if (CONFIG_FLAG(ForceSerialized) && function->GetFunctionProxy() != nullptr) {
- function->GetFunctionProxy()->EnsureDeserialized();
- }
- Js::FunctionBody *functionBody = function->GetFunctionBody();
- const Js::Utf8SourceInfo *sourceInfo = functionBody->GetUtf8SourceInfo();
- size_t cSourceCodeLength = sourceInfo->GetCbLength(_u("JsSerializeScript"));
- // truncation of code length can lead to accessing random memory. Reject the call.
- if (cSourceCodeLength > DWORD_MAX)
- {
- return JsErrorOutOfMemory;
- }
- LPCUTF8 utf8Code = sourceInfo->GetSource(_u("JsSerializeScript"));
- DWORD dwFlags = 0;
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- dwFlags = JsrtContext::GetCurrent()->GetRuntime()->IsSerializeByteCodeForLibrary() ? GENERATE_BYTE_CODE_BUFFER_LIBRARY : 0;
- #endif
- BEGIN_TEMP_ALLOCATOR(tempAllocator, scriptContext, _u("ByteCodeSerializer"));
- // We cast buffer size to DWORD* because on Windows, DWORD = unsigned long = unsigned int
- // On 64-bit clang on linux, this is not true, unsigned long is larger than unsigned int
- // However, the PAL defines DWORD for us on linux as unsigned int so the cast is safe here.
- HRESULT hr = Js::ByteCodeSerializer::SerializeToBuffer(scriptContext,
- tempAllocator, static_cast<DWORD>(cSourceCodeLength), utf8Code,
- functionBody, functionBody->GetHostSrcInfo(), &buffer,
- (DWORD*) bufferSize, dwFlags);
- END_TEMP_ALLOCATOR(tempAllocator, scriptContext);
- if (SUCCEEDED(hr))
- {
- return JsNoError;
- }
- else
- {
- return JsErrorScriptCompile;
- }
- });
- }
- CHAKRA_API JsSerializeScript(_In_z_ const WCHAR *script, _Out_writes_to_opt_(*bufferSize,
- *bufferSize) unsigned char *buffer,
- _Inout_ unsigned int *bufferSize)
- {
- return JsSerializeScriptCore((const byte*)script, wcslen(script) * sizeof(WCHAR),
- LoadScriptFlag_None, nullptr, 0, buffer, bufferSize, nullptr);
- }
- template <typename TLoadCallback, typename TUnloadCallback>
- JsErrorCode RunSerializedScriptCore(
- TLoadCallback scriptLoadCallback, TUnloadCallback scriptUnloadCallback,
- JsSourceContext scriptLoadSourceContext, // only used by scriptLoadCallback
- unsigned char *buffer, Js::ArrayBuffer* bufferVal,
- JsSourceContext sourceContext, const WCHAR *sourceUrl,
- DWORD bgParseCookie,
- bool parseOnly, bool useParserStateCache, JsValueRef *result,
- uint sourceIndex)
- {
- Js::JavascriptFunction *function;
- JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
- if (result != nullptr)
- {
- *result = nullptr;
- }
- if (bgParseCookie == 0)
- {
- PARAM_NOT_NULL(buffer);
- }
- else
- {
- Assert(buffer == nullptr);
- }
- PARAM_NOT_NULL(sourceUrl);
- Js::ISourceHolder *sourceHolder = nullptr;
- SRCINFO *hsi = nullptr;
- PARAM_NOT_NULL(scriptLoadCallback);
- PARAM_NOT_NULL(scriptUnloadCallback);
- typedef Js::JsrtSourceHolder<TLoadCallback, TUnloadCallback> TSourceHolder;
- if (!useParserStateCache || bgParseCookie != 0)
- {
- sourceIndex = Js::Constants::InvalidSourceIndex;
- sourceHolder = RecyclerNewFinalized(scriptContext->GetRecycler(), TSourceHolder,
- scriptLoadCallback, scriptUnloadCallback, scriptLoadSourceContext, bufferVal);
- SourceContextInfo *sourceContextInfo = scriptContext->GetSourceContextInfo(sourceContext, nullptr);
- if (sourceContextInfo == nullptr)
- {
- sourceContextInfo = scriptContext->CreateSourceContextInfo(sourceContext, sourceUrl,
- wcslen(sourceUrl), nullptr);
- }
- SRCINFO si = {
- /* sourceContextInfo */ sourceContextInfo,
- /* dlnHost */ 0,
- /* ulColumnHost */ 0,
- /* lnMinHost */ 0,
- /* ichMinHost */ 0,
- /* ichLimHost */ 0, // xplat-todo: need to compute this?
- /* ulCharOffset */ 0,
- /* mod */ kmodGlobal,
- /* grfsi */ 0
- };
- hsi = scriptContext->AddHostSrcInfo(&si);
- }
- else
- {
- Assert(sourceIndex != Js::Constants::InvalidSourceIndex);
- }
- HRESULT hr;
- Field(Js::FunctionBody*) functionBody = nullptr;
- if (bgParseCookie == 0)
- {
- uint32 flags = 0;
- if (CONFIG_FLAG(CreateFunctionProxy) && !scriptContext->IsProfiling())
- {
- flags = fscrAllowFunctionProxy;
- }
- if (useParserStateCache && !CONFIG_FLAG(ForceSerialized))
- {
- flags |= fscrCreateParserState;
- }
- hr = Js::ByteCodeSerializer::DeserializeFromBuffer(scriptContext, flags, sourceHolder,
- hsi, buffer, nullptr, &functionBody, sourceIndex);
- }
- else
- {
- size_t srcLength = 0;
- Js::FunctionBody* functionBodyLocal = nullptr;
- hr = BGParseManager::GetBGParseManager()->GetParseResults(
- scriptContext,
- bgParseCookie,
- nullptr, // pszSrc
- hsi,
- &functionBodyLocal,
- nullptr, // pse
- srcLength,
- nullptr, // utf8sourceinfo
- sourceIndex
- );
-
- if (hr == S_OK)
- {
- functionBody = functionBodyLocal;
- }
- }
- if (FAILED(hr))
- {
- return JsErrorBadSerializedScript;
- }
- function = scriptContext->GetLibrary()->CreateScriptFunction(functionBody);
- JsrtContext * context = JsrtContext::GetCurrent();
- context->OnScriptLoad(function, functionBody->GetUtf8SourceInfo(), nullptr);
- return JsNoError;
- });
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode {
- if (parseOnly)
- {
- PARAM_NOT_NULL(result);
- *result = function;
- }
- else
- {
- Js::Var varResult = function->CallRootFunction(Js::Arguments(0, nullptr), scriptContext, true);
- if (result != nullptr)
- {
- *result = varResult;
- }
- }
- return JsNoError;
- });
- }
- static void CHAKRA_CALLBACK DummyScriptUnloadCallback(_In_ JsSourceContext sourceContext)
- {
- // Do nothing
- }
- #ifdef _WIN32
- static bool CHAKRA_CALLBACK DummyScriptLoadSourceCallback(_In_ JsSourceContext sourceContext, _Outptr_result_z_ const WCHAR** scriptBuffer)
- {
- // sourceContext is actually the script source pointer
- *scriptBuffer = reinterpret_cast<const WCHAR*>(sourceContext);
- return true;
- }
- CHAKRA_API JsParseSerializedScript(_In_z_ const WCHAR * script, _In_ unsigned char *buffer,
- _In_ JsSourceContext sourceContext,
- _In_z_ const WCHAR *sourceUrl,
- _Out_ JsValueRef * result)
- {
- return RunSerializedScriptCore(
- DummyScriptLoadSourceCallback, DummyScriptUnloadCallback,
- reinterpret_cast<JsSourceContext>(script), // use script source pointer as scriptLoadSourceContext
- buffer, nullptr, sourceContext, sourceUrl, 0, true, false, result, Js::Constants::InvalidSourceIndex);
- }
- CHAKRA_API JsRunSerializedScript(_In_z_ const WCHAR * script, _In_ unsigned char *buffer,
- _In_ JsSourceContext sourceContext,
- _In_z_ const WCHAR *sourceUrl,
- _Out_ JsValueRef * result)
- {
- return RunSerializedScriptCore(
- DummyScriptLoadSourceCallback, DummyScriptUnloadCallback,
- reinterpret_cast<JsSourceContext>(script), // use script source pointer as scriptLoadSourceContext
- buffer, nullptr, sourceContext, sourceUrl, 0, false, false, result, Js::Constants::InvalidSourceIndex);
- }
- CHAKRA_API JsParseSerializedScriptWithCallback(_In_ JsSerializedScriptLoadSourceCallback scriptLoadCallback,
- _In_ JsSerializedScriptUnloadCallback scriptUnloadCallback,
- _In_ unsigned char *buffer, _In_ JsSourceContext sourceContext,
- _In_z_ const WCHAR *sourceUrl, _Out_ JsValueRef * result)
- {
- return RunSerializedScriptCore(
- scriptLoadCallback, scriptUnloadCallback,
- sourceContext, // use the same user provided sourceContext as scriptLoadSourceContext
- buffer, nullptr, sourceContext, sourceUrl, 0, true, false, result, Js::Constants::InvalidSourceIndex);
- }
- CHAKRA_API JsRunSerializedScriptWithCallback(_In_ JsSerializedScriptLoadSourceCallback scriptLoadCallback,
- _In_ JsSerializedScriptUnloadCallback scriptUnloadCallback,
- _In_ unsigned char *buffer, _In_ JsSourceContext sourceContext,
- _In_z_ const WCHAR *sourceUrl, _Out_opt_ JsValueRef * result)
- {
- return RunSerializedScriptCore(
- scriptLoadCallback, scriptUnloadCallback,
- sourceContext, // use the same user provided sourceContext as scriptLoadSourceContext
- buffer, nullptr, sourceContext, sourceUrl, 0, false, false, result, Js::Constants::InvalidSourceIndex);
- }
- #endif // _WIN32
- /////////////////////
- CHAKRA_API JsTTDCreateRecordRuntime(_In_ JsRuntimeAttributes attributes, _In_ bool enableDebugging, _In_ size_t snapInterval, _In_ size_t snapHistoryLength,
- _In_ TTDOpenResourceStreamCallback openResourceStream, _In_ JsTTDWriteBytesToStreamCallback writeBytesToStream, _In_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream,
- _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- if(snapInterval > UINT32_MAX || snapHistoryLength > UINT32_MAX)
- {
- return JsErrorInvalidArgument;
- }
- return CreateRuntimeCore(attributes, nullptr, 0, true, false, enableDebugging, (uint32)snapInterval, (uint32)snapHistoryLength,
- openResourceStream, nullptr, writeBytesToStream, flushAndCloseStream,
- threadService, runtime);
- #endif
- }
- CHAKRA_API JsTTDCreateReplayRuntime(_In_ JsRuntimeAttributes attributes, _In_reads_(infoUriCount) const char* infoUri, _In_ size_t infoUriCount, _In_ bool enableDebugging,
- _In_ TTDOpenResourceStreamCallback openResourceStream, _In_ JsTTDReadBytesFromStreamCallback readBytesFromStream, _In_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream,
- _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- return CreateRuntimeCore(attributes, infoUri, infoUriCount, false, true, enableDebugging, UINT_MAX, UINT_MAX,
- openResourceStream, readBytesFromStream, nullptr, flushAndCloseStream,
- threadService, runtime);
- #endif
- }
- CHAKRA_API JsTTDCreateContext(_In_ JsRuntimeHandle runtimeHandle, _In_ bool useRuntimeTTDMode, _Out_ JsContextRef *newContext)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- PARAM_NOT_NULL(newContext);
- VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
- JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext * threadContext = runtime->GetThreadContext();
- TTDAssert(threadContext->IsRuntimeInTTDMode(), "Need to create in TTD Mode.");
- bool inRecord = false;
- bool activelyRecording = false;
- bool inReplay = false;
- TTDRecorder dummyActionEntryPopper;
- if(useRuntimeTTDMode)
- {
- threadContext->TTDLog->GetModesForExplicitContextCreate(inRecord, activelyRecording, inReplay);
- }
- return CreateContextCore(runtimeHandle, dummyActionEntryPopper, inRecord, activelyRecording, inReplay, newContext);
- });
- #endif
- }
- CHAKRA_API JsTTDNotifyContextDestroy(_In_ JsContextRef context)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
- if(threadContext && threadContext->IsRuntimeInTTDMode())
- {
- Js::ScriptContext* ctx = static_cast<JsrtContext*>(context)->GetScriptContext();
- threadContext->TTDContext->NotifyCtxDestroyInRecord(ctx);
- }
- return JsNoError;
- #endif
- }
- CHAKRA_API JsTTDStart()
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
- TTDAssert(cCheck == JsNoError, "Must have valid context when starting TTD.");
- Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
- TTDAssert(scriptContext->IsTTDRecordOrReplayModeEnabled(), "Need to create in TTD Record Mode.");
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- if(scriptContext->IsTTDRecordModeEnabled())
- {
- scriptContext->GetThreadContext()->TTDLog->DoSnapshotExtract();
- }
- //Want to verify that we are at top-level of dispatch
- scriptContext->GetThreadContext()->TTDLog->PushMode(TTD::TTDMode::CurrentlyEnabled);
- return JsNoError;
- });
- #endif
- }
- CHAKRA_API JsTTDStop()
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
- TTDAssert(cCheck == JsNoError, "Must have valid context when starting TTD.");
- Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
- TTDAssert(scriptContext->IsTTDRecordOrReplayModeEnabled(), "Need to create in TTD mode.");
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- scriptContext->GetThreadContext()->TTDLog->PopMode(TTD::TTDMode::CurrentlyEnabled);
- if(scriptContext->IsTTDRecordModeEnabled())
- {
- scriptContext->GetThreadContext()->TTDLog->UnloadAllLogData();
- }
- return JsNoError;
- });
- #endif
- }
- CHAKRA_API JsTTDPauseTimeTravelBeforeRuntimeOperation()
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
- TTDAssert(cCheck == JsNoError, "Must have valid context when changing debugger mode.");
- Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
- ThreadContext* threadContext = scriptContext->GetThreadContext();
- if(threadContext->IsRuntimeInTTDMode())
- {
- threadContext->TTDLog->PushMode(TTD::TTDMode::ExcludedExecutionDebuggerAction);
- }
- return JsNoError;
- #endif
- }
- CHAKRA_API JsTTDReStartTimeTravelAfterRuntimeOperation()
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
- TTDAssert(cCheck == JsNoError, "Must have valid context when changing debugger mode.");
- Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
- ThreadContext* threadContext = scriptContext->GetThreadContext();
- if(threadContext->IsRuntimeInTTDMode())
- {
- threadContext->TTDLog->PopMode(TTD::TTDMode::ExcludedExecutionDebuggerAction);
- }
- return JsNoError;
- #endif
- }
- CHAKRA_API JsTTDNotifyYield()
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
- if(cCheck != JsNoError)
- {
- return JsNoError; //we are ok just aren't going to do any TTD related work
- }
- Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- if(scriptContext->IsTTDRecordModeEnabled())
- {
- scriptContext->GetThreadContext()->TTDLog->RecordJsRTEventLoopYieldPoint();
- }
- return JsNoError;
- });
- #endif
- }
- CHAKRA_API JsTTDNotifyLongLivedReferenceAdd(_In_ JsValueRef value)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- return GlobalAPIWrapper([&](TTDRecorder& _actionEntryPopper) -> JsErrorCode
- {
- ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
- if(threadContext == nullptr)
- {
- return JsErrorNoCurrentContext;
- }
- if (Js::VarIs<Js::RecyclableObject>(value))
- {
- Js::RecyclableObject* obj = Js::VarTo<Js::RecyclableObject>(value);
- if (obj->GetScriptContext()->IsTTDRecordModeEnabled())
- {
- if (obj->GetScriptContext()->ShouldPerformRecordAction())
- {
- threadContext->TTDLog->RecordJsRTAddWeakRootRef(_actionEntryPopper, (Js::Var)value);
- }
- threadContext->TTDContext->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(obj), obj);
- }
- }
- return JsNoError;
- });
- #endif
- }
- CHAKRA_API JsTTDHostExit(_In_ int statusCode)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHostExitProcess, statusCode);
- return JsNoError;
- });
- #endif
- }
- CHAKRA_API JsTTDRawBufferCopySyncIndirect(_In_ JsValueRef dst, _In_ size_t dstIndex, _In_ JsValueRef src, _In_ size_t srcIndex, _In_ size_t count)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- if(dstIndex > UINT32_MAX || srcIndex > UINT32_MAX || count > UINT32_MAX)
- {
- return JsErrorInvalidArgument;
- }
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferCopySync, dst, (uint32)dstIndex, src, (uint32)srcIndex, (uint32)count);
- return JsNoError;
- });
- #endif
- }
- CHAKRA_API JsTTDRawBufferModifySyncIndirect(_In_ JsValueRef buffer, _In_ size_t index, _In_ size_t count)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- if(index > UINT32_MAX || count > UINT32_MAX)
- {
- return JsErrorInvalidArgument;
- }
- return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferModifySync, buffer, (uint32)index, (uint32)count);
- return JsNoError;
- });
- #endif
- }
- CHAKRA_API JsTTDRawBufferAsyncModificationRegister(_In_ JsValueRef instance, _In_ byte* initialModPos)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsValueRef addRefObj = nullptr;
- JsErrorCode addRefResult = ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- if (scriptContext->IsTTDRecordModeEnabled())
- {
- TTDAssert(Js::VarIs<Js::ArrayBuffer>(instance), "Not array buffer object!!!");
- Js::ArrayBuffer* dstBuff = Js::VarTo<Js::ArrayBuffer>(instance);
- addRefObj = dstBuff;
- TTDAssert(dstBuff->GetBuffer() <= initialModPos && initialModPos < dstBuff->GetBuffer() + dstBuff->GetByteLength(), "Not array buffer object!!!");
- TTDAssert(initialModPos - dstBuff->GetBuffer() < UINT32_MAX, "This is really big!!!");
- ptrdiff_t index = initialModPos - Js::VarTo<Js::ArrayBuffer>(instance)->GetBuffer();
- scriptContext->TTDContextInfo->AddToAsyncPendingList(dstBuff, (uint32)index);
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferAsyncModificationRegister, instance, (uint32)index);
- }
- return JsNoError;
- });
- if(addRefResult != JsNoError)
- {
- return addRefResult;
- }
- //We need to root add ref so we can find this during replay!!!
- if(addRefObj == nullptr)
- {
- return JsNoError;
- }
- else
- {
- return JsAddRef(addRefObj, nullptr);
- }
- #endif
- }
- CHAKRA_API JsTTDRawBufferAsyncModifyComplete(_In_ byte* finalModPos)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsValueRef releaseObj = nullptr;
- JsErrorCode releaseStatus = ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
- if (scriptContext->IsTTDRecordModeEnabled())
- {
- TTD::TTDPendingAsyncBufferModification pendingAsyncInfo = { 0 };
- scriptContext->TTDContextInfo->GetFromAsyncPendingList(&pendingAsyncInfo, finalModPos);
- Js::ArrayBuffer* dstBuff = Js::VarTo<Js::ArrayBuffer>(pendingAsyncInfo.ArrayBufferVar);
- releaseObj = dstBuff;
- PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferAsyncModifyComplete, pendingAsyncInfo, finalModPos);
- }
- return JsNoError;
- });
- if(releaseStatus != JsNoError)
- {
- return releaseStatus;
- }
- //We need to root release ref so we can free this in replay if needed!!!
- if(releaseObj == nullptr)
- {
- return JsNoError;
- }
- else
- {
- return JsRelease(releaseObj, nullptr);
- }
- #endif
- }
- CHAKRA_API JsTTDCheckAndAssertIfTTDRunning(_In_ const char* msg)
- {
- #if ENABLE_TTD
- JsrtContext* context = JsrtContext::GetCurrent();
- TTDAssert(context == nullptr || !context->GetScriptContext()->ShouldPerformRecordAction(), msg);
- #endif
- return JsNoError;
- }
- CHAKRA_API JsTTDGetSnapTimeTopLevelEventMove(_In_ JsRuntimeHandle runtimeHandle,
- _In_ JsTTDMoveMode moveMode, _In_opt_ uint32_t kthEvent,
- _Inout_ int64_t* targetEventTime, _Out_ int64_t* targetStartSnapTime,
- _Out_opt_ int64_t* targetEndSnapTime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext* threadContext = runtime->GetThreadContext();
- *targetStartSnapTime = -1;
- if(targetEndSnapTime != nullptr)
- {
- *targetEndSnapTime = -1;
- }
- TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
- //If we requested a move to a specific event then extract the event count and try to find it
- if((moveMode & JsTTDMoveMode::JsTTDMoveFirstEvent) == JsTTDMoveMode::JsTTDMoveFirstEvent)
- {
- *targetEventTime = threadContext->TTDLog->GetFirstEventTimeInLog();
- if(*targetEventTime == -1)
- {
- return JsErrorCategoryUsage;
- }
- }
- else if((moveMode & JsTTDMoveMode::JsTTDMoveLastEvent) == JsTTDMoveMode::JsTTDMoveLastEvent)
- {
- *targetEventTime = threadContext->TTDLog->GetLastEventTimeInLog();
- if(*targetEventTime == -1)
- {
- return JsErrorCategoryUsage;
- }
- }
- else if((moveMode & JsTTDMoveMode::JsTTDMoveKthEvent) == JsTTDMoveMode::JsTTDMoveKthEvent)
- {
- *targetEventTime = threadContext->TTDLog->GetKthEventTimeInLog(kthEvent);
- if(*targetEventTime == -1)
- {
- return JsErrorCategoryUsage;
- }
- }
- else
- {
- ;
- }
- #ifdef __APPLE__
- //TODO: Explicit cast of ptr since compiler gets confused -- resolve in PAL later
- static_assert(sizeof(int64_t) == sizeof(int64), "int64_t and int64 size mis-match");
- *targetStartSnapTime = threadContext->TTDLog->FindSnapTimeForEventTime(*targetEventTime, (int64*)targetEndSnapTime);
- #else
- *targetStartSnapTime = threadContext->TTDLog->FindSnapTimeForEventTime(*targetEventTime, targetEndSnapTime);
- #endif
- return JsNoError;
- #endif
- }
- CHAKRA_API JsTTDGetSnapShotBoundInterval(_In_ JsRuntimeHandle runtimeHandle, _In_ int64_t targetEventTime, _Out_ int64_t* startSnapTime, _Out_ int64_t* endSnapTime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext* threadContext = runtime->GetThreadContext();
- TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
- #ifdef __APPLE__
- //TODO: Explicit cast of ptr since compiler gets confused -- resolve in PAL later
- static_assert(sizeof(int64_t) == sizeof(int64), "int64_t and int64 size mis-match");
- threadContext->TTDLog->GetSnapShotBoundInterval(targetEventTime, (int64*)startSnapTime, (int64*)endSnapTime);
- #else
- threadContext->TTDLog->GetSnapShotBoundInterval(targetEventTime, startSnapTime, endSnapTime);
- #endif
- return JsNoError;
- #endif
- }
- CHAKRA_API JsTTDGetPreviousSnapshotInterval(_In_ JsRuntimeHandle runtimeHandle, _In_ int64_t currentSnapStartTime, _Out_ int64_t* previousSnapTime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext * threadContext = runtime->GetThreadContext();
- TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
- *previousSnapTime = threadContext->TTDLog->GetPreviousSnapshotInterval(currentSnapStartTime);
- return JsNoError;
- #endif
- }
- #if ENABLE_TTD
- //Helper method for resetting breakpoint info around snapshot inflate
- JsErrorCode TTDHandleBreakpointInfoAndInflate(int64_t snapTime, JsrtRuntime* runtime, ThreadContext* threadContext)
- {
- return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- if(threadContext->TTDLog->IsDebugModeFlagSet())
- {
- threadContext->TTDExecutionInfo->LoadPreservedBPInfo(threadContext);
- }
- threadContext->TTDLog->DoSnapshotInflate(snapTime);
- threadContext->TTDLog->ResetCallStackForTopLevelCall(-1);
- if(threadContext->TTDExecutionInfo != nullptr)
- {
- threadContext->TTDExecutionInfo->ResetCallStackForTopLevelCall(-1);
- }
- return JsNoError;
- });
- }
- #endif
- CHAKRA_API JsTTDPreExecuteSnapShotInterval(_In_ JsRuntimeHandle runtimeHandle, _In_ int64_t startSnapTime, _In_ int64_t endSnapTime, _In_ JsTTDMoveMode moveMode, _Out_ int64_t* newTargetEventTime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- *newTargetEventTime = -1;
- JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext* threadContext = runtime->GetThreadContext();
- TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
- TTD::EventLog* elog = threadContext->TTDLog;
- TTD::ExecutionInfoManager* emanager = threadContext->TTDExecutionInfo;
- JsErrorCode res = JsNoError;
- JsErrorCode inflateStatus = TTDHandleBreakpointInfoAndInflate(startSnapTime, runtime, threadContext);
- if(inflateStatus != JsNoError)
- {
- return inflateStatus;
- }
- //If we are in the "active" segment set the continue breakpoint
- if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment)
- {
- GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- emanager->SetBPInfoForActiveSegmentContinueScan(threadContext->TTDContext);
- return JsNoError;
- });
- }
- elog->PushMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
- elog->PushMode(TTD::TTDMode::DebuggerLogBreakpoints);
- try
- {
- if(endSnapTime == -1)
- {
- elog->ReplayRootEventsToTime(TTD_EVENT_MAXTIME);
- }
- else
- {
- elog->ReplayRootEventsToTime(endSnapTime);
- }
- }
- catch(TTD::TTDebuggerAbortException abortException)
- {
- //If we hit the end of the log or we hit a terminal exception that is fine -- anything else is a problem
- if(!abortException.IsEndOfLog() && !abortException.IsTopLevelException())
- {
- res = JsErrorFatal;
- }
- }
- catch(...) //we are replaying something that should be known to execute successfully so encountering any error is very bad
- {
- res = JsErrorFatal;
- TTDAssert(false, "Unexpected fatal Error");
- }
- elog->PopMode(TTD::TTDMode::DebuggerLogBreakpoints);
- elog->PopMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
- //If we are in the "active" segment un-set the continue breakpoint
- if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment)
- {
- GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- emanager->ClearBPInfoForActiveSegmentContinueScan(threadContext->TTDContext);
- return JsNoError;
- });
- }
- if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinue) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinue)
- {
- bool bpFound = emanager->TryFindAndSetPreviousBP();
- if(bpFound)
- {
- *newTargetEventTime = emanager->GetPendingTTDBPTargetEventTime();
- }
- }
- return res;
- #endif
- }
- CHAKRA_API JsTTDMoveToTopLevelEvent(_In_ JsRuntimeHandle runtimeHandle, _In_ JsTTDMoveMode moveMode, _In_ int64_t snapshotTime, _In_ int64_t eventTime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
- ThreadContext* threadContext = runtime->GetThreadContext();
- TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
- TTD::EventLog* elog = threadContext->TTDLog;
- JsErrorCode res = JsNoError;
- JsErrorCode inflateStatus = TTDHandleBreakpointInfoAndInflate(snapshotTime, runtime, threadContext);
- if(inflateStatus != JsNoError)
- {
- return inflateStatus;
- }
- elog->PushMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
- try
- {
- elog->ReplayRootEventsToTime(eventTime);
- elog->DoRtrSnapIfNeeded();
- }
- catch(...) //we are replaying something that should be known to execute successfully so encountering any error is very bad
- {
- res = JsErrorFatal;
- TTDAssert(false, "Unexpected fatal Error");
- }
- elog->PopMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
- return res;
- #endif
- }
- CHAKRA_API JsTTDReplayExecution(_Inout_ JsTTDMoveMode* moveMode, _Out_ int64_t* rootEventTime)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
- TTDAssert(cCheck == JsNoError, "This shouldn't happen!!!");
- Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
- ThreadContext* threadContext = scriptContext->GetThreadContext();
- TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
- TTD::EventLog* elog = threadContext->TTDLog;
- TTD::ExecutionInfoManager* emanager = threadContext->TTDExecutionInfo;
- if(emanager != nullptr)
- {
- JsErrorCode bpstatus = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
- {
- if((*moveMode & JsTTDMoveMode::JsTTDMoveBreakOnEntry) == JsTTDMoveMode::JsTTDMoveBreakOnEntry)
- {
- emanager->SetBreakOnFirstUserCode();
- }
- //Set the active BP info from the manager (so we will hit the BP in step back operations)
- emanager->SetActiveBPInfoAsNeeded(threadContext->TTDContext);
- return JsNoError;
- });
- if(bpstatus != JsNoError)
- {
- return bpstatus;
- }
- }
- *moveMode = JsTTDMoveMode::JsTTDMoveNone;
- *rootEventTime = -1;
- JsErrorCode res = JsNoError;
- try
- {
- elog->ReplayRootEventsToTime(TTD_EVENT_MAXTIME);
- }
- catch(TTD::TTDebuggerAbortException abortException)
- {
- //if the debugger bails out with a move time request set info on the requested event time here
- //rest of breakpoint info should have been set by the debugger callback before aborting
- if (abortException.IsEventTimeMove() || abortException.IsTopLevelException())
- {
- *moveMode = (JsTTDMoveMode)abortException.GetMoveMode();
- *rootEventTime = abortException.GetTargetEventTime();
- //Check if we are tracking execution and, if so, set the exception location so we can access it later
- if(emanager != nullptr && abortException.IsTopLevelException())
- {
- emanager->SetPendingTTDUnhandledException();
- }
- }
- res = abortException.IsTopLevelException() ? JsErrorCategoryScript : JsNoError;
- }
- catch(...)
- {
- res = JsErrorFatal;
- TTDAssert(false, "Unexpected fatal Error");
- }
- return res;
- #endif
- }
- CHAKRA_API JsTTDDiagSetAutoTraceStatus(_In_ bool status)
- {
- #if !ENABLE_TTD
- return JsErrorCategoryUsage;
- #else
- JsrtContext *currentContext = JsrtContext::GetCurrent();
- JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
- TTDAssert(cCheck == JsNoError, "Must have valid context when setting auto trace status.");
- Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
- ThreadContext* threadContext = scriptContext->GetThreadContext();
- if (threadContext->IsRuntimeInTTDMode())
- {
- threadContext->TTDLog->SetAutoTraceEnabled(status);
- }
- return JsNoError;
- #endif
- }
- #ifdef _CHAKRACOREBUILD
- template <class CopyFunc>
- JsErrorCode WriteStringCopy(
- JsValueRef value,
- int start,
- int length,
- _Out_opt_ size_t* written,
- const CopyFunc& copyFunc)
- {
- if (written)
- {
- *written = 0; // init to 0 for default
- }
- const char16* str = nullptr;
- size_t strLength = 0;
- JsErrorCode errorCode = JsStringToPointer(value, &str, &strLength);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- if (start < 0 || (size_t)start > strLength)
- {
- return JsErrorInvalidArgument; // start out of range, no chars written
- }
- size_t count = min(static_cast<size_t>(length), strLength - start);
- if (count == 0)
- {
- return JsNoError; // no chars written
- }
- errorCode = copyFunc(str + start, count, written);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- if (written)
- {
- *written = count;
- }
- return JsNoError;
- }
- CHAKRA_API JsCopyStringUtf16(
- _In_ JsValueRef value,
- _In_ int start,
- _In_ int length,
- _Out_opt_ uint16_t* buffer,
- _Out_opt_ size_t* written)
- {
- PARAM_NOT_NULL(value);
- VALIDATE_JSREF(value);
- return WriteStringCopy(value, start, length, written,
- [buffer](const char16* src, size_t count, size_t *needed)
- {
- if (buffer)
- {
- memmove(buffer, src, sizeof(char16) * count);
- }
- return JsNoError;
- });
- }
- CHAKRA_API JsCopyString(
- _In_ JsValueRef value,
- _Out_opt_ char* buffer,
- _In_ size_t bufferSize,
- _Out_opt_ size_t* length)
- {
- PARAM_NOT_NULL(value);
- VALIDATE_JSREF(value);
- const char16* str = nullptr;
- size_t strLength = 0;
- JsErrorCode errorCode = JsStringToPointer(value, &str, &strLength);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- utf8::WideToNarrow utf8Str(str, strLength, buffer, bufferSize);
- if (length)
- {
- *length = utf8Str.Length();
- }
- return JsNoError;
- }
- _ALWAYSINLINE JsErrorCode CompileRun(
- JsValueRef scriptVal,
- JsSourceContext sourceContext,
- JsValueRef sourceUrl,
- JsParseScriptAttributes parseAttributes,
- _Out_ JsValueRef *result,
- bool parseOnly)
- {
- PARAM_NOT_NULL(scriptVal);
- VALIDATE_JSREF(scriptVal);
- PARAM_NOT_NULL(sourceUrl);
- bool isExternalArray = Js::VarIs<Js::ArrayBuffer>(scriptVal),
- isString = false;
- bool isUtf8 = !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded);
- LoadScriptFlag scriptFlag = LoadScriptFlag_None;
- const byte* script;
- size_t cb;
- const WCHAR *url;
- if (isExternalArray)
- {
- script = ((Js::ExternalArrayBuffer*)(scriptVal))->GetBuffer();
- cb = ((Js::ExternalArrayBuffer*)(scriptVal))->GetByteLength();
- scriptFlag = (LoadScriptFlag)(isUtf8 ?
- LoadScriptFlag_ExternalArrayBuffer | LoadScriptFlag_Utf8Source :
- LoadScriptFlag_ExternalArrayBuffer);
- }
- else
- {
- isString = Js::VarIs<Js::JavascriptString>(scriptVal);
- if (!isString)
- {
- return JsErrorInvalidArgument;
- }
- }
- JsErrorCode error = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
- if (isString)
- {
- Js::JavascriptString* jsString = Js::VarTo<Js::JavascriptString>(scriptVal);
- script = (const byte*)jsString->GetSz();
- // JavascriptString is 2 bytes (WCHAR/char16)
- cb = jsString->GetLength() * sizeof(WCHAR);
- }
- if (!Js::VarIs<Js::JavascriptString>(sourceUrl))
- {
- return JsErrorInvalidArgument;
- }
- url = Js::VarTo<Js::JavascriptString>(sourceUrl)->GetSz();
- return JsNoError;
- });
- if (error != JsNoError)
- {
- return error;
- }
- return RunScriptCore(scriptVal, script, cb, scriptFlag,
- sourceContext, url, parseOnly, parseAttributes, false, result);
- }
- CHAKRA_API JsParse(
- _In_ JsValueRef scriptVal,
- _In_ JsSourceContext sourceContext,
- _In_ JsValueRef sourceUrl,
- _In_ JsParseScriptAttributes parseAttributes,
- _Out_ JsValueRef *result)
- {
- return CompileRun(scriptVal, sourceContext, sourceUrl, parseAttributes,
- result, true);
- }
- CHAKRA_API JsRun(
- _In_ JsValueRef scriptVal,
- _In_ JsSourceContext sourceContext,
- _In_ JsValueRef sourceUrl,
- _In_ JsParseScriptAttributes parseAttributes,
- _Out_ JsValueRef *result)
- {
- return CompileRun(scriptVal, sourceContext, sourceUrl, parseAttributes,
- result, false);
- }
- CHAKRA_API JsCreatePropertyId(
- _In_z_ const char *name,
- _In_ size_t length,
- _Out_ JsPropertyIdRef *propertyId)
- {
- PARAM_NOT_NULL(name);
- utf8::NarrowToWide wname(name, length);
- if (!wname)
- {
- return JsErrorOutOfMemory;
- }
- return JsGetPropertyIdFromNameInternal(wname, wname.Length(), propertyId);
- }
- CHAKRA_API JsCopyPropertyId(
- _In_ JsPropertyIdRef propertyId,
- _Out_ char* buffer,
- _In_ size_t bufferSize,
- _Out_ size_t* length)
- {
- PARAM_NOT_NULL(propertyId);
- const char16* str = nullptr;
- JsErrorCode errorCode = JsGetPropertyNameFromId(propertyId, &str);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- utf8::WideToNarrow utf8Str(str);
- if (!buffer)
- {
- if (length)
- {
- *length = utf8Str.Length();
- }
- }
- else
- {
- size_t count = min(bufferSize, utf8Str.Length());
- // Try to copy whole characters if buffer size insufficient
- auto maxFitChars = utf8::ByteIndexIntoCharacterIndex(
- (LPCUTF8)(const char*)utf8Str, count,
- utf8::DecodeOptions::doChunkedEncoding);
- count = utf8::CharacterIndexToByteIndex(
- (LPCUTF8)(const char*)utf8Str, utf8Str.Length(), maxFitChars);
- memmove(buffer, utf8Str, sizeof(char) * count);
- if (length)
- {
- *length = count;
- }
- }
- return JsNoError;
- }
- CHAKRA_API JsSerialize(
- _In_ JsValueRef scriptVal,
- _Out_ JsValueRef *bufferVal,
- _In_ JsParseScriptAttributes parseAttributes)
- {
- PARAM_NOT_NULL(scriptVal);
- PARAM_NOT_NULL(bufferVal);
- VALIDATE_JSREF(scriptVal);
- *bufferVal = nullptr;
- const byte* script = nullptr;
- size_t cb = 0;
- LoadScriptFlag scriptFlag = LoadScriptFlag_None;
- JsErrorCode errorCode = GetScriptBufferDetails(scriptVal, parseAttributes,
- &scriptFlag, &cb, &script);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- unsigned int bufferSize = 0;
- errorCode = JsSerializeScriptCore(script, cb, scriptFlag, nullptr,
- 0, nullptr, &bufferSize, scriptVal);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- if (bufferSize == 0)
- {
- return JsErrorScriptCompile;
- }
- if ((errorCode = JsCreateArrayBuffer(bufferSize, bufferVal)) == JsNoError)
- {
- byte* buffer = ((Js::ArrayBuffer*)(*bufferVal))->GetBuffer();
- errorCode = JsSerializeScriptCore(script, cb, scriptFlag, nullptr,
- 0, buffer, &bufferSize, scriptVal);
- }
- return errorCode;
- }
- CHAKRA_API JsParseSerialized(
- _In_ JsValueRef bufferVal,
- _In_ JsSerializedLoadScriptCallback scriptLoadCallback,
- _In_ JsSourceContext sourceContext,
- _In_ JsValueRef sourceUrl,
- _Out_ JsValueRef *result)
- {
- PARAM_NOT_NULL(bufferVal);
- PARAM_NOT_NULL(sourceUrl);
- const WCHAR *url;
- if (Js::VarIs<Js::JavascriptString>(sourceUrl))
- {
- url = ((Js::JavascriptString*)(sourceUrl))->GetSz();
- }
- else
- {
- return JsErrorInvalidArgument;
- }
- // JsParseSerialized only accepts ArrayBuffer (incl. ExternalArrayBuffer)
- if (!Js::VarIs<Js::ArrayBuffer>(bufferVal))
- {
- return JsErrorInvalidArgument;
- }
- Js::ArrayBuffer* arrayBuffer = Js::VarTo<Js::ArrayBuffer>(bufferVal);
- byte* buffer = arrayBuffer->GetBuffer();
- return RunSerializedScriptCore(
- scriptLoadCallback, DummyScriptUnloadCallback,
- sourceContext,// use the same user provided sourceContext as scriptLoadSourceContext
- buffer, arrayBuffer, sourceContext, url, 0, true, false, result, Js::Constants::InvalidSourceIndex);
- }
- CHAKRA_API JsRunSerialized(
- _In_ JsValueRef bufferVal,
- _In_ JsSerializedLoadScriptCallback scriptLoadCallback,
- _In_ JsSourceContext sourceContext,
- _In_ JsValueRef sourceUrl,
- _Out_ JsValueRef *result)
- {
- PARAM_NOT_NULL(bufferVal);
- const WCHAR *url;
- if (sourceUrl && Js::VarIs<Js::JavascriptString>(sourceUrl))
- {
- url = ((Js::JavascriptString*)(sourceUrl))->GetSz();
- }
- else
- {
- return JsErrorInvalidArgument;
- }
- // JsParseSerialized only accepts ArrayBuffer (incl. ExternalArrayBuffer)
- if (!Js::VarIs<Js::ArrayBuffer>(bufferVal))
- {
- return JsErrorInvalidArgument;
- }
- Js::ArrayBuffer* arrayBuffer = Js::VarTo<Js::ArrayBuffer>(bufferVal);
- byte* buffer = arrayBuffer->GetBuffer();
- return RunSerializedScriptCore(
- scriptLoadCallback, DummyScriptUnloadCallback,
- sourceContext, // use the same user provided sourceContext as scriptLoadSourceContext
- buffer, arrayBuffer, sourceContext, url, 0, false, false, result, Js::Constants::InvalidSourceIndex);
- }
- CHAKRA_API JsCopyStringOneByte(
- _In_ JsValueRef value,
- _In_ int start,
- _In_ int length,
- _Out_opt_ char* buffer,
- _Out_opt_ size_t* written)
- {
- PARAM_NOT_NULL(value);
- VALIDATE_JSREF(value);
- return WriteStringCopy(value, start, length, written,
- [buffer](const char16* src, size_t count, size_t *needed)
- {
- if (buffer)
- {
- for (size_t i = 0; i < count; i++)
- {
- buffer[i] = (char)src[i];
- }
- }
- return JsNoError;
- });
- }
- CHAKRA_API JsSerializeParserStateCore(
- _In_z_ const byte* script,
- _In_ size_t cb,
- _In_ LoadScriptFlag loadScriptFlag,
- _Out_writes_to_opt_(*bufferSize, *bufferSize) unsigned char *buffer,
- _Inout_ unsigned int *bufferSize)
- {
- Js::JavascriptFunction *function;
- CompileScriptException se;
- return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
- PARAM_NOT_NULL(script);
- PARAM_NOT_NULL(bufferSize);
- if (*bufferSize > 0)
- {
- PARAM_NOT_NULL(buffer);
- ZeroMemory(buffer, *bufferSize);
- }
- if (scriptContext->IsScriptContextInDebugMode())
- {
- return JsErrorCannotSerializeDebugScript;
- }
- SourceContextInfo * sourceContextInfo = scriptContext->GetSourceContextInfo(JS_SOURCE_CONTEXT_NONE, nullptr);
- Assert(sourceContextInfo != nullptr);
- sourceContextInfo->nextLocalFunctionId = 0;
- const int chsize = (loadScriptFlag & LoadScriptFlag_Utf8Source) ?
- sizeof(utf8char_t) : sizeof(WCHAR);
- SRCINFO si = {
- /* sourceContextInfo */ sourceContextInfo,
- /* dlnHost */ 0,
- /* ulColumnHost */ 0,
- /* lnMinHost */ 0,
- /* ichMinHost */ 0,
- /* ichLimHost */ static_cast<ULONG>(cb / chsize), // OK to truncate since this is used to limit sourceText in debugDocument/compilation errors.
- /* ulCharOffset */ 0,
- /* mod */ kmodGlobal,
- /* grfsi */ 0
- };
- Js::Utf8SourceInfo* sourceInfo = nullptr;
- loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_CreateParserState);
- BEGIN_TEMP_ALLOCATOR(tempAllocator, scriptContext, _u("ByteCodeSerializer"));
- // We cast buffer size to DWORD* because on Windows, DWORD = unsigned long = unsigned int
- // On 64-bit clang on linux, this is not true, unsigned long is larger than unsigned int
- // However, the PAL defines DWORD for us on linux as unsigned int so the cast is safe here.
- HRESULT hr = scriptContext->SerializeParserState(script, cb, &si, &se, &sourceInfo,
- Js::Constants::GlobalCode, loadScriptFlag, &buffer, (DWORD*)bufferSize, tempAllocator, &function, nullptr);
- END_TEMP_ALLOCATOR(tempAllocator, scriptContext);
- if (function == nullptr)
- {
- HandleScriptCompileError(scriptContext, &se);
- return JsErrorScriptCompile;
- }
- Js::FunctionBody *functionBody = function->GetFunctionBody();
- sourceInfo = functionBody->GetUtf8SourceInfo();
- size_t cSourceCodeLength = sourceInfo->GetCbLength(_u("JsSerializeParserState"));
- // truncation of code length can lead to accessing random memory. Reject the call.
- if (cSourceCodeLength > DWORD_MAX)
- {
- return JsErrorOutOfMemory;
- }
- if (SUCCEEDED(hr))
- {
- return JsNoError;
- }
- else
- {
- return JsErrorScriptCompile;
- }
- });
- }
- CHAKRA_API JsSerializeParserState(
- _In_ JsValueRef scriptVal,
- _Out_ JsValueRef *bufferVal,
- _In_ JsParseScriptAttributes parseAttributes)
- {
- PARAM_NOT_NULL(scriptVal);
- PARAM_NOT_NULL(bufferVal);
- VALIDATE_JSREF(scriptVal);
- *bufferVal = nullptr;
- const byte* script = nullptr;
- size_t cb = 0;
- LoadScriptFlag scriptFlag = LoadScriptFlag_None;
- JsErrorCode errorCode = GetScriptBufferDetails(scriptVal, parseAttributes,
- &scriptFlag, &cb, &script);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- unsigned int bufferSize = 0;
- errorCode = JsSerializeParserStateCore(script, cb, scriptFlag, nullptr,
- &bufferSize);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- if (bufferSize == 0)
- {
- return JsErrorScriptCompile;
- }
- if ((errorCode = JsCreateArrayBuffer(bufferSize, bufferVal)) == JsNoError)
- {
- byte* buffer = ((Js::ArrayBuffer*)(*bufferVal))->GetBuffer();
- errorCode = JsSerializeParserStateCore(script, cb, scriptFlag, buffer,
- &bufferSize);
- }
- return errorCode;
- }
- static bool CHAKRA_CALLBACK DummyScriptLoadSourceCallbackForRunScriptWithParserState(
- JsSourceContext sourceContext,
- _Out_ JsValueRef *value,
- _Out_ JsParseScriptAttributes *parseAttributes)
- {
- *value = nullptr;
- *parseAttributes = JsParseScriptAttributeNone;
- return true;
- }
- CHAKRA_API RunScriptWithParserStateCore(
- _In_ DWORD dwBgParseCookie,
- _In_ JsValueRef script,
- _In_ JsSourceContext sourceContext,
- _In_ WCHAR *url,
- _In_ JsParseScriptAttributes parseAttributes,
- _In_ JsValueRef parserState,
- _In_ bool parseOnly,
- _Out_ JsValueRef *result
- )
- {
- PARAM_NOT_NULL(script);
- if (dwBgParseCookie == 0)
- {
- PARAM_NOT_NULL(parserState);
- }
- uint sourceIndex = 0;
- JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
- const byte* bytes;
- size_t cb;
- LoadScriptFlag loadScriptFlag;
- JsErrorCode errorCode = GetScriptBufferDetails(script, parseAttributes, &loadScriptFlag, &cb, &bytes);
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- SourceContextInfo* sourceContextInfo = scriptContext->GetSourceContextInfo(sourceContext, nullptr);
- if (sourceContextInfo == nullptr)
- {
- sourceContextInfo = scriptContext->CreateSourceContextInfo(sourceContext, url, wcslen(url), nullptr);
- }
- const int chsize = (loadScriptFlag & LoadScriptFlag_Utf8Source) ?
- sizeof(utf8char_t) : sizeof(WCHAR);
- SRCINFO si = {
- /* sourceContextInfo */ sourceContextInfo,
- /* dlnHost */ 0,
- /* ulColumnHost */ 0,
- /* lnMinHost */ 0,
- /* ichMinHost */ 0,
- /* ichLimHost */ static_cast<ULONG>(cb / chsize), // OK to truncate since this is used to limit sourceText in debugDocument/compilation errors.
- /* ulCharOffset */ 0,
- /* mod */ kmodGlobal,
- /* grfsi */ 0
- };
- Js::Utf8SourceInfo* utf8SourceInfo = nullptr;
- scriptContext->MakeUtf8SourceInfo(bytes, cb, &si, &utf8SourceInfo, loadScriptFlag, script);
- if (utf8SourceInfo == nullptr)
- {
- return JsErrorInvalidArgument;
- }
- ULONG grfscr = scriptContext->GetParseFlags(loadScriptFlag, utf8SourceInfo, sourceContextInfo);
- utf8SourceInfo->SetParseFlags(grfscr);
- if ((loadScriptFlag & LoadScriptFlag_Utf8Source) != LoadScriptFlag_Utf8Source)
- {
- sourceIndex = scriptContext->SaveSourceNoCopy(utf8SourceInfo, static_cast<charcount_t>(utf8SourceInfo->GetCchLength()), /*isCesu8*/ true);
- }
- else
- {
- // TODO: This length may not be correct because we could have actually parsed a different number of characters
- sourceIndex = scriptContext->SaveSourceNoCopy(utf8SourceInfo, static_cast<charcount_t>(utf8SourceInfo->GetCchLength()), /* isCesu8*/ false);
- }
- return JsNoError;
- });
- if (errorCode != JsNoError)
- {
- return errorCode;
- }
- Js::ArrayBuffer* arrayBuffer = nullptr;
- byte* buffer = nullptr;
- if (dwBgParseCookie == 0)
- {
- if (!Js::VarIs<Js::ArrayBuffer>(parserState))
- {
- return JsErrorInvalidArgument;
- }
- arrayBuffer = Js::VarTo<Js::ArrayBuffer>(parserState);
- buffer = arrayBuffer->GetBuffer();
- }
- JsSerializedLoadScriptCallback dummy = DummyScriptLoadSourceCallbackForRunScriptWithParserState;
- return RunSerializedScriptCore(
- dummy, DummyScriptUnloadCallback,
- sourceContext, // use the same user provided sourceContext as scriptLoadSourceContext
- buffer, arrayBuffer, sourceContext, url, dwBgParseCookie, parseOnly, true, result, sourceIndex);
- }
- CHAKRA_API JsRunScriptWithParserState(
- _In_ JsValueRef script,
- _In_ JsSourceContext sourceContext,
- _In_ JsValueRef sourceUrl,
- _In_ JsParseScriptAttributes parseAttributes,
- _In_ JsValueRef parserState,
- _Out_ JsValueRef *result)
- {
- WCHAR *url = nullptr;
- if (sourceUrl && Js::VarIs<Js::JavascriptString>(sourceUrl))
- {
- url = const_cast<WCHAR*>(((Js::JavascriptString*)(sourceUrl))->GetSz());
- return RunScriptWithParserStateCore(0, script, sourceContext, url, parseAttributes, parserState, false, result);
- }
- else
- {
- return JsErrorInvalidArgument;
- }
- }
- CHAKRA_API JsDeserializeParserState(
- _In_ JsValueRef script,
- _In_ JsSourceContext sourceContext,
- _In_ JsValueRef sourceUrl,
- _In_ JsParseScriptAttributes parseAttributes,
- _In_ JsValueRef parserState,
- _Out_ JsValueRef * result)
- {
- WCHAR *url = nullptr;
- if (sourceUrl && Js::VarIs<Js::JavascriptString>(sourceUrl))
- {
- url = const_cast<WCHAR*>(((Js::JavascriptString*)(sourceUrl))->GetSz());
- return RunScriptWithParserStateCore(0, script, sourceContext, url, parseAttributes, parserState, true, result);
- }
- else
- {
- return JsErrorInvalidArgument;
- }
- }
- CHAKRA_API
- JsExecuteBackgroundParse_Experimental(
- _In_ DWORD dwBgParseCookie,
- _In_ JsValueRef script,
- _In_ JsSourceContext sourceContext,
- _In_ WCHAR *url,
- _In_ JsParseScriptAttributes parseAttributes,
- _In_ JsValueRef parserState,
- _Out_ JsValueRef *result)
- {
- HRESULT hr = BGParseManager::GetBGParseManager()->GetInputFromCookie(dwBgParseCookie, nullptr, nullptr, &url);
- if (hr == S_OK)
- {
- return RunScriptWithParserStateCore(
- dwBgParseCookie,
- script,
- sourceContext,
- url,
- parseAttributes,
- parserState,
- false,
- result
- );
- }
- else
- {
- return JsErrorFatal;
- }
- }
- #endif
|