Jsrt.cpp 180 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "JsrtPch.h"
  6. #include "JsrtInternal.h"
  7. #include "JsrtExternalObject.h"
  8. #include "JsrtExternalArrayBuffer.h"
  9. #include "jsrtHelper.h"
  10. #include "JsrtSourceHolder.h"
  11. #include "ByteCode/ByteCodeSerializer.h"
  12. #include "Common/ByteSwap.h"
  13. #include "Library/DataView.h"
  14. #include "Library/JavascriptExceptionMetadata.h"
  15. #include "Library/JavascriptSymbol.h"
  16. #include "Library/JavascriptPromise.h"
  17. #include "Base/ThreadContextTlsEntry.h"
  18. #include "Codex/Utf8Helper.h"
  19. // Parser Includes
  20. #include "cmperr.h" // For ERRnoMemory
  21. #include "screrror.h" // For CompileScriptException
  22. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  23. #include "TestHooksRt.h"
  24. #endif
  25. struct CodexHeapAllocatorInterface
  26. {
  27. public:
  28. static void* allocate(size_t size)
  29. {
  30. return HeapNewArray(char, size);
  31. }
  32. static void free(void* ptr, size_t count)
  33. {
  34. HeapDeleteArray(count, (char*) ptr);
  35. }
  36. };
  37. JsErrorCode CheckContext(JsrtContext *currentContext, bool verifyRuntimeState,
  38. bool allowInObjectBeforeCollectCallback)
  39. {
  40. if (currentContext == nullptr)
  41. {
  42. return JsErrorNoCurrentContext;
  43. }
  44. // We don't need parameter check if it's checked in previous wrapper.
  45. if (verifyRuntimeState)
  46. {
  47. Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
  48. Assert(scriptContext != nullptr);
  49. Recycler *recycler = scriptContext->GetRecycler();
  50. ThreadContext *threadContext = scriptContext->GetThreadContext();
  51. if (recycler && recycler->IsHeapEnumInProgress())
  52. {
  53. return JsErrorHeapEnumInProgress;
  54. }
  55. else if (!allowInObjectBeforeCollectCallback &&
  56. recycler && recycler->IsInObjectBeforeCollectCallback())
  57. {
  58. return JsErrorInObjectBeforeCollectCallback;
  59. }
  60. else if (threadContext->IsExecutionDisabled())
  61. {
  62. return JsErrorInDisabledState;
  63. }
  64. else if (scriptContext->IsInProfileCallback())
  65. {
  66. return JsErrorInProfileCallback;
  67. }
  68. else if (threadContext->IsInThreadServiceCallback())
  69. {
  70. return JsErrorInThreadServiceCallback;
  71. }
  72. // Make sure we don't have an outstanding exception.
  73. if (scriptContext->GetThreadContext()->GetRecordedException() != nullptr)
  74. {
  75. return JsErrorInExceptionState;
  76. }
  77. }
  78. return JsNoError;
  79. }
  80. /////////////////////
  81. #if ENABLE_TTD
  82. void CALLBACK OnScriptLoad_TTDCallback(FinalizableObject* jsrtCtx, Js::FunctionBody* body, Js::Utf8SourceInfo* utf8SourceInfo, CompileScriptException* compileException, bool notify)
  83. {
  84. ((JsrtContext*)jsrtCtx)->OnScriptLoad_TTDCallback(body, utf8SourceInfo, compileException, notify);
  85. }
  86. uint32 CALLBACK OnBPRegister_TTDCallback(void* runtimeRcvr, int64 bpID, Js::ScriptContext* scriptContext, Js::Utf8SourceInfo* utf8SourceInfo, uint32 line, uint32 column, BOOL* isNewBP)
  87. {
  88. return ((JsrtRuntime*)runtimeRcvr)->BPRegister_TTD(bpID, scriptContext, utf8SourceInfo, line, column, isNewBP);
  89. }
  90. void CALLBACK OnBPDelete_TTDCallback(void* runtimeRcvr, uint32 bpID)
  91. {
  92. ((JsrtRuntime*)runtimeRcvr)->BPDelete_TTD(bpID);
  93. }
  94. void CALLBACK OnBPClearDocument_TTDCallback(void* runtimeRcvr)
  95. {
  96. ((JsrtRuntime*)runtimeRcvr)->BPClearDocument_TTD();
  97. }
  98. #endif
  99. //A create context function that we can funnel to for regular and record or debug aware creation
  100. JsErrorCode CreateContextCore(_In_ JsRuntimeHandle runtimeHandle, _In_ TTDRecorder& _actionEntryPopper, _In_ bool inRecordMode, _In_ bool activelyRecording, _In_ bool inReplayMode, _Out_ JsContextRef *newContext)
  101. {
  102. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  103. ThreadContext * threadContext = runtime->GetThreadContext();
  104. if(threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
  105. {
  106. return JsErrorHeapEnumInProgress;
  107. }
  108. else if(threadContext->IsInThreadServiceCallback())
  109. {
  110. return JsErrorInThreadServiceCallback;
  111. }
  112. ThreadContextScope scope(threadContext);
  113. if(!scope.IsValid())
  114. {
  115. return JsErrorWrongThread;
  116. }
  117. #if ENABLE_TTD
  118. TTD::NSLogEvents::EventLogEntry* createEvent = nullptr;
  119. if(activelyRecording)
  120. {
  121. createEvent = threadContext->TTDLog->RecordJsRTCreateScriptContext(_actionEntryPopper);
  122. }
  123. #endif
  124. JsrtContext * context = JsrtContext::New(runtime);
  125. #if ENABLE_TTD
  126. if(inRecordMode | inReplayMode)
  127. {
  128. Js::ScriptContext* scriptContext = context->GetScriptContext();
  129. HostScriptContextCallbackFunctor callbackFunctor((FinalizableObject*)context, (void*)runtime, &OnScriptLoad_TTDCallback, &OnBPRegister_TTDCallback, &OnBPDelete_TTDCallback, &OnBPClearDocument_TTDCallback);
  130. #if ENABLE_TTD_DIAGNOSTICS_TRACING
  131. bool noNative = true;
  132. bool doDebug = true;
  133. #else
  134. bool noNative = TTD_FORCE_NOJIT_MODE || threadContext->TTDLog->IsDebugModeFlagSet();
  135. bool doDebug = TTD_FORCE_DEBUG_MODE || threadContext->TTDLog->IsDebugModeFlagSet();
  136. #endif
  137. threadContext->TTDLog->PushMode(TTD::TTDMode::ExcludedExecutionTTAction);
  138. if(inRecordMode)
  139. {
  140. threadContext->TTDContext->AddNewScriptContextRecord(context, scriptContext, callbackFunctor, noNative, doDebug);
  141. }
  142. else
  143. {
  144. threadContext->TTDContext->AddNewScriptContextReplay(context, scriptContext, callbackFunctor, noNative, doDebug);
  145. }
  146. threadContext->TTDLog->SetModeFlagsOnContext(scriptContext);
  147. threadContext->TTDLog->PopMode(TTD::TTDMode::ExcludedExecutionTTAction);
  148. }
  149. #endif
  150. #ifdef ENABLE_SCRIPT_DEBUGGING
  151. JsrtDebugManager* jsrtDebugManager = runtime->GetJsrtDebugManager();
  152. if(jsrtDebugManager != nullptr)
  153. {
  154. // JsDiagStartDebugging was called
  155. threadContext->GetDebugManager()->SetLocalsDisplayFlags(Js::DebugManager::LocalsDisplayFlags::LocalsDisplayFlags_NoGroupMethods);
  156. Js::ScriptContext* scriptContext = context->GetScriptContext();
  157. Js::DebugContext* debugContext = scriptContext->GetDebugContext();
  158. debugContext->SetHostDebugContext(jsrtDebugManager);
  159. if (!jsrtDebugManager->IsDebugEventCallbackSet())
  160. {
  161. // JsDiagStopDebugging was called so we need to be in SourceRunDownMode
  162. debugContext->SetDebuggerMode(Js::DebuggerMode::SourceRundown);
  163. }
  164. else
  165. {
  166. // Set Debugging mode
  167. scriptContext->InitializeDebugging();
  168. Js::ProbeContainer* probeContainer = debugContext->GetProbeContainer();
  169. probeContainer->InitializeInlineBreakEngine(jsrtDebugManager);
  170. probeContainer->InitializeDebuggerScriptOptionCallback(jsrtDebugManager);
  171. }
  172. }
  173. #endif
  174. #if ENABLE_TTD
  175. if(activelyRecording)
  176. {
  177. threadContext->TTDLog->RecordJsRTCreateScriptContextResult(createEvent, context->GetScriptContext());
  178. }
  179. #endif
  180. *newContext = (JsContextRef)context;
  181. return JsNoError;
  182. }
  183. #if ENABLE_TTD
  184. void CALLBACK CreateExternalObject_TTDCallback(Js::ScriptContext* ctx, Js::Var* object)
  185. {
  186. TTDAssert(object != nullptr, "This should always be a valid location");
  187. *object = JsrtExternalObject::Create(nullptr, nullptr, ctx);
  188. }
  189. void CALLBACK TTDDummyPromiseContinuationCallback(JsValueRef task, void *callbackState)
  190. {
  191. TTDAssert(false, "This should never actually be invoked!!!");
  192. }
  193. void CALLBACK CreateJsRTContext_TTDCallback(void* runtimeHandle, Js::ScriptContext** result)
  194. {
  195. JsContextRef newContext = nullptr;
  196. *result = nullptr;
  197. TTDRecorder dummyActionEntryPopper;
  198. JsErrorCode err = CreateContextCore(static_cast<JsRuntimeHandle>(runtimeHandle), dummyActionEntryPopper, false /*inRecordMode*/, false /*activelyRecording*/, true /*inReplayMode*/, &newContext);
  199. TTDAssert(err == JsNoError, "Shouldn't fail on us!!!");
  200. *result = static_cast<JsrtContext*>(newContext)->GetScriptContext();
  201. (*result)->GetLibrary()->SetNativeHostPromiseContinuationFunction((Js::JavascriptLibrary::PromiseContinuationCallback)TTDDummyPromiseContinuationCallback, nullptr);
  202. //To ensure we have a valid context active (when we next try and inflate into this context) set this as active by convention
  203. JsrtContext::TrySetCurrent(static_cast<JsrtContext*>(newContext));
  204. }
  205. void CALLBACK ReleaseJsRTContext_TTDCallback(FinalizableObject* jsrtCtx)
  206. {
  207. static_cast<JsrtContext*>(jsrtCtx)->GetScriptContext()->GetThreadContext()->GetRecycler()->RootRelease(jsrtCtx);
  208. JsrtContext::OnReplayDisposeContext_TTDCallback(jsrtCtx);
  209. }
  210. void CALLBACK SetActiveJsRTContext_TTDCallback(void* runtimeHandle, Js::ScriptContext* ctx)
  211. {
  212. JsrtRuntime * runtime = JsrtRuntime::FromHandle(static_cast<JsRuntimeHandle>(runtimeHandle));
  213. ThreadContext * threadContext = runtime->GetThreadContext();
  214. threadContext->TTDContext->SetActiveScriptContext(ctx);
  215. JsrtContext* runtimeCtx = (JsrtContext*)threadContext->TTDContext->GetRuntimeContextForScriptContext(ctx);
  216. JsrtContext::TrySetCurrent(runtimeCtx);
  217. }
  218. #endif
  219. //A create runtime function that we can funnel to for regular and record or debug aware creation
  220. JsErrorCode CreateRuntimeCore(_In_ JsRuntimeAttributes attributes,
  221. _In_opt_ const char* optTTUri, size_t optTTUriCount, bool isRecord, bool isReplay, bool isDebug,
  222. _In_ UINT32 snapInterval, _In_ UINT32 snapHistoryLength,
  223. _In_opt_ TTDOpenResourceStreamCallback openResourceStream, _In_opt_ JsTTDReadBytesFromStreamCallback readBytesFromStream,
  224. _In_opt_ JsTTDWriteBytesToStreamCallback writeBytesToStream, _In_opt_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream,
  225. _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtimeHandle)
  226. {
  227. VALIDATE_ENTER_CURRENT_THREAD();
  228. PARAM_NOT_NULL(runtimeHandle);
  229. *runtimeHandle = nullptr;
  230. JsErrorCode runtimeResult = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  231. const JsRuntimeAttributes JsRuntimeAttributesAll =
  232. (JsRuntimeAttributes)(
  233. JsRuntimeAttributeDisableBackgroundWork |
  234. JsRuntimeAttributeAllowScriptInterrupt |
  235. JsRuntimeAttributeEnableIdleProcessing |
  236. JsRuntimeAttributeDisableEval |
  237. JsRuntimeAttributeDisableNativeCodeGeneration |
  238. JsRuntimeAttributeEnableExperimentalFeatures |
  239. JsRuntimeAttributeDispatchSetExceptionsToDebugger |
  240. JsRuntimeAttributeDisableFatalOnOOM
  241. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  242. | JsRuntimeAttributeSerializeLibraryByteCode
  243. #endif
  244. );
  245. Assert((attributes & ~JsRuntimeAttributesAll) == 0);
  246. if ((attributes & ~JsRuntimeAttributesAll) != 0)
  247. {
  248. return JsErrorInvalidArgument;
  249. }
  250. CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 0, nullptr);
  251. AllocationPolicyManager * policyManager = HeapNew(AllocationPolicyManager, (attributes & JsRuntimeAttributeDisableBackgroundWork) == 0);
  252. bool enableExperimentalFeatures = (attributes & JsRuntimeAttributeEnableExperimentalFeatures) != 0;
  253. ThreadContext * threadContext = HeapNew(ThreadContext, policyManager, threadService, enableExperimentalFeatures);
  254. if (((attributes & JsRuntimeAttributeDisableBackgroundWork) != 0)
  255. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  256. && !Js::Configuration::Global.flags.ConcurrentRuntime
  257. #endif
  258. )
  259. {
  260. threadContext->OptimizeForManyInstances(true);
  261. #if ENABLE_NATIVE_CODEGEN
  262. threadContext->EnableBgJit(false);
  263. #endif
  264. }
  265. if (!threadContext->IsRentalThreadingEnabledInJSRT()
  266. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  267. || Js::Configuration::Global.flags.DisableRentalThreading
  268. #endif
  269. )
  270. {
  271. threadContext->SetIsThreadBound();
  272. }
  273. if (attributes & JsRuntimeAttributeAllowScriptInterrupt)
  274. {
  275. threadContext->SetThreadContextFlag(ThreadContextFlagCanDisableExecution);
  276. }
  277. if (attributes & JsRuntimeAttributeDisableEval)
  278. {
  279. threadContext->SetThreadContextFlag(ThreadContextFlagEvalDisabled);
  280. }
  281. if (attributes & JsRuntimeAttributeDisableNativeCodeGeneration)
  282. {
  283. threadContext->SetThreadContextFlag(ThreadContextFlagNoJIT);
  284. }
  285. if (attributes & JsRuntimeAttributeDisableFatalOnOOM)
  286. {
  287. threadContext->SetThreadContextFlag(ThreadContextFlagDisableFatalOnOOM);
  288. }
  289. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  290. if (Js::Configuration::Global.flags.PrimeRecycler)
  291. {
  292. threadContext->EnsureRecycler()->Prime();
  293. }
  294. #endif
  295. bool enableIdle = (attributes & JsRuntimeAttributeEnableIdleProcessing) == JsRuntimeAttributeEnableIdleProcessing;
  296. bool dispatchExceptions = (attributes & JsRuntimeAttributeDispatchSetExceptionsToDebugger) == JsRuntimeAttributeDispatchSetExceptionsToDebugger;
  297. JsrtRuntime * runtime = HeapNew(JsrtRuntime, threadContext, enableIdle, dispatchExceptions);
  298. threadContext->SetCurrentThreadId(ThreadContext::NoThread);
  299. *runtimeHandle = runtime->ToHandle();
  300. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  301. runtime->SetSerializeByteCodeForLibrary((attributes & JsRuntimeAttributeSerializeLibraryByteCode) != 0);
  302. #endif
  303. return JsNoError;
  304. });
  305. #if ENABLE_TTD
  306. if(runtimeResult != JsNoError)
  307. {
  308. return runtimeResult;
  309. }
  310. if(isRecord | isReplay | isDebug)
  311. {
  312. ThreadContext* threadContext = JsrtRuntime::FromHandle(*runtimeHandle)->GetThreadContext();
  313. if(isRecord && isReplay)
  314. {
  315. return JsErrorInvalidArgument; //A runtime can only be in 1 mode
  316. }
  317. if(isDebug && !isReplay)
  318. {
  319. return JsErrorInvalidArgument; //A debug runtime also needs to be in runtime mode (and we are going to be strict about it)
  320. }
  321. if(isReplay && optTTUri == nullptr)
  322. {
  323. return JsErrorInvalidArgument; //We must have a location to store data into
  324. }
  325. runtimeResult = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  326. //Make sure the thread context recycler is allocated before we do anything else
  327. ThreadContextScope scope(threadContext);
  328. threadContext->EnsureRecycler();
  329. threadContext->InitTimeTravel(threadContext, *runtimeHandle, snapInterval, max<uint32>(2, snapHistoryLength));
  330. threadContext->InitHostFunctionsAndTTData(isRecord, isReplay, isDebug, optTTUriCount, optTTUri,
  331. openResourceStream, readBytesFromStream, writeBytesToStream, flushAndCloseStream,
  332. &CreateExternalObject_TTDCallback, &CreateJsRTContext_TTDCallback, &ReleaseJsRTContext_TTDCallback, &SetActiveJsRTContext_TTDCallback);
  333. return JsNoError;
  334. });
  335. }
  336. #endif
  337. return runtimeResult;
  338. }
  339. /////////////////////
  340. CHAKRA_API JsCreateRuntime(_In_ JsRuntimeAttributes attributes, _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtimeHandle)
  341. {
  342. return CreateRuntimeCore(attributes,
  343. nullptr /*optRecordUri*/, 0 /*optRecordUriCount */, false /*isRecord*/, false /*isReplay*/, false /*isDebug*/,
  344. UINT_MAX /*optSnapInterval*/, UINT_MAX /*optLogLength*/,
  345. nullptr, nullptr, nullptr, nullptr, /*TTD IO handlers*/
  346. threadService, runtimeHandle);
  347. }
  348. template <CollectionFlags flags>
  349. JsErrorCode JsCollectGarbageCommon(JsRuntimeHandle runtimeHandle)
  350. {
  351. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  352. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  353. ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
  354. if (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
  355. {
  356. return JsErrorHeapEnumInProgress;
  357. }
  358. else if (threadContext->IsInThreadServiceCallback())
  359. {
  360. return JsErrorInThreadServiceCallback;
  361. }
  362. ThreadContextScope scope(threadContext);
  363. if (!scope.IsValid())
  364. {
  365. return JsErrorWrongThread;
  366. }
  367. Recycler* recycler = threadContext->EnsureRecycler();
  368. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  369. if (flags & CollectOverride_SkipStack)
  370. {
  371. Recycler::AutoEnterExternalStackSkippingGCMode autoGC(recycler);
  372. recycler->CollectNow<flags>();
  373. }
  374. else
  375. #endif
  376. {
  377. recycler->CollectNow<flags>();
  378. }
  379. return JsNoError;
  380. });
  381. }
  382. CHAKRA_API JsCollectGarbage(_In_ JsRuntimeHandle runtimeHandle)
  383. {
  384. return JsCollectGarbageCommon<CollectNowExhaustive>(runtimeHandle);
  385. }
  386. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  387. CHAKRA_API JsPrivateCollectGarbageSkipStack(_In_ JsRuntimeHandle runtimeHandle)
  388. {
  389. return JsCollectGarbageCommon<CollectNowExhaustiveSkipStack>(runtimeHandle);
  390. }
  391. CHAKRA_API JsPrivateDetachArrayBuffer(_In_ JsValueRef ref, _Out_ void** detachedState)
  392. {
  393. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  394. {
  395. VALIDATE_JSREF(ref);
  396. *detachedState = Js::JavascriptOperators::DetachVarAndGetState(ref);
  397. return JsNoError;
  398. });
  399. }
  400. CHAKRA_API JsPrivateFreeDetachedArrayBuffer(_In_ void* detachedState)
  401. {
  402. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  403. {
  404. auto state = reinterpret_cast<Js::ArrayBufferDetachedStateBase*>(detachedState);
  405. state->CleanUp();
  406. return JsNoError;
  407. });
  408. }
  409. #endif
  410. CHAKRA_API JsDisposeRuntime(_In_ JsRuntimeHandle runtimeHandle)
  411. {
  412. return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode {
  413. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  414. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  415. ThreadContext * threadContext = runtime->GetThreadContext();
  416. ThreadContextScope scope(threadContext);
  417. // We should not dispose if the runtime is being used.
  418. if (!scope.IsValid() ||
  419. scope.WasInUse() ||
  420. (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress()))
  421. {
  422. return JsErrorRuntimeInUse;
  423. }
  424. else if (threadContext->IsInThreadServiceCallback())
  425. {
  426. return JsErrorInThreadServiceCallback;
  427. }
  428. // Invoke and clear the callbacks while the contexts and runtime are still available
  429. {
  430. Recycler* recycler = threadContext->GetRecycler();
  431. if (recycler != nullptr)
  432. {
  433. recycler->ClearObjectBeforeCollectCallbacks();
  434. }
  435. }
  436. #ifdef ENABLE_SCRIPT_DEBUGGING
  437. if (runtime->GetJsrtDebugManager() != nullptr)
  438. {
  439. runtime->GetJsrtDebugManager()->ClearDebuggerObjects();
  440. }
  441. #endif
  442. Js::ScriptContext *scriptContext;
  443. for (scriptContext = threadContext->GetScriptContextList(); scriptContext; scriptContext = scriptContext->next)
  444. {
  445. #ifdef ENABLE_SCRIPT_DEBUGGING
  446. if (runtime->GetJsrtDebugManager() != nullptr)
  447. {
  448. runtime->GetJsrtDebugManager()->ClearDebugDocument(scriptContext);
  449. }
  450. #endif
  451. scriptContext->MarkForClose();
  452. }
  453. // Close any open Contexts.
  454. // We need to do this before recycler shutdown, because ScriptEngine->Close won't work then.
  455. runtime->CloseContexts();
  456. #ifdef ENABLE_SCRIPT_DEBUGGING
  457. runtime->DeleteJsrtDebugManager();
  458. #endif
  459. #if defined(CHECK_MEMORY_LEAK) || defined(LEAK_REPORT)
  460. bool doFinalGC = false;
  461. #if defined(LEAK_REPORT)
  462. if (Js::Configuration::Global.flags.IsEnabled(Js::LeakReportFlag))
  463. {
  464. doFinalGC = true;
  465. }
  466. #endif
  467. #if defined(CHECK_MEMORY_LEAK)
  468. if (Js::Configuration::Global.flags.CheckMemoryLeak)
  469. {
  470. doFinalGC = true;
  471. }
  472. #endif
  473. if (doFinalGC)
  474. {
  475. Recycler *recycler = threadContext->GetRecycler();
  476. if (recycler)
  477. {
  478. recycler->EnsureNotCollecting();
  479. recycler->CollectNow<CollectNowFinalGC>();
  480. Assert(!recycler->CollectionInProgress());
  481. }
  482. }
  483. #endif
  484. runtime->SetBeforeCollectCallback(nullptr, nullptr);
  485. threadContext->CloseForJSRT();
  486. HeapDelete(threadContext);
  487. HeapDelete(runtime);
  488. scope.Invalidate();
  489. return JsNoError;
  490. });
  491. }
  492. CHAKRA_API JsAddRef(_In_ JsRef ref, _Out_opt_ unsigned int *count)
  493. {
  494. VALIDATE_JSREF(ref);
  495. if (count != nullptr)
  496. {
  497. *count = 0;
  498. }
  499. if (Js::TaggedNumber::Is(ref))
  500. {
  501. // The count is always one because these are never collected
  502. if (count)
  503. {
  504. *count = 1;
  505. }
  506. return JsNoError;
  507. }
  508. if (JsrtContext::Is(ref))
  509. {
  510. return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode
  511. {
  512. Recycler * recycler = static_cast<JsrtContext *>(ref)->GetRuntime()->GetThreadContext()->GetRecycler();
  513. recycler->RootAddRef(ref, count);
  514. return JsNoError;
  515. });
  516. }
  517. else
  518. {
  519. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  520. if (threadContext == nullptr)
  521. {
  522. return JsErrorNoCurrentContext;
  523. }
  524. Recycler * recycler = threadContext->GetRecycler();
  525. return GlobalAPIWrapper([&] (TTDRecorder& _actionEntryPopper) -> JsErrorCode
  526. {
  527. // Note, some references may live in arena-allocated memory, so we need to do this check
  528. if (!recycler->IsValidObject(ref))
  529. {
  530. return JsNoError;
  531. }
  532. #if ENABLE_TTD
  533. unsigned int lCount = 0;
  534. recycler->RootAddRef(ref, &lCount);
  535. if (count != nullptr)
  536. {
  537. *count = lCount;
  538. }
  539. if((lCount == 1) && (threadContext->IsRuntimeInTTDMode()) && (!threadContext->TTDLog->IsPropertyRecordRef(ref)))
  540. {
  541. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(ref);
  542. if(obj->GetScriptContext()->IsTTDRecordModeEnabled())
  543. {
  544. if(obj->GetScriptContext()->ShouldPerformRecordAction())
  545. {
  546. threadContext->TTDLog->RecordJsRTAddRootRef(_actionEntryPopper, (Js::Var)ref);
  547. }
  548. threadContext->TTDContext->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(obj), obj);
  549. }
  550. }
  551. #else
  552. recycler->RootAddRef(ref, count);
  553. #endif
  554. return JsNoError;
  555. });
  556. }
  557. }
  558. CHAKRA_API JsRelease(_In_ JsRef ref, _Out_opt_ unsigned int *count)
  559. {
  560. VALIDATE_JSREF(ref);
  561. if (count != nullptr)
  562. {
  563. *count = 0;
  564. }
  565. if (Js::TaggedNumber::Is(ref))
  566. {
  567. // The count is always one because these are never collected
  568. if (count)
  569. {
  570. *count = 1;
  571. }
  572. return JsNoError;
  573. }
  574. if (JsrtContext::Is(ref))
  575. {
  576. return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode
  577. {
  578. Recycler * recycler = static_cast<JsrtContext *>(ref)->GetRuntime()->GetThreadContext()->GetRecycler();
  579. recycler->RootRelease(ref, count);
  580. return JsNoError;
  581. });
  582. }
  583. else
  584. {
  585. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  586. if (threadContext == nullptr)
  587. {
  588. return JsErrorNoCurrentContext;
  589. }
  590. Recycler * recycler = threadContext->GetRecycler();
  591. return GlobalAPIWrapper([&](TTDRecorder& _actionEntryPopper) -> JsErrorCode
  592. {
  593. // Note, some references may live in arena-allocated memory, so we need to do this check
  594. if (!recycler->IsValidObject(ref))
  595. {
  596. return JsNoError;
  597. }
  598. recycler->RootRelease(ref, count);
  599. return JsNoError;
  600. });
  601. }
  602. }
  603. CHAKRA_API JsSetObjectBeforeCollectCallback(_In_ JsRef ref, _In_opt_ void *callbackState, _In_ JsObjectBeforeCollectCallback objectBeforeCollectCallback)
  604. {
  605. VALIDATE_JSREF(ref);
  606. if (Js::TaggedNumber::Is(ref))
  607. {
  608. return JsErrorInvalidArgument;
  609. }
  610. if (JsrtContext::Is(ref))
  611. {
  612. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  613. {
  614. ThreadContext* threadContext = static_cast<JsrtContext *>(ref)->GetRuntime()->GetThreadContext();
  615. Recycler * recycler = threadContext->GetRecycler();
  616. recycler->SetObjectBeforeCollectCallback(ref, reinterpret_cast<Recycler::ObjectBeforeCollectCallback>(objectBeforeCollectCallback), callbackState,
  617. reinterpret_cast<Recycler::ObjectBeforeCollectCallbackWrapper>(JsrtCallbackState::ObjectBeforeCallectCallbackWrapper), threadContext);
  618. return JsNoError;
  619. });
  620. }
  621. else
  622. {
  623. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  624. if (threadContext == nullptr)
  625. {
  626. return JsErrorNoCurrentContext;
  627. }
  628. Recycler * recycler = threadContext->GetRecycler();
  629. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  630. {
  631. if (!recycler->IsValidObject(ref))
  632. {
  633. return JsErrorInvalidArgument;
  634. }
  635. recycler->SetObjectBeforeCollectCallback(ref, reinterpret_cast<Recycler::ObjectBeforeCollectCallback>(objectBeforeCollectCallback), callbackState,
  636. reinterpret_cast<Recycler::ObjectBeforeCollectCallbackWrapper>(JsrtCallbackState::ObjectBeforeCallectCallbackWrapper), threadContext);
  637. return JsNoError;
  638. });
  639. }
  640. }
  641. CHAKRA_API JsCreateContext(_In_ JsRuntimeHandle runtimeHandle, _Out_ JsContextRef *newContext)
  642. {
  643. return GlobalAPIWrapper([&](TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  644. PARAM_NOT_NULL(newContext);
  645. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  646. bool inRecord = false;
  647. bool activelyRecording = false;
  648. bool inReplay = false;
  649. #if ENABLE_TTD
  650. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  651. ThreadContext * threadContext = runtime->GetThreadContext();
  652. if(threadContext->IsRuntimeInTTDMode() && threadContext->TTDContext->GetActiveScriptContext() != nullptr)
  653. {
  654. Js::ScriptContext* currentCtx = threadContext->TTDContext->GetActiveScriptContext();
  655. inRecord = currentCtx->IsTTDRecordModeEnabled();
  656. activelyRecording = currentCtx->ShouldPerformRecordAction();
  657. inReplay = currentCtx->IsTTDReplayModeEnabled();
  658. }
  659. #endif
  660. return CreateContextCore(runtimeHandle, _actionEntryPopper, inRecord, activelyRecording, inReplay, newContext);
  661. });
  662. }
  663. CHAKRA_API JsGetCurrentContext(_Out_ JsContextRef *currentContext)
  664. {
  665. PARAM_NOT_NULL(currentContext);
  666. BEGIN_JSRT_NO_EXCEPTION
  667. {
  668. *currentContext = (JsContextRef)JsrtContext::GetCurrent();
  669. }
  670. END_JSRT_NO_EXCEPTION
  671. }
  672. CHAKRA_API JsSetCurrentContext(_In_ JsContextRef newContext)
  673. {
  674. VALIDATE_ENTER_CURRENT_THREAD();
  675. return GlobalAPIWrapper([&] (TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  676. JsrtContext *currentContext = JsrtContext::GetCurrent();
  677. Recycler* recycler = currentContext != nullptr ? currentContext->GetScriptContext()->GetRecycler() : nullptr;
  678. #if ENABLE_TTD
  679. Js::ScriptContext* newScriptContext = newContext != nullptr ? static_cast<JsrtContext*>(newContext)->GetScriptContext() : nullptr;
  680. Js::ScriptContext* oldScriptContext = currentContext != nullptr ? static_cast<JsrtContext*>(currentContext)->GetScriptContext() : nullptr;
  681. if(newScriptContext == nullptr)
  682. {
  683. if(oldScriptContext == nullptr)
  684. {
  685. ; //if newScriptContext and oldScriptContext are null then we don't worry about doing anything
  686. }
  687. else
  688. {
  689. if(oldScriptContext->IsTTDRecordModeEnabled())
  690. {
  691. //already know newScriptContext != oldScriptContext so don't check again
  692. if(oldScriptContext->ShouldPerformRecordAction())
  693. {
  694. oldScriptContext->GetThreadContext()->TTDLog->RecordJsRTSetCurrentContext(_actionEntryPopper, nullptr);
  695. }
  696. oldScriptContext->GetThreadContext()->TTDContext->SetActiveScriptContext(nullptr);
  697. }
  698. }
  699. }
  700. else
  701. {
  702. if(newScriptContext->IsTTDRecordModeEnabled())
  703. {
  704. if(newScriptContext != oldScriptContext && newScriptContext->ShouldPerformRecordAction())
  705. {
  706. newScriptContext->GetThreadContext()->TTDLog->RecordJsRTSetCurrentContext(_actionEntryPopper, newScriptContext->GetGlobalObject());
  707. }
  708. newScriptContext->GetThreadContext()->TTDContext->SetActiveScriptContext(newScriptContext);
  709. }
  710. }
  711. #endif
  712. if (currentContext && recycler->IsHeapEnumInProgress())
  713. {
  714. return JsErrorHeapEnumInProgress;
  715. }
  716. else if (currentContext && currentContext->GetRuntime()->GetThreadContext()->IsInThreadServiceCallback())
  717. {
  718. return JsErrorInThreadServiceCallback;
  719. }
  720. if (!JsrtContext::TrySetCurrent((JsrtContext *)newContext))
  721. {
  722. return JsErrorWrongThread;
  723. }
  724. return JsNoError;
  725. });
  726. }
  727. CHAKRA_API JsGetContextOfObject(_In_ JsValueRef object, _Out_ JsContextRef *context)
  728. {
  729. VALIDATE_JSREF(object);
  730. PARAM_NOT_NULL(context);
  731. BEGIN_JSRT_NO_EXCEPTION
  732. {
  733. if (!Js::RecyclableObject::Is(object))
  734. {
  735. RETURN_NO_EXCEPTION(JsErrorArgumentNotObject);
  736. }
  737. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(object);
  738. *context = (JsContextRef)obj->GetScriptContext()->GetLibrary()->GetJsrtContext();
  739. }
  740. END_JSRT_NO_EXCEPTION
  741. }
  742. CHAKRA_API JsGetContextData(_In_ JsContextRef context, _Out_ void **data)
  743. {
  744. VALIDATE_JSREF(context);
  745. PARAM_NOT_NULL(data);
  746. BEGIN_JSRT_NO_EXCEPTION
  747. {
  748. if (!JsrtContext::Is(context))
  749. {
  750. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  751. }
  752. *data = static_cast<JsrtContext *>(context)->GetExternalData();
  753. }
  754. END_JSRT_NO_EXCEPTION
  755. }
  756. CHAKRA_API JsSetContextData(_In_ JsContextRef context, _In_ void *data)
  757. {
  758. VALIDATE_JSREF(context);
  759. BEGIN_JSRT_NO_EXCEPTION
  760. {
  761. if (!JsrtContext::Is(context))
  762. {
  763. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  764. }
  765. static_cast<JsrtContext *>(context)->SetExternalData(data);
  766. }
  767. END_JSRT_NO_EXCEPTION
  768. }
  769. void HandleScriptCompileError(Js::ScriptContext * scriptContext, CompileScriptException * se, const WCHAR * sourceUrl)
  770. {
  771. HRESULT hr = se->ei.scode;
  772. if (hr == E_OUTOFMEMORY || hr == VBSERR_OutOfMemory || hr == VBSERR_OutOfStack || hr == ERRnoMemory)
  773. {
  774. Js::Throw::OutOfMemory();
  775. }
  776. Js::JavascriptError* error = Js::JavascriptError::CreateFromCompileScriptException(scriptContext, se, sourceUrl);
  777. Js::JavascriptExceptionObject * exceptionObject = RecyclerNew(scriptContext->GetRecycler(),
  778. Js::JavascriptExceptionObject, error, scriptContext, nullptr);
  779. scriptContext->GetThreadContext()->SetRecordedException(exceptionObject);
  780. }
  781. CHAKRA_API JsGetUndefinedValue(_Out_ JsValueRef *undefinedValue)
  782. {
  783. return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
  784. PARAM_NOT_NULL(undefinedValue);
  785. *undefinedValue = scriptContext->GetLibrary()->GetUndefined();
  786. return JsNoError;
  787. },
  788. /*allowInObjectBeforeCollectCallback*/true);
  789. }
  790. CHAKRA_API JsGetNullValue(_Out_ JsValueRef *nullValue)
  791. {
  792. return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
  793. PARAM_NOT_NULL(nullValue);
  794. *nullValue = scriptContext->GetLibrary()->GetNull();
  795. return JsNoError;
  796. },
  797. /*allowInObjectBeforeCollectCallback*/true);
  798. }
  799. CHAKRA_API JsGetTrueValue(_Out_ JsValueRef *trueValue)
  800. {
  801. return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
  802. PARAM_NOT_NULL(trueValue);
  803. *trueValue = scriptContext->GetLibrary()->GetTrue();
  804. return JsNoError;
  805. },
  806. /*allowInObjectBeforeCollectCallback*/true);
  807. }
  808. CHAKRA_API JsGetFalseValue(_Out_ JsValueRef *falseValue)
  809. {
  810. return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext *scriptContext) -> JsErrorCode {
  811. PARAM_NOT_NULL(falseValue);
  812. *falseValue = scriptContext->GetLibrary()->GetFalse();
  813. return JsNoError;
  814. },
  815. /*allowInObjectBeforeCollectCallback*/true);
  816. }
  817. CHAKRA_API JsBoolToBoolean(_In_ bool value, _Out_ JsValueRef *booleanValue)
  818. {
  819. return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  820. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateBoolean, value);
  821. PARAM_NOT_NULL(booleanValue);
  822. *booleanValue = value ? scriptContext->GetLibrary()->GetTrue() : scriptContext->GetLibrary()->GetFalse();
  823. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, booleanValue);
  824. return JsNoError;
  825. },
  826. /*allowInObjectBeforeCollectCallback*/true);
  827. }
  828. CHAKRA_API JsBooleanToBool(_In_ JsValueRef value, _Out_ bool *boolValue)
  829. {
  830. VALIDATE_JSREF(value);
  831. PARAM_NOT_NULL(boolValue);
  832. BEGIN_JSRT_NO_EXCEPTION
  833. {
  834. if (!Js::JavascriptBoolean::Is(value))
  835. {
  836. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  837. }
  838. *boolValue = Js::JavascriptBoolean::FromVar(value)->GetValue() ? true : false;
  839. }
  840. END_JSRT_NO_EXCEPTION
  841. }
  842. CHAKRA_API JsConvertValueToBoolean(_In_ JsValueRef value, _Out_ JsValueRef *result)
  843. {
  844. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  845. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToBooleanConversion, (Js::Var)value);
  846. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  847. PARAM_NOT_NULL(result);
  848. if (Js::JavascriptConversion::ToBool((Js::Var)value, scriptContext))
  849. {
  850. *result = scriptContext->GetLibrary()->GetTrue();
  851. }
  852. else
  853. {
  854. *result = scriptContext->GetLibrary()->GetFalse();
  855. }
  856. //It is either true or false which we always track so no need to store result identity
  857. return JsNoError;
  858. });
  859. }
  860. CHAKRA_API JsGetValueType(_In_ JsValueRef value, _Out_ JsValueType *type)
  861. {
  862. VALIDATE_JSREF(value);
  863. PARAM_NOT_NULL(type);
  864. BEGIN_JSRT_NO_EXCEPTION
  865. {
  866. Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(value);
  867. switch (typeId)
  868. {
  869. case Js::TypeIds_Undefined:
  870. *type = JsUndefined;
  871. break;
  872. case Js::TypeIds_Null:
  873. *type = JsNull;
  874. break;
  875. case Js::TypeIds_Boolean:
  876. *type = JsBoolean;
  877. break;
  878. case Js::TypeIds_Integer:
  879. case Js::TypeIds_Number:
  880. case Js::TypeIds_Int64Number:
  881. case Js::TypeIds_UInt64Number:
  882. *type = JsNumber;
  883. break;
  884. case Js::TypeIds_String:
  885. *type = JsString;
  886. break;
  887. case Js::TypeIds_Function:
  888. *type = JsFunction;
  889. break;
  890. case Js::TypeIds_Error:
  891. *type = JsError;
  892. break;
  893. case Js::TypeIds_Array:
  894. case Js::TypeIds_NativeIntArray:
  895. #if ENABLE_COPYONACCESS_ARRAY
  896. case Js::TypeIds_CopyOnAccessNativeIntArray:
  897. #endif
  898. case Js::TypeIds_NativeFloatArray:
  899. case Js::TypeIds_ES5Array:
  900. *type = JsArray;
  901. break;
  902. case Js::TypeIds_Symbol:
  903. *type = JsSymbol;
  904. break;
  905. case Js::TypeIds_ArrayBuffer:
  906. *type = JsArrayBuffer;
  907. break;
  908. case Js::TypeIds_DataView:
  909. *type = JsDataView;
  910. break;
  911. default:
  912. if (Js::TypedArrayBase::Is(typeId))
  913. {
  914. *type = JsTypedArray;
  915. }
  916. else
  917. {
  918. *type = JsObject;
  919. }
  920. break;
  921. }
  922. }
  923. END_JSRT_NO_EXCEPTION
  924. }
  925. CHAKRA_API JsDoubleToNumber(_In_ double dbl, _Out_ JsValueRef *asValue)
  926. {
  927. PARAM_NOT_NULL(asValue);
  928. //If number is not heap allocated then we don't need to record/track the creation for time-travel
  929. if (Js::JavascriptNumber::TryToVarFastWithCheck(dbl, asValue))
  930. {
  931. return JsNoError;
  932. }
  933. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  934. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateNumber, dbl);
  935. *asValue = Js::JavascriptNumber::ToVarNoCheck(dbl, scriptContext);
  936. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, asValue);
  937. return JsNoError;
  938. });
  939. }
  940. CHAKRA_API JsIntToNumber(_In_ int intValue, _Out_ JsValueRef *asValue)
  941. {
  942. PARAM_NOT_NULL(asValue);
  943. //If number is not heap allocated then we don't need to record/track the creation for time-travel
  944. if (Js::JavascriptNumber::TryToVarFast(intValue, asValue))
  945. {
  946. return JsNoError;
  947. }
  948. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  949. #if !INT32VAR
  950. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateInteger, intValue);
  951. #endif
  952. *asValue = Js::JavascriptNumber::ToVar(intValue, scriptContext);
  953. #if !INT32VAR
  954. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, asValue);
  955. #endif
  956. return JsNoError;
  957. });
  958. }
  959. CHAKRA_API JsNumberToDouble(_In_ JsValueRef value, _Out_ double *asDouble)
  960. {
  961. VALIDATE_JSREF(value);
  962. PARAM_NOT_NULL(asDouble);
  963. BEGIN_JSRT_NO_EXCEPTION
  964. {
  965. if (Js::TaggedInt::Is(value))
  966. {
  967. *asDouble = Js::TaggedInt::ToDouble(value);
  968. }
  969. else if (Js::JavascriptNumber::Is_NoTaggedIntCheck(value))
  970. {
  971. *asDouble = Js::JavascriptNumber::GetValue(value);
  972. }
  973. else
  974. {
  975. *asDouble = 0;
  976. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  977. }
  978. }
  979. END_JSRT_NO_EXCEPTION
  980. }
  981. CHAKRA_API JsNumberToInt(_In_ JsValueRef value, _Out_ int *asInt)
  982. {
  983. VALIDATE_JSREF(value);
  984. PARAM_NOT_NULL(asInt);
  985. BEGIN_JSRT_NO_EXCEPTION
  986. {
  987. if (Js::TaggedInt::Is(value))
  988. {
  989. *asInt = Js::TaggedInt::ToInt32(value);
  990. }
  991. else if (Js::JavascriptNumber::Is_NoTaggedIntCheck(value))
  992. {
  993. *asInt = Js::JavascriptConversion::ToInt32(Js::JavascriptNumber::GetValue(value));
  994. }
  995. else
  996. {
  997. *asInt = 0;
  998. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  999. }
  1000. }
  1001. END_JSRT_NO_EXCEPTION
  1002. }
  1003. CHAKRA_API JsConvertValueToNumber(_In_ JsValueRef value, _Out_ JsValueRef *result)
  1004. {
  1005. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1006. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToNumberConversion, (Js::Var)value);
  1007. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  1008. PARAM_NOT_NULL(result);
  1009. *result = (JsValueRef)Js::JavascriptOperators::ToNumber((Js::Var)value, scriptContext);
  1010. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1011. return JsNoError;
  1012. });
  1013. }
  1014. CHAKRA_API JsGetStringLength(_In_ JsValueRef value, _Out_ int *length)
  1015. {
  1016. VALIDATE_JSREF(value);
  1017. PARAM_NOT_NULL(length);
  1018. BEGIN_JSRT_NO_EXCEPTION
  1019. {
  1020. if (!Js::JavascriptString::Is(value))
  1021. {
  1022. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  1023. }
  1024. *length = Js::JavascriptString::FromVar(value)->GetLengthAsSignedInt();
  1025. }
  1026. END_JSRT_NO_EXCEPTION
  1027. }
  1028. CHAKRA_API JsPointerToString(_In_reads_(stringLength) const WCHAR *stringValue, _In_ size_t stringLength, _Out_ JsValueRef *string)
  1029. {
  1030. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1031. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue, stringLength);
  1032. PARAM_NOT_NULL(stringValue);
  1033. PARAM_NOT_NULL(string);
  1034. if (!Js::IsValidCharCount(stringLength))
  1035. {
  1036. Js::JavascriptError::ThrowOutOfMemoryError(scriptContext);
  1037. }
  1038. *string = Js::JavascriptString::NewCopyBuffer(stringValue, static_cast<charcount_t>(stringLength), scriptContext);
  1039. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, string);
  1040. return JsNoError;
  1041. });
  1042. }
  1043. // TODO: The annotation of stringPtr is wrong. Need to fix definition in chakrart.h
  1044. // The warning is '*stringPtr' could be '0' : this does not adhere to the specification for the function 'JsStringToPointer'.
  1045. #pragma warning(suppress:6387)
  1046. CHAKRA_API JsStringToPointer(_In_ JsValueRef stringValue, _Outptr_result_buffer_(*stringLength) const WCHAR **stringPtr, _Out_ size_t *stringLength)
  1047. {
  1048. VALIDATE_JSREF(stringValue);
  1049. PARAM_NOT_NULL(stringPtr);
  1050. *stringPtr = nullptr;
  1051. PARAM_NOT_NULL(stringLength);
  1052. *stringLength = 0;
  1053. if (!Js::JavascriptString::Is(stringValue))
  1054. {
  1055. return JsErrorInvalidArgument;
  1056. }
  1057. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  1058. Js::JavascriptString *jsString = Js::JavascriptString::FromVar(stringValue);
  1059. *stringPtr = jsString->GetSz();
  1060. *stringLength = jsString->GetLength();
  1061. return JsNoError;
  1062. });
  1063. }
  1064. CHAKRA_API JsConvertValueToString(_In_ JsValueRef value, _Out_ JsValueRef *result)
  1065. {
  1066. PARAM_NOT_NULL(result);
  1067. *result = nullptr;
  1068. if (value != nullptr && Js::JavascriptString::Is(value))
  1069. {
  1070. return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  1071. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  1072. *result = value;
  1073. return JsNoError;
  1074. });
  1075. }
  1076. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1077. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToStringConversion, (Js::Var)value);
  1078. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  1079. *result = (JsValueRef) Js::JavascriptConversion::ToString((Js::Var)value, scriptContext);
  1080. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1081. return JsNoError;
  1082. });
  1083. }
  1084. CHAKRA_API JsGetGlobalObject(_Out_ JsValueRef *globalObject)
  1085. {
  1086. return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  1087. PARAM_NOT_NULL(globalObject);
  1088. *globalObject = (JsValueRef)scriptContext->GetGlobalObject();
  1089. return JsNoError;
  1090. },
  1091. /*allowInObjectBeforeCollectCallback*/true);
  1092. }
  1093. CHAKRA_API JsCreateObject(_Out_ JsValueRef *object)
  1094. {
  1095. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1096. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateBasicObject);
  1097. PARAM_NOT_NULL(object);
  1098. *object = scriptContext->GetLibrary()->CreateObject();
  1099. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object);
  1100. return JsNoError;
  1101. });
  1102. }
  1103. CHAKRA_API JsCreateExternalObject(_In_opt_ void *data, _In_opt_ JsFinalizeCallback finalizeCallback, _Out_ JsValueRef *object)
  1104. {
  1105. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1106. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateExternalObject);
  1107. PARAM_NOT_NULL(object);
  1108. *object = JsrtExternalObject::Create(data, finalizeCallback, scriptContext);
  1109. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, object);
  1110. return JsNoError;
  1111. });
  1112. }
  1113. CHAKRA_API JsConvertValueToObject(_In_ JsValueRef value, _Out_ JsValueRef *result)
  1114. {
  1115. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1116. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTVarToObjectConversion, (Js::Var)value);
  1117. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  1118. PARAM_NOT_NULL(result);
  1119. *result = (JsValueRef)Js::JavascriptOperators::ToObject((Js::Var)value, scriptContext);
  1120. Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
  1121. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1122. return JsNoError;
  1123. });
  1124. }
  1125. CHAKRA_API JsGetPrototype(_In_ JsValueRef object, _Out_ JsValueRef *prototypeObject)
  1126. {
  1127. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1128. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetPrototype, object);
  1129. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1130. PARAM_NOT_NULL(prototypeObject);
  1131. *prototypeObject = (JsValueRef)Js::JavascriptOperators::OP_GetPrototype(object, scriptContext);
  1132. Assert(*prototypeObject == nullptr || !Js::CrossSite::NeedMarshalVar(*prototypeObject, scriptContext));
  1133. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, prototypeObject);
  1134. return JsNoError;
  1135. });
  1136. }
  1137. CHAKRA_API JsSetPrototype(_In_ JsValueRef object, _In_ JsValueRef prototypeObject)
  1138. {
  1139. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1140. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetPrototype, object, prototypeObject);
  1141. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1142. VALIDATE_INCOMING_OBJECT_OR_NULL(prototypeObject, scriptContext);
  1143. // We're not allowed to set this.
  1144. if (object == scriptContext->GetLibrary()->GetObjectPrototype())
  1145. {
  1146. return JsErrorInvalidArgument;
  1147. }
  1148. Js::JavascriptObject::ChangePrototype(Js::RecyclableObject::FromVar(object), Js::RecyclableObject::FromVar(prototypeObject), true, scriptContext);
  1149. return JsNoError;
  1150. });
  1151. }
  1152. CHAKRA_API JsInstanceOf(_In_ JsValueRef object, _In_ JsValueRef constructor, _Out_ bool *result) {
  1153. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1154. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTInstanceOf, object, constructor);
  1155. VALIDATE_INCOMING_REFERENCE(object, scriptContext);
  1156. VALIDATE_INCOMING_REFERENCE(constructor, scriptContext);
  1157. PARAM_NOT_NULL(result);
  1158. *result = Js::RecyclableObject::FromVar(constructor)->HasInstance(object, scriptContext) ? true : false;
  1159. return JsNoError;
  1160. });
  1161. }
  1162. CHAKRA_API JsGetExtensionAllowed(_In_ JsValueRef object, _Out_ bool *value)
  1163. {
  1164. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1165. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  1166. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1167. PARAM_NOT_NULL(value);
  1168. *value = false;
  1169. *value = Js::RecyclableObject::FromVar(object)->IsExtensible() != 0;
  1170. return JsNoError;
  1171. });
  1172. }
  1173. CHAKRA_API JsPreventExtension(_In_ JsValueRef object)
  1174. {
  1175. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1176. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  1177. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1178. Js::RecyclableObject::FromVar(object)->PreventExtensions();
  1179. return JsNoError;
  1180. });
  1181. }
  1182. CHAKRA_API JsHasOwnPropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
  1183. _In_ const Js::PropertyRecord * propertyRecord, _Out_ bool *hasOwnProperty,
  1184. TTDRecorder& _actionEntryPopper)
  1185. {
  1186. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasOwnProperty, propertyRecord, object);
  1187. *hasOwnProperty = Js::JavascriptOperators::OP_HasOwnProperty(object,
  1188. propertyRecord->GetPropertyId(), scriptContext) != 0;
  1189. return JsNoError;
  1190. }
  1191. CHAKRA_API JsHasOwnProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId,
  1192. _Out_ bool *hasOwnProperty)
  1193. {
  1194. return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext,
  1195. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1196. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1197. VALIDATE_INCOMING_PROPERTYID(propertyId);
  1198. PARAM_NOT_NULL(hasOwnProperty);
  1199. *hasOwnProperty = false;
  1200. return JsHasOwnPropertyCommon(scriptContext, object,
  1201. (const Js::PropertyRecord *)propertyId, hasOwnProperty, _actionEntryPopper);
  1202. });
  1203. }
  1204. #ifdef _CHAKRACOREBUILD
  1205. static JsErrorCode InternalGetPropertyRecord(Js::ScriptContext * scriptContext,
  1206. Js::RecyclableObject * key, _Out_ const Js::PropertyRecord ** propertyRecord)
  1207. {
  1208. Assert(propertyRecord != nullptr);
  1209. *propertyRecord = nullptr;
  1210. if (key->GetTypeId() != Js::TypeIds_String)
  1211. {
  1212. return JsErrorInvalidArgument;
  1213. }
  1214. scriptContext->GetOrAddPropertyRecord(Js::JavascriptString::FromVar(key),
  1215. (Js::PropertyRecord const **)propertyRecord);
  1216. return JsNoError;
  1217. }
  1218. CHAKRA_API JsObjectHasOwnProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ bool *hasOwnProperty)
  1219. {
  1220. return ContextAPIWrapper<true>([&] (Js::ScriptContext *scriptContext,
  1221. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1222. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1223. VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
  1224. PARAM_NOT_NULL(hasOwnProperty);
  1225. *hasOwnProperty = false;
  1226. const Js::PropertyRecord *propertyRecord = nullptr;
  1227. JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
  1228. Js::RecyclableObject::FromVar(propertyId), &propertyRecord);
  1229. if (errorValue != JsNoError)
  1230. {
  1231. return errorValue;
  1232. }
  1233. return JsHasOwnPropertyCommon(scriptContext, object, propertyRecord, hasOwnProperty, _actionEntryPopper);
  1234. });
  1235. }
  1236. #endif
  1237. static JsErrorCode JsGetPropertyCommon(Js::ScriptContext * scriptContext,
  1238. _In_ Js::RecyclableObject * object,
  1239. _In_ const Js::PropertyRecord * propertyRecord, _Out_ JsValueRef *value,
  1240. TTDRecorder& _actionEntryPopper)
  1241. {
  1242. AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
  1243. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetProperty, propertyRecord, object);
  1244. *value = Js::JavascriptOperators::GetPropertyNoCache(object, propertyRecord->GetPropertyId(), scriptContext);
  1245. Assert(*value == nullptr || !Js::CrossSite::NeedMarshalVar(*value, scriptContext));
  1246. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value);
  1247. return JsNoError;
  1248. }
  1249. CHAKRA_API JsGetProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *value)
  1250. {
  1251. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1252. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1253. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1254. VALIDATE_INCOMING_PROPERTYID(propertyId);
  1255. PARAM_NOT_NULL(value);
  1256. *value = nullptr;
  1257. Js::RecyclableObject * instance = Js::RecyclableObject::FromVar(object);
  1258. return JsGetPropertyCommon(scriptContext, instance, (const Js::PropertyRecord *)propertyId,
  1259. value, _actionEntryPopper);
  1260. });
  1261. }
  1262. #ifdef _CHAKRACOREBUILD
  1263. CHAKRA_API JsObjectGetProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ JsValueRef *value)
  1264. {
  1265. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1266. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1267. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1268. VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
  1269. PARAM_NOT_NULL(value);
  1270. *value = nullptr;
  1271. const Js::PropertyRecord *propertyRecord = nullptr;
  1272. JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
  1273. Js::RecyclableObject::FromVar(propertyId), &propertyRecord);
  1274. if (errorValue != JsNoError)
  1275. {
  1276. return errorValue;
  1277. }
  1278. Assert(propertyRecord != nullptr);
  1279. Js::RecyclableObject * instance = Js::RecyclableObject::FromVar(object);
  1280. return JsGetPropertyCommon(scriptContext, instance, propertyRecord, value, _actionEntryPopper);
  1281. });
  1282. }
  1283. #endif
  1284. static JsErrorCode JsGetOwnPropertyDescriptorCommon(Js::ScriptContext * scriptContext,
  1285. _In_ JsValueRef object, _In_ const Js::PropertyRecord * propertyRecord, _Out_ JsValueRef *propertyDescriptor,
  1286. TTDRecorder& _actionEntryPopper)
  1287. {
  1288. AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
  1289. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetOwnPropertyInfo, propertyRecord, object);
  1290. Js::PropertyDescriptor propertyDescriptorValue;
  1291. if (Js::JavascriptOperators::GetOwnPropertyDescriptor(Js::RecyclableObject::FromVar(object),
  1292. propertyRecord->GetPropertyId(), scriptContext, &propertyDescriptorValue))
  1293. {
  1294. *propertyDescriptor = Js::JavascriptOperators::FromPropertyDescriptor(propertyDescriptorValue, scriptContext);
  1295. }
  1296. else
  1297. {
  1298. *propertyDescriptor = scriptContext->GetLibrary()->GetUndefined();
  1299. }
  1300. Assert(*propertyDescriptor == nullptr || !Js::CrossSite::NeedMarshalVar(*propertyDescriptor, scriptContext));
  1301. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, propertyDescriptor);
  1302. return JsNoError;
  1303. }
  1304. CHAKRA_API JsGetOwnPropertyDescriptor(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *propertyDescriptor)
  1305. {
  1306. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1307. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1308. VALIDATE_INCOMING_PROPERTYID(propertyId);
  1309. PARAM_NOT_NULL(propertyDescriptor);
  1310. *propertyDescriptor = nullptr;
  1311. return JsGetOwnPropertyDescriptorCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
  1312. propertyDescriptor, _actionEntryPopper);
  1313. });
  1314. }
  1315. #ifdef _CHAKRACOREBUILD
  1316. CHAKRA_API JsObjectGetOwnPropertyDescriptor(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ JsValueRef *propertyDescriptor)
  1317. {
  1318. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1319. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1320. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1321. VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
  1322. PARAM_NOT_NULL(propertyDescriptor);
  1323. *propertyDescriptor = nullptr;
  1324. const Js::PropertyRecord *propertyRecord = nullptr;
  1325. JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
  1326. Js::RecyclableObject::FromVar(propertyId), &propertyRecord);
  1327. if (errorValue != JsNoError)
  1328. {
  1329. return errorValue;
  1330. }
  1331. Assert(propertyRecord != nullptr);
  1332. return JsGetOwnPropertyDescriptorCommon(scriptContext, object, propertyRecord, propertyDescriptor, _actionEntryPopper);
  1333. });
  1334. }
  1335. #endif
  1336. static JsErrorCode JsSetPropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
  1337. _In_ const Js::PropertyRecord * propertyRecord, _In_ JsValueRef value, _In_ bool useStrictRules,
  1338. TTDRecorder& _actionEntryPopper)
  1339. {
  1340. AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
  1341. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetProperty, object,
  1342. propertyRecord, value, useStrictRules);
  1343. Js::JavascriptOperators::OP_SetProperty(object, propertyRecord->GetPropertyId(),
  1344. value, scriptContext, nullptr, useStrictRules ? Js::PropertyOperation_StrictMode : Js::PropertyOperation_None);
  1345. return JsNoError;
  1346. }
  1347. CHAKRA_API JsSetProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _In_ JsValueRef value, _In_ bool useStrictRules)
  1348. {
  1349. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1350. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1351. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1352. VALIDATE_INCOMING_PROPERTYID(propertyId);
  1353. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  1354. return JsSetPropertyCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
  1355. value, useStrictRules, _actionEntryPopper);
  1356. });
  1357. }
  1358. #ifdef _CHAKRACOREBUILD
  1359. CHAKRA_API JsObjectSetProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _In_ JsValueRef value, _In_ bool useStrictRules)
  1360. {
  1361. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1362. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1363. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1364. VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
  1365. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  1366. const Js::PropertyRecord *propertyRecord = nullptr;
  1367. JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
  1368. Js::RecyclableObject::FromVar(propertyId), &propertyRecord);
  1369. if (errorValue != JsNoError)
  1370. {
  1371. return errorValue;
  1372. }
  1373. Assert(propertyRecord != nullptr);
  1374. return JsSetPropertyCommon(scriptContext, object, propertyRecord, value, useStrictRules, _actionEntryPopper);
  1375. });
  1376. }
  1377. #endif
  1378. CHAKRA_API JsHasProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId, _Out_ bool *hasProperty)
  1379. {
  1380. VALIDATE_JSREF(object);
  1381. if (!Js::JavascriptOperators::IsObject(object)) return JsErrorArgumentNotObject;
  1382. auto internalHasProperty = [&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1383. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasProperty, (Js::PropertyRecord *)propertyId, object);
  1384. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1385. VALIDATE_INCOMING_PROPERTYID(propertyId);
  1386. PARAM_NOT_NULL(hasProperty);
  1387. *hasProperty = false;
  1388. Js::RecyclableObject * instance = Js::RecyclableObject::FromVar(object);
  1389. *hasProperty = Js::JavascriptOperators::HasProperty(instance, ((Js::PropertyRecord *)propertyId)->GetPropertyId()) != 0;
  1390. return JsNoError;
  1391. };
  1392. Js::RecyclableObject* robject = Js::RecyclableObject::FromVar(object);
  1393. Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(robject);
  1394. while (typeId != Js::TypeIds_Null && typeId != Js::TypeIds_Proxy)
  1395. {
  1396. robject = robject->GetPrototype();
  1397. typeId = Js::JavascriptOperators::GetTypeId(robject);
  1398. }
  1399. if (typeId == Js::TypeIds_Proxy)
  1400. {
  1401. return ContextAPIWrapper<JSRT_MAYBE_TRUE>(internalHasProperty);
  1402. }
  1403. else
  1404. {
  1405. return ContextAPINoScriptWrapper(internalHasProperty);
  1406. }
  1407. }
  1408. #ifdef _CHAKRACOREBUILD
  1409. CHAKRA_API JsObjectHasProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId, _Out_ bool *hasProperty)
  1410. {
  1411. VALIDATE_JSREF(object);
  1412. if (!Js::JavascriptOperators::IsObject(object)) return JsErrorArgumentNotObject;
  1413. auto internalHasProperty = [&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1414. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1415. VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
  1416. PARAM_NOT_NULL(hasProperty);
  1417. *hasProperty = false;
  1418. const Js::PropertyRecord *propertyRecord = nullptr;
  1419. JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
  1420. Js::RecyclableObject::FromVar(propertyId), &propertyRecord);
  1421. if (errorValue != JsNoError)
  1422. {
  1423. return errorValue;
  1424. }
  1425. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHasProperty, propertyRecord, object);
  1426. Js::RecyclableObject * instance = Js::RecyclableObject::FromVar(object);
  1427. *hasProperty = Js::JavascriptOperators::HasProperty(instance, propertyRecord->GetPropertyId()) != 0;
  1428. return JsNoError;
  1429. };
  1430. Js::RecyclableObject* robject = Js::RecyclableObject::FromVar(object);
  1431. Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(robject);
  1432. while (typeId != Js::TypeIds_Null && typeId != Js::TypeIds_Proxy)
  1433. {
  1434. robject = robject->GetPrototype();
  1435. typeId = Js::JavascriptOperators::GetTypeId(robject);
  1436. }
  1437. if (typeId == Js::TypeIds_Proxy)
  1438. {
  1439. return ContextAPIWrapper<JSRT_MAYBE_TRUE>(internalHasProperty);
  1440. }
  1441. else
  1442. {
  1443. return ContextAPINoScriptWrapper(internalHasProperty);
  1444. }
  1445. }
  1446. #endif
  1447. static JsErrorCode JsDeletePropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
  1448. _In_ const Js::PropertyRecord * propertyRecord, _In_ bool useStrictRules, _Out_ JsValueRef *result,
  1449. TTDRecorder& _actionEntryPopper)
  1450. {
  1451. AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
  1452. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTDeleteProperty, object,
  1453. propertyRecord, useStrictRules);
  1454. *result = Js::JavascriptOperators::OP_DeleteProperty((Js::Var)object,
  1455. propertyRecord->GetPropertyId(),
  1456. scriptContext, useStrictRules ? Js::PropertyOperation_StrictMode : Js::PropertyOperation_None);
  1457. Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
  1458. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1459. return JsNoError;
  1460. }
  1461. CHAKRA_API JsDeleteProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId,
  1462. _In_ bool useStrictRules, _Out_ JsValueRef *result)
  1463. {
  1464. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1465. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1466. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1467. VALIDATE_INCOMING_PROPERTYID(propertyId);
  1468. PARAM_NOT_NULL(result);
  1469. *result = nullptr;
  1470. return JsDeletePropertyCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
  1471. useStrictRules, result, _actionEntryPopper);
  1472. });
  1473. }
  1474. #ifdef _CHAKRACOREBUILD
  1475. CHAKRA_API JsObjectDeleteProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId,
  1476. _In_ bool useStrictRules, _Out_ JsValueRef *result)
  1477. {
  1478. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1479. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1480. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1481. VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
  1482. PARAM_NOT_NULL(result);
  1483. *result = nullptr;
  1484. const Js::PropertyRecord *propertyRecord = nullptr;
  1485. JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
  1486. Js::RecyclableObject::FromVar(propertyId), &propertyRecord);
  1487. if (errorValue != JsNoError)
  1488. {
  1489. return errorValue;
  1490. }
  1491. Assert(propertyRecord != nullptr);
  1492. return JsDeletePropertyCommon(scriptContext, object, propertyRecord,
  1493. useStrictRules, result, _actionEntryPopper);
  1494. });
  1495. }
  1496. #endif
  1497. static JsErrorCode JsDefinePropertyCommon(Js::ScriptContext * scriptContext, _In_ JsValueRef object,
  1498. _In_ const Js::PropertyRecord *propertyRecord, _In_ JsValueRef propertyDescriptor,
  1499. _Out_ bool *result, TTDRecorder& _actionEntryPopper)
  1500. {
  1501. AssertMsg(scriptContext->GetThreadContext()->IsScriptActive(), "Caller is expected to be under ContextAPIWrapper!");
  1502. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTDefineProperty, object,
  1503. propertyRecord, propertyDescriptor);
  1504. Js::PropertyDescriptor propertyDescriptorValue;
  1505. if (!Js::JavascriptOperators::ToPropertyDescriptor(propertyDescriptor, &propertyDescriptorValue, scriptContext))
  1506. {
  1507. return JsErrorInvalidArgument;
  1508. }
  1509. *result = Js::JavascriptOperators::DefineOwnPropertyDescriptor(
  1510. Js::RecyclableObject::FromVar(object), propertyRecord->GetPropertyId(),
  1511. propertyDescriptorValue, true, scriptContext) != 0;
  1512. return JsNoError;
  1513. }
  1514. CHAKRA_API JsDefineProperty(_In_ JsValueRef object, _In_ JsPropertyIdRef propertyId,
  1515. _In_ JsValueRef propertyDescriptor, _Out_ bool *result)
  1516. {
  1517. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1518. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1519. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1520. VALIDATE_INCOMING_PROPERTYID(propertyId);
  1521. VALIDATE_INCOMING_OBJECT(propertyDescriptor, scriptContext);
  1522. PARAM_NOT_NULL(result);
  1523. *result = false;
  1524. return JsDefinePropertyCommon(scriptContext, object, (const Js::PropertyRecord *)propertyId,
  1525. propertyDescriptor, result, _actionEntryPopper);
  1526. });
  1527. }
  1528. #ifdef _CHAKRACOREBUILD
  1529. CHAKRA_API JsObjectDefineProperty(_In_ JsValueRef object, _In_ JsValueRef propertyId,
  1530. _In_ JsValueRef propertyDescriptor, _Out_ bool *result)
  1531. {
  1532. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext,
  1533. TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1534. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1535. VALIDATE_INCOMING_RECYCLABLE(propertyId, scriptContext);
  1536. VALIDATE_INCOMING_OBJECT(propertyDescriptor, scriptContext);
  1537. PARAM_NOT_NULL(result);
  1538. *result = false;
  1539. const Js::PropertyRecord *propertyRecord = nullptr;
  1540. JsErrorCode errorValue = InternalGetPropertyRecord(scriptContext,
  1541. Js::RecyclableObject::FromVar(propertyId), &propertyRecord);
  1542. if (errorValue != JsNoError)
  1543. {
  1544. return errorValue;
  1545. }
  1546. return JsDefinePropertyCommon(scriptContext, object, propertyRecord, propertyDescriptor, result, _actionEntryPopper);
  1547. });
  1548. }
  1549. #endif
  1550. CHAKRA_API JsGetOwnPropertyNames(_In_ JsValueRef object, _Out_ JsValueRef *propertyNames)
  1551. {
  1552. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1553. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetOwnPropertyNamesInfo, object);
  1554. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1555. PARAM_NOT_NULL(propertyNames);
  1556. *propertyNames = nullptr;
  1557. *propertyNames = Js::JavascriptOperators::GetOwnPropertyNames(object, scriptContext);
  1558. Assert(*propertyNames == nullptr || !Js::CrossSite::NeedMarshalVar(*propertyNames, scriptContext));
  1559. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, propertyNames);
  1560. return JsNoError;
  1561. });
  1562. }
  1563. CHAKRA_API JsGetOwnPropertySymbols(_In_ JsValueRef object, _Out_ JsValueRef *propertySymbols)
  1564. {
  1565. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1566. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetOwnPropertySymbolsInfo, object);
  1567. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1568. PARAM_NOT_NULL(propertySymbols);
  1569. *propertySymbols = Js::JavascriptOperators::GetOwnPropertySymbols(object, scriptContext);
  1570. Assert(*propertySymbols == nullptr || !Js::CrossSite::NeedMarshalVar(*propertySymbols, scriptContext));
  1571. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, propertySymbols);
  1572. return JsNoError;
  1573. });
  1574. }
  1575. CHAKRA_API JsCreateArray(_In_ unsigned int length, _Out_ JsValueRef *result)
  1576. {
  1577. return ContextAPINoScriptWrapper([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1578. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateBasicArray, length);
  1579. PARAM_NOT_NULL(result);
  1580. *result = nullptr;
  1581. *result = scriptContext->GetLibrary()->CreateArray(length);
  1582. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1583. return JsNoError;
  1584. });
  1585. }
  1586. CHAKRA_API JsCreateArrayBuffer(_In_ unsigned int byteLength, _Out_ JsValueRef *result)
  1587. {
  1588. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1589. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateArrayBuffer, byteLength);
  1590. PARAM_NOT_NULL(result);
  1591. Js::JavascriptLibrary* library = scriptContext->GetLibrary();
  1592. *result = library->CreateArrayBuffer(byteLength);
  1593. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1594. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
  1595. return JsNoError;
  1596. });
  1597. }
  1598. #ifdef _CHAKRACOREBUILD
  1599. CHAKRA_API JsCreateSharedArrayBufferWithSharedContent(_In_ JsSharedArrayBufferContentHandle sharedContents, _Out_ JsValueRef *result)
  1600. {
  1601. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1602. PARAM_NOT_NULL(result);
  1603. Js::JavascriptLibrary* library = scriptContext->GetLibrary();
  1604. *result = library->CreateSharedArrayBuffer((Js::SharedContents*)sharedContents);
  1605. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1606. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
  1607. return JsNoError;
  1608. });
  1609. }
  1610. CHAKRA_API JsGetSharedArrayBufferContent(_In_ JsValueRef sharedArrayBuffer, _Out_ JsSharedArrayBufferContentHandle *sharedContents)
  1611. {
  1612. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1613. PARAM_NOT_NULL(sharedContents);
  1614. if (!Js::SharedArrayBuffer::Is(sharedArrayBuffer))
  1615. {
  1616. return JsErrorInvalidArgument;
  1617. }
  1618. Js::SharedContents**& content = (Js::SharedContents**&)sharedContents;
  1619. *content = Js::SharedArrayBuffer::FromVar(sharedArrayBuffer)->GetSharedContents();
  1620. if (*content == nullptr)
  1621. {
  1622. return JsErrorFatal;
  1623. }
  1624. (*content)->AddRef();
  1625. return JsNoError;
  1626. });
  1627. }
  1628. CHAKRA_API JsReleaseSharedArrayBufferContentHandle(_In_ JsSharedArrayBufferContentHandle sharedContents)
  1629. {
  1630. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1631. ((Js::SharedContents*)sharedContents)->Release();
  1632. return JsNoError;
  1633. });
  1634. }
  1635. #endif // _CHAKRACOREBUILD
  1636. CHAKRA_API JsCreateExternalArrayBuffer(_Pre_maybenull_ _Pre_writable_byte_size_(byteLength) void *data, _In_ unsigned int byteLength,
  1637. _In_opt_ JsFinalizeCallback finalizeCallback, _In_opt_ void *callbackState, _Out_ JsValueRef *result)
  1638. {
  1639. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1640. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateExternalArrayBuffer, reinterpret_cast<BYTE*>(data), byteLength);
  1641. PARAM_NOT_NULL(result);
  1642. if (data == nullptr && byteLength > 0)
  1643. {
  1644. return JsErrorInvalidArgument;
  1645. }
  1646. Js::JavascriptLibrary* library = scriptContext->GetLibrary();
  1647. *result = Js::JsrtExternalArrayBuffer::New(
  1648. reinterpret_cast<BYTE*>(data),
  1649. byteLength,
  1650. finalizeCallback,
  1651. callbackState,
  1652. library->GetArrayBufferType());
  1653. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1654. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
  1655. return JsNoError;
  1656. });
  1657. }
  1658. CHAKRA_API JsCreateTypedArray(_In_ JsTypedArrayType arrayType, _In_ JsValueRef baseArray, _In_ unsigned int byteOffset,
  1659. _In_ unsigned int elementLength, _Out_ JsValueRef *result)
  1660. {
  1661. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1662. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  1663. if (baseArray != JS_INVALID_REFERENCE)
  1664. {
  1665. VALIDATE_INCOMING_REFERENCE(baseArray, scriptContext);
  1666. }
  1667. PARAM_NOT_NULL(result);
  1668. Js::JavascriptLibrary* library = scriptContext->GetLibrary();
  1669. const bool fromArrayBuffer = (baseArray != JS_INVALID_REFERENCE && Js::ArrayBuffer::Is(baseArray));
  1670. if (byteOffset != 0 && !fromArrayBuffer)
  1671. {
  1672. return JsErrorInvalidArgument;
  1673. }
  1674. if (elementLength != 0 && !(baseArray == JS_INVALID_REFERENCE || fromArrayBuffer))
  1675. {
  1676. return JsErrorInvalidArgument;
  1677. }
  1678. Js::JavascriptFunction* constructorFunc = nullptr;
  1679. Js::Var values[4] =
  1680. {
  1681. library->GetUndefined(),
  1682. baseArray != nullptr ? baseArray : Js::JavascriptNumber::ToVar(elementLength, scriptContext)
  1683. };
  1684. if (fromArrayBuffer)
  1685. {
  1686. values[2] = Js::JavascriptNumber::ToVar(byteOffset, scriptContext);
  1687. values[3] = Js::JavascriptNumber::ToVar(elementLength, scriptContext);
  1688. }
  1689. Js::CallInfo info(Js::CallFlags_New, fromArrayBuffer ? 4 : 2);
  1690. Js::Arguments args(info, values);
  1691. switch (arrayType)
  1692. {
  1693. case JsArrayTypeInt8:
  1694. constructorFunc = library->GetInt8ArrayConstructor();
  1695. break;
  1696. case JsArrayTypeUint8:
  1697. constructorFunc = library->GetUint8ArrayConstructor();
  1698. break;
  1699. case JsArrayTypeUint8Clamped:
  1700. constructorFunc = library->GetUint8ClampedArrayConstructor();
  1701. break;
  1702. case JsArrayTypeInt16:
  1703. constructorFunc = library->GetInt16ArrayConstructor();
  1704. break;
  1705. case JsArrayTypeUint16:
  1706. constructorFunc = library->GetUint16ArrayConstructor();
  1707. break;
  1708. case JsArrayTypeInt32:
  1709. constructorFunc = library->GetInt32ArrayConstructor();
  1710. break;
  1711. case JsArrayTypeUint32:
  1712. constructorFunc = library->GetUint32ArrayConstructor();
  1713. break;
  1714. case JsArrayTypeFloat32:
  1715. constructorFunc = library->GetFloat32ArrayConstructor();
  1716. break;
  1717. case JsArrayTypeFloat64:
  1718. constructorFunc = library->GetFloat64ArrayConstructor();
  1719. break;
  1720. default:
  1721. return JsErrorInvalidArgument;
  1722. }
  1723. *result = Js::JavascriptFunction::CallAsConstructor(constructorFunc, /* overridingNewTarget = */nullptr, args, scriptContext);
  1724. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
  1725. return JsNoError;
  1726. });
  1727. }
  1728. CHAKRA_API JsCreateDataView(_In_ JsValueRef arrayBuffer, _In_ unsigned int byteOffset, _In_ unsigned int byteLength, _Out_ JsValueRef *result)
  1729. {
  1730. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1731. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  1732. VALIDATE_INCOMING_REFERENCE(arrayBuffer, scriptContext);
  1733. PARAM_NOT_NULL(result);
  1734. if (!Js::ArrayBuffer::Is(arrayBuffer))
  1735. {
  1736. return JsErrorInvalidArgument;
  1737. }
  1738. Js::JavascriptLibrary* library = scriptContext->GetLibrary();
  1739. *result = library->CreateDataView(Js::ArrayBuffer::FromVar(arrayBuffer), byteOffset, byteLength);
  1740. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*result));
  1741. return JsNoError;
  1742. });
  1743. }
  1744. C_ASSERT(JsArrayTypeUint8 - Js::TypeIds_Uint8Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1745. C_ASSERT(JsArrayTypeUint8Clamped - Js::TypeIds_Uint8ClampedArray == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1746. C_ASSERT(JsArrayTypeInt16 - Js::TypeIds_Int16Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1747. C_ASSERT(JsArrayTypeUint16 - Js::TypeIds_Uint16Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1748. C_ASSERT(JsArrayTypeInt32 - Js::TypeIds_Int32Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1749. C_ASSERT(JsArrayTypeUint32 - Js::TypeIds_Uint32Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1750. C_ASSERT(JsArrayTypeFloat32 - Js::TypeIds_Float32Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1751. C_ASSERT(JsArrayTypeFloat64 - Js::TypeIds_Float64Array == JsArrayTypeInt8 - Js::TypeIds_Int8Array);
  1752. inline JsTypedArrayType GetTypedArrayType(Js::TypeId typeId)
  1753. {
  1754. Assert(Js::TypedArrayBase::Is(typeId));
  1755. return static_cast<JsTypedArrayType>(typeId + (JsArrayTypeInt8 - Js::TypeIds_Int8Array));
  1756. }
  1757. CHAKRA_API JsGetTypedArrayInfo(_In_ JsValueRef typedArray, _Out_opt_ JsTypedArrayType *arrayType, _Out_opt_ JsValueRef *arrayBuffer,
  1758. _Out_opt_ unsigned int *byteOffset, _Out_opt_ unsigned int *byteLength)
  1759. {
  1760. VALIDATE_JSREF(typedArray);
  1761. BEGIN_JSRT_NO_EXCEPTION
  1762. {
  1763. const Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(typedArray);
  1764. if (!Js::TypedArrayBase::Is(typeId))
  1765. {
  1766. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  1767. }
  1768. if (arrayType != nullptr) {
  1769. *arrayType = GetTypedArrayType(typeId);
  1770. }
  1771. Js::TypedArrayBase* typedArrayBase = Js::TypedArrayBase::FromVar(typedArray);
  1772. if (arrayBuffer != nullptr) {
  1773. *arrayBuffer = typedArrayBase->GetArrayBuffer();
  1774. }
  1775. if (byteOffset != nullptr) {
  1776. *byteOffset = typedArrayBase->GetByteOffset();
  1777. }
  1778. if (byteLength != nullptr) {
  1779. *byteLength = typedArrayBase->GetByteLength();
  1780. }
  1781. }
  1782. #if ENABLE_TTD
  1783. Js::ScriptContext* scriptContext = Js::RecyclableObject::FromVar(typedArray)->GetScriptContext();
  1784. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext) && arrayBuffer != nullptr)
  1785. {
  1786. scriptContext->GetThreadContext()->TTDLog->RecordJsRTGetTypedArrayInfo(typedArray, *arrayBuffer);
  1787. }
  1788. #endif
  1789. END_JSRT_NO_EXCEPTION
  1790. }
  1791. CHAKRA_API JsGetArrayBufferStorage(_In_ JsValueRef instance, _Outptr_result_bytebuffer_(*bufferLength) BYTE **buffer,
  1792. _Out_ unsigned int *bufferLength)
  1793. {
  1794. VALIDATE_JSREF(instance);
  1795. PARAM_NOT_NULL(buffer);
  1796. PARAM_NOT_NULL(bufferLength);
  1797. BEGIN_JSRT_NO_EXCEPTION
  1798. {
  1799. if (!Js::ArrayBuffer::Is(instance))
  1800. {
  1801. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  1802. }
  1803. Js::ArrayBuffer* arrayBuffer = Js::ArrayBuffer::FromVar(instance);
  1804. *buffer = arrayBuffer->GetBuffer();
  1805. *bufferLength = arrayBuffer->GetByteLength();
  1806. }
  1807. END_JSRT_NO_EXCEPTION
  1808. }
  1809. CHAKRA_API JsGetTypedArrayStorage(_In_ JsValueRef instance, _Outptr_result_bytebuffer_(*bufferLength) BYTE **buffer,
  1810. _Out_ unsigned int *bufferLength, _Out_opt_ JsTypedArrayType *typedArrayType, _Out_opt_ int *elementSize)
  1811. {
  1812. VALIDATE_JSREF(instance);
  1813. PARAM_NOT_NULL(buffer);
  1814. PARAM_NOT_NULL(bufferLength);
  1815. BEGIN_JSRT_NO_EXCEPTION
  1816. {
  1817. const Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(instance);
  1818. if (!Js::TypedArrayBase::Is(typeId))
  1819. {
  1820. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  1821. }
  1822. Js::TypedArrayBase* typedArrayBase = Js::TypedArrayBase::FromVar(instance);
  1823. *buffer = typedArrayBase->GetByteBuffer();
  1824. *bufferLength = typedArrayBase->GetByteLength();
  1825. if (typedArrayType)
  1826. {
  1827. *typedArrayType = GetTypedArrayType(typeId);
  1828. }
  1829. if (elementSize)
  1830. {
  1831. switch (typeId)
  1832. {
  1833. case Js::TypeIds_Int8Array:
  1834. *elementSize = sizeof(int8);
  1835. break;
  1836. case Js::TypeIds_Uint8Array:
  1837. *elementSize = sizeof(uint8);
  1838. break;
  1839. case Js::TypeIds_Uint8ClampedArray:
  1840. *elementSize = sizeof(uint8);
  1841. break;
  1842. case Js::TypeIds_Int16Array:
  1843. *elementSize = sizeof(int16);
  1844. break;
  1845. case Js::TypeIds_Uint16Array:
  1846. *elementSize = sizeof(uint16);
  1847. break;
  1848. case Js::TypeIds_Int32Array:
  1849. *elementSize = sizeof(int32);
  1850. break;
  1851. case Js::TypeIds_Uint32Array:
  1852. *elementSize = sizeof(uint32);
  1853. break;
  1854. case Js::TypeIds_Float32Array:
  1855. *elementSize = sizeof(float);
  1856. break;
  1857. case Js::TypeIds_Float64Array:
  1858. *elementSize = sizeof(double);
  1859. break;
  1860. default:
  1861. AssertMsg(FALSE, "invalid typed array type");
  1862. *elementSize = 1;
  1863. RETURN_NO_EXCEPTION(JsErrorFatal);
  1864. }
  1865. }
  1866. }
  1867. END_JSRT_NO_EXCEPTION
  1868. }
  1869. CHAKRA_API JsGetDataViewStorage(_In_ JsValueRef instance, _Outptr_result_bytebuffer_(*bufferLength) BYTE **buffer, _Out_ unsigned int *bufferLength)
  1870. {
  1871. VALIDATE_JSREF(instance);
  1872. PARAM_NOT_NULL(buffer);
  1873. PARAM_NOT_NULL(bufferLength);
  1874. BEGIN_JSRT_NO_EXCEPTION
  1875. {
  1876. if (!Js::DataView::Is(instance))
  1877. {
  1878. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  1879. }
  1880. Js::DataView* dataView = Js::DataView::FromVar(instance);
  1881. *buffer = dataView->GetArrayBuffer()->GetBuffer() + dataView->GetByteOffset();
  1882. *bufferLength = dataView->GetLength();
  1883. }
  1884. END_JSRT_NO_EXCEPTION
  1885. }
  1886. CHAKRA_API JsCreateSymbol(_In_ JsValueRef description, _Out_ JsValueRef *result)
  1887. {
  1888. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1889. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateSymbol, description);
  1890. PARAM_NOT_NULL(result);
  1891. *result = nullptr;
  1892. Js::JavascriptString* descriptionString;
  1893. if (description != JS_INVALID_REFERENCE)
  1894. {
  1895. VALIDATE_INCOMING_REFERENCE(description, scriptContext);
  1896. descriptionString = Js::JavascriptConversion::ToString(description, scriptContext);
  1897. }
  1898. else
  1899. {
  1900. descriptionString = scriptContext->GetLibrary()->GetEmptyString();
  1901. }
  1902. *result = scriptContext->GetLibrary()->CreateSymbol(descriptionString);
  1903. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1904. return JsNoError;
  1905. });
  1906. }
  1907. CHAKRA_API JsHasIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index, _Out_ bool *result)
  1908. {
  1909. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1910. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  1911. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1912. VALIDATE_INCOMING_REFERENCE(index, scriptContext);
  1913. PARAM_NOT_NULL(result);
  1914. *result = false;
  1915. *result = Js::JavascriptOperators::OP_HasItem((Js::Var)object, (Js::Var)index, scriptContext) != 0;
  1916. return JsNoError;
  1917. });
  1918. }
  1919. CHAKRA_API JsGetIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index, _Out_ JsValueRef *result)
  1920. {
  1921. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1922. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetIndex, index, object);
  1923. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1924. VALIDATE_INCOMING_REFERENCE(index, scriptContext);
  1925. PARAM_NOT_NULL(result);
  1926. *result = nullptr;
  1927. *result = (JsValueRef)Js::JavascriptOperators::OP_GetElementI((Js::Var)object, (Js::Var)index, scriptContext);
  1928. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  1929. return JsNoError;
  1930. });
  1931. }
  1932. CHAKRA_API JsSetIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index, _In_ JsValueRef value)
  1933. {
  1934. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1935. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetIndex, object, index, value);
  1936. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1937. VALIDATE_INCOMING_REFERENCE(index, scriptContext);
  1938. VALIDATE_INCOMING_REFERENCE(value, scriptContext);
  1939. Js::JavascriptOperators::OP_SetElementI((Js::Var)object, (Js::Var)index, (Js::Var)value, scriptContext);
  1940. return JsNoError;
  1941. });
  1942. }
  1943. CHAKRA_API JsDeleteIndexedProperty(_In_ JsValueRef object, _In_ JsValueRef index)
  1944. {
  1945. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1946. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  1947. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1948. VALIDATE_INCOMING_REFERENCE(index, scriptContext);
  1949. Js::JavascriptOperators::OP_DeleteElementI((Js::Var)object, (Js::Var)index, scriptContext);
  1950. return JsNoError;
  1951. });
  1952. }
  1953. template <class T, bool clamped = false> struct TypedArrayTypeTraits { static const JsTypedArrayType cTypedArrayType; };
  1954. template<> struct TypedArrayTypeTraits<int8> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeInt8; };
  1955. template<> struct TypedArrayTypeTraits<uint8, false> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint8; };
  1956. template<> struct TypedArrayTypeTraits<uint8, true> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint8Clamped; };
  1957. template<> struct TypedArrayTypeTraits<int16> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeInt16; };
  1958. template<> struct TypedArrayTypeTraits<uint16> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint16; };
  1959. template<> struct TypedArrayTypeTraits<int32> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeInt32; };
  1960. template<> struct TypedArrayTypeTraits<uint32> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeUint32; };
  1961. template<> struct TypedArrayTypeTraits<float> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeFloat32; };
  1962. template<> struct TypedArrayTypeTraits<double> { static const JsTypedArrayType cTypedArrayType = JsTypedArrayType::JsArrayTypeFloat64; };
  1963. template <class T, bool clamped = false>
  1964. Js::ArrayObject* CreateTypedArray(Js::ScriptContext *scriptContext, void* data, unsigned int length)
  1965. {
  1966. Js::JavascriptLibrary* library = scriptContext->GetLibrary();
  1967. Js::ArrayBufferBase* arrayBuffer = RecyclerNew(
  1968. scriptContext->GetRecycler(),
  1969. Js::ExternalArrayBuffer,
  1970. reinterpret_cast<BYTE*>(data),
  1971. length * sizeof(T),
  1972. library->GetArrayBufferType());
  1973. return static_cast<Js::ArrayObject*>(Js::TypedArray<T, clamped>::Create(arrayBuffer, 0, length, library));
  1974. }
  1975. template <class T, bool clamped = false>
  1976. void GetObjectArrayData(Js::ArrayObject* objectArray, void** data, JsTypedArrayType* arrayType, uint* length)
  1977. {
  1978. Js::TypedArray<T, clamped>* typedArray = Js::TypedArray<T, clamped>::FromVar(objectArray);
  1979. *data = typedArray->GetArrayBuffer()->GetBuffer();
  1980. *arrayType = TypedArrayTypeTraits<T, clamped>::cTypedArrayType;
  1981. *length = typedArray->GetLength();
  1982. }
  1983. CHAKRA_API JsSetIndexedPropertiesToExternalData(
  1984. _In_ JsValueRef object,
  1985. _In_ void* data,
  1986. _In_ JsTypedArrayType arrayType,
  1987. _In_ unsigned int elementLength)
  1988. {
  1989. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  1990. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  1991. VALIDATE_INCOMING_OBJECT(object, scriptContext);
  1992. // Don't support doing this on array or array-like object
  1993. Js::TypeId typeId = Js::JavascriptOperators::GetTypeId(object);
  1994. if (!Js::DynamicType::Is(typeId)
  1995. || Js::DynamicObject::IsAnyArrayTypeId(typeId)
  1996. || (typeId >= Js::TypeIds_TypedArrayMin && typeId <= Js::TypeIds_TypedArrayMax)
  1997. || typeId == Js::TypeIds_ArrayBuffer
  1998. || typeId == Js::TypeIds_DataView
  1999. || Js::RecyclableObject::FromVar(object)->IsExternal()
  2000. )
  2001. {
  2002. return JsErrorInvalidArgument;
  2003. }
  2004. if (data == nullptr && elementLength > 0)
  2005. {
  2006. return JsErrorInvalidArgument;
  2007. }
  2008. Js::ArrayObject* newTypedArray = nullptr;
  2009. switch (arrayType)
  2010. {
  2011. case JsArrayTypeInt8:
  2012. newTypedArray = CreateTypedArray<int8>(scriptContext, data, elementLength);
  2013. break;
  2014. case JsArrayTypeUint8:
  2015. newTypedArray = CreateTypedArray<uint8>(scriptContext, data, elementLength);
  2016. break;
  2017. case JsArrayTypeUint8Clamped:
  2018. newTypedArray = CreateTypedArray<uint8, true>(scriptContext, data, elementLength);
  2019. break;
  2020. case JsArrayTypeInt16:
  2021. newTypedArray = CreateTypedArray<int16>(scriptContext, data, elementLength);
  2022. break;
  2023. case JsArrayTypeUint16:
  2024. newTypedArray = CreateTypedArray<uint16>(scriptContext, data, elementLength);
  2025. break;
  2026. case JsArrayTypeInt32:
  2027. newTypedArray = CreateTypedArray<int32>(scriptContext, data, elementLength);
  2028. break;
  2029. case JsArrayTypeUint32:
  2030. newTypedArray = CreateTypedArray<uint32>(scriptContext, data, elementLength);
  2031. break;
  2032. case JsArrayTypeFloat32:
  2033. newTypedArray = CreateTypedArray<float>(scriptContext, data, elementLength);
  2034. break;
  2035. case JsArrayTypeFloat64:
  2036. newTypedArray = CreateTypedArray<double>(scriptContext, data, elementLength);
  2037. break;
  2038. default:
  2039. return JsErrorInvalidArgument;
  2040. }
  2041. Js::DynamicObject* dynamicObject = Js::DynamicObject::FromVar(object);
  2042. dynamicObject->SetObjectArray(newTypedArray);
  2043. return JsNoError;
  2044. });
  2045. }
  2046. CHAKRA_API JsHasIndexedPropertiesExternalData(_In_ JsValueRef object, _Out_ bool *value)
  2047. {
  2048. VALIDATE_JSREF(object);
  2049. PARAM_NOT_NULL(value);
  2050. BEGIN_JSRT_NO_EXCEPTION
  2051. {
  2052. *value = false;
  2053. if (Js::DynamicType::Is(Js::JavascriptOperators::GetTypeId(object)))
  2054. {
  2055. Js::DynamicObject* dynamicObject = Js::DynamicObject::UnsafeFromVar(object);
  2056. Js::ArrayObject* objectArray = dynamicObject->GetObjectArray();
  2057. *value = (objectArray && !Js::DynamicObject::IsAnyArray(objectArray));
  2058. }
  2059. }
  2060. END_JSRT_NO_EXCEPTION
  2061. }
  2062. CHAKRA_API JsGetIndexedPropertiesExternalData(
  2063. _In_ JsValueRef object,
  2064. _Out_ void** buffer,
  2065. _Out_ JsTypedArrayType* arrayType,
  2066. _Out_ unsigned int* elementLength)
  2067. {
  2068. VALIDATE_JSREF(object);
  2069. PARAM_NOT_NULL(buffer);
  2070. PARAM_NOT_NULL(arrayType);
  2071. PARAM_NOT_NULL(elementLength);
  2072. BEGIN_JSRT_NO_EXCEPTION
  2073. {
  2074. if (!Js::DynamicType::Is(Js::JavascriptOperators::GetTypeId(object)))
  2075. {
  2076. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  2077. }
  2078. *buffer = nullptr;
  2079. *arrayType = JsTypedArrayType();
  2080. *elementLength = 0;
  2081. Js::DynamicObject* dynamicObject = Js::DynamicObject::UnsafeFromVar(object);
  2082. Js::ArrayObject* objectArray = dynamicObject->GetObjectArray();
  2083. if (!objectArray)
  2084. {
  2085. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  2086. }
  2087. switch (Js::JavascriptOperators::GetTypeId(objectArray))
  2088. {
  2089. case Js::TypeIds_Int8Array:
  2090. GetObjectArrayData<int8>(objectArray, buffer, arrayType, elementLength);
  2091. break;
  2092. case Js::TypeIds_Uint8Array:
  2093. GetObjectArrayData<uint8>(objectArray, buffer, arrayType, elementLength);
  2094. break;
  2095. case Js::TypeIds_Uint8ClampedArray:
  2096. GetObjectArrayData<uint8, true>(objectArray, buffer, arrayType, elementLength);
  2097. break;
  2098. case Js::TypeIds_Int16Array:
  2099. GetObjectArrayData<int16>(objectArray, buffer, arrayType, elementLength);
  2100. break;
  2101. case Js::TypeIds_Uint16Array:
  2102. GetObjectArrayData<uint16>(objectArray, buffer, arrayType, elementLength);
  2103. break;
  2104. case Js::TypeIds_Int32Array:
  2105. GetObjectArrayData<int32>(objectArray, buffer, arrayType, elementLength);
  2106. break;
  2107. case Js::TypeIds_Uint32Array:
  2108. GetObjectArrayData<uint32>(objectArray, buffer, arrayType, elementLength);
  2109. break;
  2110. case Js::TypeIds_Float32Array:
  2111. GetObjectArrayData<float>(objectArray, buffer, arrayType, elementLength);
  2112. break;
  2113. case Js::TypeIds_Float64Array:
  2114. GetObjectArrayData<double>(objectArray, buffer, arrayType, elementLength);
  2115. break;
  2116. default:
  2117. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  2118. }
  2119. }
  2120. END_JSRT_NO_EXCEPTION
  2121. }
  2122. CHAKRA_API JsLessThan(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
  2123. {
  2124. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2125. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTLessThan, object1, object2, false);
  2126. VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
  2127. VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
  2128. PARAM_NOT_NULL(result);
  2129. *result = Js::JavascriptOperators::Less((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
  2130. return JsNoError;
  2131. });
  2132. }
  2133. CHAKRA_API JsLessThanOrEqual(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
  2134. {
  2135. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2136. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTLessThan, object1, object2, true);
  2137. VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
  2138. VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
  2139. PARAM_NOT_NULL(result);
  2140. *result = Js::JavascriptOperators::LessEqual((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
  2141. return JsNoError;
  2142. });
  2143. }
  2144. CHAKRA_API JsEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
  2145. {
  2146. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2147. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTEquals, object1, object2, false);
  2148. VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
  2149. VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
  2150. PARAM_NOT_NULL(result);
  2151. *result = Js::JavascriptOperators::Equal((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
  2152. return JsNoError;
  2153. });
  2154. }
  2155. CHAKRA_API JsStrictEquals(_In_ JsValueRef object1, _In_ JsValueRef object2, _Out_ bool *result)
  2156. {
  2157. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2158. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTEquals, object1, object2, true);
  2159. VALIDATE_INCOMING_REFERENCE(object1, scriptContext);
  2160. VALIDATE_INCOMING_REFERENCE(object2, scriptContext);
  2161. PARAM_NOT_NULL(result);
  2162. *result = Js::JavascriptOperators::StrictEqual((Js::Var)object1, (Js::Var)object2, scriptContext) != 0;
  2163. return JsNoError;
  2164. });
  2165. }
  2166. CHAKRA_API JsHasExternalData(_In_ JsValueRef object, _Out_ bool *value)
  2167. {
  2168. VALIDATE_JSREF(object);
  2169. PARAM_NOT_NULL(value);
  2170. BEGIN_JSRT_NO_EXCEPTION
  2171. {
  2172. *value = JsrtExternalObject::Is(object);
  2173. }
  2174. END_JSRT_NO_EXCEPTION
  2175. }
  2176. CHAKRA_API JsGetExternalData(_In_ JsValueRef object, _Out_ void **data)
  2177. {
  2178. VALIDATE_JSREF(object);
  2179. PARAM_NOT_NULL(data);
  2180. BEGIN_JSRT_NO_EXCEPTION
  2181. {
  2182. if (JsrtExternalObject::Is(object))
  2183. {
  2184. *data = JsrtExternalObject::FromVar(object)->GetSlotData();
  2185. }
  2186. else
  2187. {
  2188. *data = nullptr;
  2189. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  2190. }
  2191. }
  2192. END_JSRT_NO_EXCEPTION
  2193. }
  2194. CHAKRA_API JsSetExternalData(_In_ JsValueRef object, _In_opt_ void *data)
  2195. {
  2196. VALIDATE_JSREF(object);
  2197. BEGIN_JSRT_NO_EXCEPTION
  2198. {
  2199. if (JsrtExternalObject::Is(object))
  2200. {
  2201. JsrtExternalObject::FromVar(object)->SetSlotData(data);
  2202. }
  2203. else
  2204. {
  2205. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  2206. }
  2207. }
  2208. END_JSRT_NO_EXCEPTION
  2209. }
  2210. CHAKRA_API JsCallFunction(_In_ JsValueRef function, _In_reads_(cargs) JsValueRef *args, _In_ ushort cargs, _Out_opt_ JsValueRef *result)
  2211. {
  2212. if(result != nullptr)
  2213. {
  2214. *result = nullptr;
  2215. }
  2216. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2217. #if ENABLE_TTD
  2218. TTD::TTDJsRTFunctionCallActionPopperRecorder callInfoPopper;
  2219. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
  2220. {
  2221. TTD::NSLogEvents::EventLogEntry* callEvent = scriptContext->GetThreadContext()->TTDLog->RecordJsRTCallFunction(_actionEntryPopper, scriptContext->GetThreadContext()->TTDRootNestingCount, function, cargs, args);
  2222. callInfoPopper.InitializeForRecording(scriptContext, scriptContext->GetThreadContext()->TTDLog->GetCurrentWallTime(), callEvent);
  2223. if(scriptContext->GetThreadContext()->TTDRootNestingCount == 0)
  2224. {
  2225. TTD::EventLog* elog = scriptContext->GetThreadContext()->TTDLog;
  2226. elog->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
  2227. TTD::ExecutionInfoManager* emanager = scriptContext->GetThreadContext()->TTDExecutionInfo;
  2228. if(emanager != nullptr)
  2229. {
  2230. emanager->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
  2231. }
  2232. }
  2233. }
  2234. #endif
  2235. VALIDATE_INCOMING_FUNCTION(function, scriptContext);
  2236. if(cargs == 0 || args == nullptr)
  2237. {
  2238. return JsErrorInvalidArgument;
  2239. }
  2240. for(int index = 0; index < cargs; index++)
  2241. {
  2242. VALIDATE_INCOMING_REFERENCE(args[index], scriptContext);
  2243. }
  2244. Js::JavascriptFunction *jsFunction = Js::JavascriptFunction::FromVar(function);
  2245. Js::CallInfo callInfo(cargs);
  2246. Js::Arguments jsArgs(callInfo, reinterpret_cast<Js::Var *>(args));
  2247. Js::Var varResult = jsFunction->CallRootFunction(jsArgs, scriptContext, true);
  2248. if(result != nullptr)
  2249. {
  2250. *result = varResult;
  2251. Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
  2252. }
  2253. #if ENABLE_TTD
  2254. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
  2255. {
  2256. _actionEntryPopper.SetResult(result);
  2257. }
  2258. #endif
  2259. return JsNoError;
  2260. });
  2261. }
  2262. CHAKRA_API JsConstructObject(_In_ JsValueRef function, _In_reads_(cargs) JsValueRef *args, _In_ ushort cargs, _Out_ JsValueRef *result)
  2263. {
  2264. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2265. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTConstructCall, function, cargs, args);
  2266. VALIDATE_INCOMING_FUNCTION(function, scriptContext);
  2267. PARAM_NOT_NULL(result);
  2268. *result = nullptr;
  2269. if (cargs == 0 || args == nullptr)
  2270. {
  2271. return JsErrorInvalidArgument;
  2272. }
  2273. for (int index = 0; index < cargs; index++)
  2274. {
  2275. VALIDATE_INCOMING_REFERENCE(args[index], scriptContext);
  2276. }
  2277. Js::JavascriptFunction *jsFunction = Js::JavascriptFunction::FromVar(function);
  2278. Js::CallInfo callInfo(Js::CallFlags::CallFlags_New, cargs);
  2279. Js::Arguments jsArgs(callInfo, reinterpret_cast<Js::Var *>(args));
  2280. //
  2281. //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
  2282. //TTDAssert(!Js::ScriptFunction::Is(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!!!!");
  2283. //
  2284. *result = Js::JavascriptFunction::CallAsConstructor(jsFunction, /* overridingNewTarget = */nullptr, jsArgs, scriptContext);
  2285. Assert(*result == nullptr || !Js::CrossSite::NeedMarshalVar(*result, scriptContext));
  2286. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, result);
  2287. return JsNoError;
  2288. });
  2289. }
  2290. CHAKRA_API JsCreateFunction(_In_ JsNativeFunction nativeFunction, _In_opt_ void *callbackState, _Out_ JsValueRef *function)
  2291. {
  2292. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2293. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateFunction, false, nullptr);
  2294. PARAM_NOT_NULL(nativeFunction);
  2295. PARAM_NOT_NULL(function);
  2296. *function = nullptr;
  2297. Js::JavascriptExternalFunction *externalFunction = scriptContext->GetLibrary()->CreateStdCallExternalFunction((Js::StdCallJavascriptMethod)nativeFunction, 0, callbackState);
  2298. *function = (JsValueRef)externalFunction;
  2299. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, function);
  2300. return JsNoError;
  2301. });
  2302. }
  2303. CHAKRA_API JsCreateNamedFunction(_In_ JsValueRef name, _In_ JsNativeFunction nativeFunction, _In_opt_ void *callbackState, _Out_ JsValueRef *function)
  2304. {
  2305. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2306. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTAllocateFunction, true, name);
  2307. VALIDATE_INCOMING_REFERENCE(name, scriptContext);
  2308. PARAM_NOT_NULL(nativeFunction);
  2309. PARAM_NOT_NULL(function);
  2310. *function = nullptr;
  2311. if (name != JS_INVALID_REFERENCE)
  2312. {
  2313. name = Js::JavascriptConversion::ToString(name, scriptContext);
  2314. }
  2315. else
  2316. {
  2317. name = scriptContext->GetLibrary()->GetEmptyString();
  2318. }
  2319. Js::JavascriptExternalFunction *externalFunction = scriptContext->GetLibrary()->CreateStdCallExternalFunction((Js::StdCallJavascriptMethod)nativeFunction, Js::JavascriptString::FromVar(name), callbackState);
  2320. *function = (JsValueRef)externalFunction;
  2321. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, function);
  2322. return JsNoError;
  2323. });
  2324. }
  2325. void SetErrorMessage(Js::ScriptContext *scriptContext, JsValueRef newError, JsValueRef message)
  2326. {
  2327. Js::JavascriptOperators::OP_SetProperty(newError, Js::PropertyIds::message, message, scriptContext);
  2328. }
  2329. CHAKRA_API JsCreateError(_In_ JsValueRef message, _Out_ JsValueRef *error)
  2330. {
  2331. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2332. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateError, message);
  2333. VALIDATE_INCOMING_REFERENCE(message, scriptContext);
  2334. PARAM_NOT_NULL(error);
  2335. *error = nullptr;
  2336. JsValueRef newError = scriptContext->GetLibrary()->CreateError();
  2337. SetErrorMessage(scriptContext, newError, message);
  2338. *error = newError;
  2339. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
  2340. return JsNoError;
  2341. });
  2342. }
  2343. CHAKRA_API JsCreateRangeError(_In_ JsValueRef message, _Out_ JsValueRef *error)
  2344. {
  2345. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2346. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateRangeError, message);
  2347. VALIDATE_INCOMING_REFERENCE(message, scriptContext);
  2348. PARAM_NOT_NULL(error);
  2349. *error = nullptr;
  2350. JsValueRef newError = scriptContext->GetLibrary()->CreateRangeError();
  2351. SetErrorMessage(scriptContext, newError, message);
  2352. *error = newError;
  2353. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
  2354. return JsNoError;
  2355. });
  2356. }
  2357. CHAKRA_API JsCreateReferenceError(_In_ JsValueRef message, _Out_ JsValueRef *error)
  2358. {
  2359. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2360. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateReferenceError, message);
  2361. VALIDATE_INCOMING_REFERENCE(message, scriptContext);
  2362. PARAM_NOT_NULL(error);
  2363. *error = nullptr;
  2364. JsValueRef newError = scriptContext->GetLibrary()->CreateReferenceError();
  2365. SetErrorMessage(scriptContext, newError, message);
  2366. *error = newError;
  2367. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
  2368. return JsNoError;
  2369. });
  2370. }
  2371. CHAKRA_API JsCreateSyntaxError(_In_ JsValueRef message, _Out_ JsValueRef *error)
  2372. {
  2373. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2374. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateSyntaxError, message);
  2375. VALIDATE_INCOMING_REFERENCE(message, scriptContext);
  2376. PARAM_NOT_NULL(error);
  2377. *error = nullptr;
  2378. JsValueRef newError = scriptContext->GetLibrary()->CreateSyntaxError();
  2379. SetErrorMessage(scriptContext, newError, message);
  2380. *error = newError;
  2381. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
  2382. return JsNoError;
  2383. });
  2384. }
  2385. CHAKRA_API JsCreateTypeError(_In_ JsValueRef message, _Out_ JsValueRef *error)
  2386. {
  2387. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2388. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateTypeError, message);
  2389. VALIDATE_INCOMING_REFERENCE(message, scriptContext);
  2390. PARAM_NOT_NULL(error);
  2391. *error = nullptr;
  2392. JsValueRef newError = scriptContext->GetLibrary()->CreateTypeError();
  2393. SetErrorMessage(scriptContext, newError, message);
  2394. *error = newError;
  2395. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
  2396. return JsNoError;
  2397. });
  2398. }
  2399. CHAKRA_API JsCreateURIError(_In_ JsValueRef message, _Out_ JsValueRef *error)
  2400. {
  2401. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&] (Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2402. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateURIError, message);
  2403. VALIDATE_INCOMING_REFERENCE(message, scriptContext);
  2404. PARAM_NOT_NULL(error);
  2405. *error = nullptr;
  2406. JsValueRef newError = scriptContext->GetLibrary()->CreateURIError();
  2407. SetErrorMessage(scriptContext, newError, message);
  2408. *error = newError;
  2409. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, error);
  2410. return JsNoError;
  2411. });
  2412. }
  2413. CHAKRA_API JsHasException(_Out_ bool *hasException)
  2414. {
  2415. PARAM_NOT_NULL(hasException);
  2416. *hasException = false;
  2417. JsrtContext *currentContext = JsrtContext::GetCurrent();
  2418. if (currentContext == nullptr)
  2419. {
  2420. return JsErrorNoCurrentContext;
  2421. }
  2422. Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
  2423. Assert(scriptContext != nullptr);
  2424. Recycler *recycler = scriptContext->GetRecycler();
  2425. ThreadContext *threadContext = scriptContext->GetThreadContext();
  2426. #ifndef JSRT_VERIFY_RUNTIME_STATE
  2427. if (recycler && recycler->IsInObjectBeforeCollectCallback())
  2428. {
  2429. return JsErrorInObjectBeforeCollectCallback;
  2430. }
  2431. #endif
  2432. if (recycler && recycler->IsHeapEnumInProgress())
  2433. {
  2434. return JsErrorHeapEnumInProgress;
  2435. }
  2436. else if (threadContext->IsInThreadServiceCallback())
  2437. {
  2438. return JsErrorInThreadServiceCallback;
  2439. }
  2440. if (threadContext->IsExecutionDisabled())
  2441. {
  2442. return JsErrorInDisabledState;
  2443. }
  2444. *hasException = scriptContext->HasRecordedException();
  2445. return JsNoError;
  2446. }
  2447. CHAKRA_API JsGetAndClearException(_Out_ JsValueRef *exception)
  2448. {
  2449. PARAM_NOT_NULL(exception);
  2450. *exception = nullptr;
  2451. JsrtContext *currentContext = JsrtContext::GetCurrent();
  2452. if (currentContext == nullptr)
  2453. {
  2454. return JsErrorNoCurrentContext;
  2455. }
  2456. Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
  2457. Assert(scriptContext != nullptr);
  2458. if (scriptContext->GetRecycler() && scriptContext->GetRecycler()->IsHeapEnumInProgress())
  2459. {
  2460. return JsErrorHeapEnumInProgress;
  2461. }
  2462. else if (scriptContext->GetThreadContext()->IsInThreadServiceCallback())
  2463. {
  2464. return JsErrorInThreadServiceCallback;
  2465. }
  2466. if (scriptContext->GetThreadContext()->IsExecutionDisabled())
  2467. {
  2468. return JsErrorInDisabledState;
  2469. }
  2470. HRESULT hr = S_OK;
  2471. Js::JavascriptExceptionObject *recordedException = nullptr;
  2472. BEGIN_TRANSLATE_OOM_TO_HRESULT
  2473. if (scriptContext->HasRecordedException())
  2474. {
  2475. recordedException = scriptContext->GetAndClearRecordedException();
  2476. }
  2477. END_TRANSLATE_OOM_TO_HRESULT(hr)
  2478. if (hr == E_OUTOFMEMORY)
  2479. {
  2480. recordedException = scriptContext->GetThreadContext()->GetRecordedException();
  2481. }
  2482. if (recordedException == nullptr)
  2483. {
  2484. return JsErrorInvalidArgument;
  2485. }
  2486. *exception = recordedException->GetThrownObject(nullptr);
  2487. #if ENABLE_TTD
  2488. if(hr != E_OUTOFMEMORY)
  2489. {
  2490. TTD::TTDJsRTActionResultAutoRecorder _actionEntryPopper;
  2491. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetAndClearException);
  2492. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, exception);
  2493. }
  2494. #endif
  2495. if (*exception == nullptr)
  2496. {
  2497. return JsErrorInvalidArgument;
  2498. }
  2499. return JsNoError;
  2500. }
  2501. CHAKRA_API JsSetException(_In_ JsValueRef exception)
  2502. {
  2503. return ContextAPINoScriptWrapper([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2504. JsrtContext * context = JsrtContext::GetCurrent();
  2505. JsrtRuntime * runtime = context->GetRuntime();
  2506. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTSetException, exception, runtime->DispatchExceptions());
  2507. VALIDATE_INCOMING_REFERENCE(exception, scriptContext);
  2508. Js::JavascriptExceptionObject *exceptionObject;
  2509. exceptionObject = RecyclerNew(scriptContext->GetRecycler(), Js::JavascriptExceptionObject, exception, scriptContext, nullptr);
  2510. scriptContext->RecordException(exceptionObject, runtime->DispatchExceptions());
  2511. return JsNoError;
  2512. });
  2513. }
  2514. CHAKRA_API JsGetRuntimeMemoryUsage(_In_ JsRuntimeHandle runtimeHandle, _Out_ size_t * memoryUsage)
  2515. {
  2516. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  2517. PARAM_NOT_NULL(memoryUsage);
  2518. *memoryUsage = 0;
  2519. ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
  2520. AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
  2521. *memoryUsage = allocPolicyManager->GetUsage();
  2522. return JsNoError;
  2523. }
  2524. CHAKRA_API JsSetRuntimeMemoryLimit(_In_ JsRuntimeHandle runtimeHandle, _In_ size_t memoryLimit)
  2525. {
  2526. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  2527. ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
  2528. AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
  2529. allocPolicyManager->SetLimit(memoryLimit);
  2530. return JsNoError;
  2531. }
  2532. CHAKRA_API JsGetRuntimeMemoryLimit(_In_ JsRuntimeHandle runtimeHandle, _Out_ size_t * memoryLimit)
  2533. {
  2534. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  2535. PARAM_NOT_NULL(memoryLimit);
  2536. *memoryLimit = 0;
  2537. ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
  2538. AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
  2539. *memoryLimit = allocPolicyManager->GetLimit();
  2540. return JsNoError;
  2541. }
  2542. C_ASSERT(JsMemoryAllocate == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryAllocate);
  2543. C_ASSERT(JsMemoryFree == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryFree);
  2544. C_ASSERT(JsMemoryFailure == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryFailure);
  2545. C_ASSERT(JsMemoryFailure == (_JsMemoryEventType) AllocationPolicyManager::MemoryAllocateEvent::MemoryMax);
  2546. CHAKRA_API JsSetRuntimeMemoryAllocationCallback(_In_ JsRuntimeHandle runtime, _In_opt_ void *callbackState, _In_ JsMemoryAllocationCallback allocationCallback)
  2547. {
  2548. VALIDATE_INCOMING_RUNTIME_HANDLE(runtime);
  2549. ThreadContext* threadContext = JsrtRuntime::FromHandle(runtime)->GetThreadContext();
  2550. AllocationPolicyManager * allocPolicyManager = threadContext->GetAllocationPolicyManager();
  2551. allocPolicyManager->SetMemoryAllocationCallback(callbackState, (AllocationPolicyManager::PageAllocatorMemoryAllocationCallback)allocationCallback);
  2552. return JsNoError;
  2553. }
  2554. CHAKRA_API JsSetRuntimeBeforeCollectCallback(_In_ JsRuntimeHandle runtime, _In_opt_ void *callbackState, _In_ JsBeforeCollectCallback beforeCollectCallback)
  2555. {
  2556. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  2557. VALIDATE_INCOMING_RUNTIME_HANDLE(runtime);
  2558. JsrtRuntime::FromHandle(runtime)->SetBeforeCollectCallback(beforeCollectCallback, callbackState);
  2559. return JsNoError;
  2560. });
  2561. }
  2562. CHAKRA_API JsDisableRuntimeExecution(_In_ JsRuntimeHandle runtimeHandle)
  2563. {
  2564. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  2565. ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
  2566. if (!threadContext->TestThreadContextFlag(ThreadContextFlagCanDisableExecution))
  2567. {
  2568. return JsErrorCannotDisableExecution;
  2569. }
  2570. if (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
  2571. {
  2572. return JsErrorHeapEnumInProgress;
  2573. }
  2574. else if (threadContext->IsInThreadServiceCallback())
  2575. {
  2576. return JsErrorInThreadServiceCallback;
  2577. }
  2578. threadContext->DisableExecution();
  2579. return JsNoError;
  2580. }
  2581. CHAKRA_API JsEnableRuntimeExecution(_In_ JsRuntimeHandle runtimeHandle)
  2582. {
  2583. return GlobalAPIWrapper_NoRecord([&] () -> JsErrorCode {
  2584. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  2585. ThreadContext * threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
  2586. if (!threadContext->TestThreadContextFlag(ThreadContextFlagCanDisableExecution))
  2587. {
  2588. return JsNoError;
  2589. }
  2590. if (threadContext->GetRecycler() && threadContext->GetRecycler()->IsHeapEnumInProgress())
  2591. {
  2592. return JsErrorHeapEnumInProgress;
  2593. }
  2594. else if (threadContext->IsInThreadServiceCallback())
  2595. {
  2596. return JsErrorInThreadServiceCallback;
  2597. }
  2598. ThreadContextScope scope(threadContext);
  2599. if (!scope.IsValid())
  2600. {
  2601. return JsErrorWrongThread;
  2602. }
  2603. threadContext->EnableExecution();
  2604. return JsNoError;
  2605. });
  2606. }
  2607. CHAKRA_API JsIsRuntimeExecutionDisabled(_In_ JsRuntimeHandle runtimeHandle, _Out_ bool *isDisabled)
  2608. {
  2609. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  2610. PARAM_NOT_NULL(isDisabled);
  2611. *isDisabled = false;
  2612. ThreadContext* threadContext = JsrtRuntime::FromHandle(runtimeHandle)->GetThreadContext();
  2613. *isDisabled = threadContext->IsExecutionDisabled();
  2614. return JsNoError;
  2615. }
  2616. inline JsErrorCode JsGetPropertyIdFromNameInternal(_In_z_ const WCHAR *name, size_t cPropertyNameLength, _Out_ JsPropertyIdRef *propertyId)
  2617. {
  2618. return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext * scriptContext) -> JsErrorCode {
  2619. PARAM_NOT_NULL(name);
  2620. PARAM_NOT_NULL(propertyId);
  2621. *propertyId = nullptr;
  2622. if (cPropertyNameLength <= INT_MAX)
  2623. {
  2624. scriptContext->GetOrAddPropertyRecord(name, static_cast<int>(cPropertyNameLength), (Js::PropertyRecord const **)propertyId);
  2625. return JsNoError;
  2626. }
  2627. else
  2628. {
  2629. return JsErrorOutOfMemory;
  2630. }
  2631. });
  2632. }
  2633. CHAKRA_API JsGetPropertyIdFromName(_In_z_ const WCHAR *name, _Out_ JsPropertyIdRef *propertyId)
  2634. {
  2635. return JsGetPropertyIdFromNameInternal(name, wcslen(name), propertyId);
  2636. }
  2637. CHAKRA_API JsGetPropertyIdFromSymbol(_In_ JsValueRef symbol, _Out_ JsPropertyIdRef *propertyId)
  2638. {
  2639. return ContextAPINoScriptWrapper([&](Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2640. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetPropertyIdFromSymbol, symbol);
  2641. VALIDATE_INCOMING_REFERENCE(symbol, scriptContext);
  2642. PARAM_NOT_NULL(propertyId);
  2643. *propertyId = nullptr;
  2644. if (!Js::JavascriptSymbol::Is(symbol))
  2645. {
  2646. return JsErrorPropertyNotSymbol;
  2647. }
  2648. *propertyId = (JsPropertyIdRef)Js::JavascriptSymbol::FromVar(symbol)->GetValue();
  2649. return JsNoError;
  2650. },
  2651. /*allowInObjectBeforeCollectCallback*/true);
  2652. }
  2653. CHAKRA_API JsGetSymbolFromPropertyId(_In_ JsPropertyIdRef propertyId, _Out_ JsValueRef *symbol)
  2654. {
  2655. return ContextAPINoScriptWrapper([&](Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2656. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  2657. VALIDATE_INCOMING_PROPERTYID(propertyId);
  2658. PARAM_NOT_NULL(symbol);
  2659. *symbol = nullptr;
  2660. Js::PropertyRecord const * propertyRecord = (Js::PropertyRecord const *)propertyId;
  2661. if (!propertyRecord->IsSymbol())
  2662. {
  2663. return JsErrorPropertyNotSymbol;
  2664. }
  2665. *symbol = scriptContext->GetLibrary()->CreateSymbol(propertyRecord);
  2666. return JsNoError;
  2667. });
  2668. }
  2669. #pragma prefast(suppress:6101, "Prefast doesn't see through the lambda")
  2670. CHAKRA_API JsGetPropertyNameFromId(_In_ JsPropertyIdRef propertyId, _Outptr_result_z_ const WCHAR **name)
  2671. {
  2672. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  2673. VALIDATE_INCOMING_PROPERTYID(propertyId);
  2674. PARAM_NOT_NULL(name);
  2675. *name = nullptr;
  2676. Js::PropertyRecord const * propertyRecord = (Js::PropertyRecord const *)propertyId;
  2677. if (propertyRecord->IsSymbol())
  2678. {
  2679. return JsErrorPropertyNotString;
  2680. }
  2681. *name = propertyRecord->GetBuffer();
  2682. return JsNoError;
  2683. });
  2684. }
  2685. CHAKRA_API JsGetPropertyIdType(_In_ JsPropertyIdRef propertyId, _Out_ JsPropertyIdType* propertyIdType)
  2686. {
  2687. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  2688. VALIDATE_INCOMING_PROPERTYID(propertyId);
  2689. Js::PropertyRecord const * propertyRecord = (Js::PropertyRecord const *)propertyId;
  2690. if (propertyRecord->IsSymbol())
  2691. {
  2692. *propertyIdType = JsPropertyIdTypeSymbol;
  2693. }
  2694. else
  2695. {
  2696. *propertyIdType = JsPropertyIdTypeString;
  2697. }
  2698. return JsNoError;
  2699. });
  2700. }
  2701. CHAKRA_API JsGetRuntime(_In_ JsContextRef context, _Out_ JsRuntimeHandle *runtime)
  2702. {
  2703. VALIDATE_JSREF(context);
  2704. PARAM_NOT_NULL(runtime);
  2705. *runtime = nullptr;
  2706. if (!JsrtContext::Is(context))
  2707. {
  2708. return JsErrorInvalidArgument;
  2709. }
  2710. *runtime = static_cast<JsrtContext *>(context)->GetRuntime();
  2711. return JsNoError;
  2712. }
  2713. CHAKRA_API JsIdle(_Out_opt_ unsigned int *nextIdleTick)
  2714. {
  2715. PARAM_NOT_NULL(nextIdleTick);
  2716. return ContextAPINoScriptWrapper_NoRecord([&] (Js::ScriptContext * scriptContext) -> JsErrorCode {
  2717. *nextIdleTick = 0;
  2718. if (scriptContext->GetThreadContext()->GetRecycler() && scriptContext->GetThreadContext()->GetRecycler()->IsHeapEnumInProgress())
  2719. {
  2720. return JsErrorHeapEnumInProgress;
  2721. }
  2722. else if (scriptContext->GetThreadContext()->IsInThreadServiceCallback())
  2723. {
  2724. return JsErrorInThreadServiceCallback;
  2725. }
  2726. JsrtContext * context = JsrtContext::GetCurrent();
  2727. JsrtRuntime * runtime = context->GetRuntime();
  2728. if (!runtime->UseIdle())
  2729. {
  2730. return JsErrorIdleNotEnabled;
  2731. }
  2732. unsigned int ticks = runtime->Idle();
  2733. *nextIdleTick = ticks;
  2734. return JsNoError;
  2735. });
  2736. }
  2737. CHAKRA_API JsSetPromiseContinuationCallback(_In_opt_ JsPromiseContinuationCallback promiseContinuationCallback, _In_opt_ void *callbackState)
  2738. {
  2739. return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  2740. scriptContext->GetLibrary()->SetNativeHostPromiseContinuationFunction((Js::JavascriptLibrary::PromiseContinuationCallback) promiseContinuationCallback, callbackState);
  2741. return JsNoError;
  2742. },
  2743. /*allowInObjectBeforeCollectCallback*/true);
  2744. }
  2745. JsErrorCode RunScriptCore(JsValueRef scriptSource, const byte *script, size_t cb,
  2746. LoadScriptFlag loadScriptFlag, JsSourceContext sourceContext,
  2747. const WCHAR *sourceUrl, bool parseOnly, JsParseScriptAttributes parseAttributes,
  2748. bool isSourceModule, JsValueRef *result)
  2749. {
  2750. Js::JavascriptFunction *scriptFunction;
  2751. CompileScriptException se;
  2752. JsErrorCode errorCode = ContextAPINoScriptWrapper([&](Js::ScriptContext * scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2753. PARAM_NOT_NULL(script);
  2754. PARAM_NOT_NULL(sourceUrl);
  2755. SourceContextInfo * sourceContextInfo = scriptContext->GetSourceContextInfo(sourceContext, nullptr);
  2756. if (sourceContextInfo == nullptr)
  2757. {
  2758. sourceContextInfo = scriptContext->CreateSourceContextInfo(sourceContext, sourceUrl, wcslen(sourceUrl), nullptr);
  2759. }
  2760. const int chsize = (loadScriptFlag & LoadScriptFlag_Utf8Source) ?
  2761. sizeof(utf8char_t) : sizeof(WCHAR);
  2762. SRCINFO si = {
  2763. /* sourceContextInfo */ sourceContextInfo,
  2764. /* dlnHost */ 0,
  2765. /* ulColumnHost */ 0,
  2766. /* lnMinHost */ 0,
  2767. /* ichMinHost */ 0,
  2768. /* ichLimHost */ static_cast<ULONG>(cb / chsize), // OK to truncate since this is used to limit sourceText in debugDocument/compilation errors.
  2769. /* ulCharOffset */ 0,
  2770. /* mod */ kmodGlobal,
  2771. /* grfsi */ 0
  2772. };
  2773. Js::Utf8SourceInfo* utf8SourceInfo = nullptr;
  2774. if (result != nullptr)
  2775. {
  2776. loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Expression);
  2777. }
  2778. bool isLibraryCode = (parseAttributes & JsParseScriptAttributeLibraryCode) == JsParseScriptAttributeLibraryCode;
  2779. if (isLibraryCode)
  2780. {
  2781. loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_LibraryCode);
  2782. }
  2783. if (isSourceModule)
  2784. {
  2785. loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Module);
  2786. }
  2787. #if ENABLE_TTD
  2788. TTD::NSLogEvents::EventLogEntry* parseEvent = nullptr;
  2789. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
  2790. {
  2791. parseEvent = scriptContext->GetThreadContext()->TTDLog->RecordJsRTCodeParse(_actionEntryPopper,
  2792. loadScriptFlag, ((loadScriptFlag & LoadScriptFlag_Utf8Source) == LoadScriptFlag_Utf8Source),
  2793. script, (uint32)cb, sourceContext, sourceUrl);
  2794. }
  2795. #endif
  2796. scriptFunction = scriptContext->LoadScript(script, cb,
  2797. &si, &se, &utf8SourceInfo,
  2798. Js::Constants::GlobalCode, loadScriptFlag, scriptSource);
  2799. #if ENABLE_TTD
  2800. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
  2801. {
  2802. _actionEntryPopper.SetResult((Js::Var*)&scriptFunction);
  2803. }
  2804. //
  2805. //TODO: We may (probably?) want to use the debugger source rundown functionality here instead
  2806. //
  2807. if (scriptFunction != nullptr && scriptContext->IsTTDRecordModeEnabled())
  2808. {
  2809. //Make sure we have the body and text information available
  2810. Js::FunctionBody* globalBody = TTD::JsSupport::ForceAndGetFunctionBody(scriptFunction->GetParseableFunctionInfo());
  2811. const TTD::NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo* tbfi = scriptContext->GetThreadContext()->TTDLog->AddScriptLoad(globalBody, kmodGlobal, sourceContext, script, (uint32)cb, loadScriptFlag);
  2812. if(parseEvent != nullptr)
  2813. {
  2814. TTD::NSLogEvents::JsRTCodeParseAction_SetBodyCtrId(parseEvent, tbfi->TopLevelBase.TopLevelBodyCtr);
  2815. }
  2816. //walk global body to (1) add functions to pin set (2) build parent map
  2817. BEGIN_JS_RUNTIME_CALL(scriptContext);
  2818. {
  2819. scriptContext->TTDContextInfo->ProcessFunctionBodyOnLoad(globalBody, nullptr);
  2820. scriptContext->TTDContextInfo->RegisterLoadedScript(globalBody, tbfi->TopLevelBase.TopLevelBodyCtr);
  2821. }
  2822. END_JS_RUNTIME_CALL(scriptContext);
  2823. }
  2824. #endif
  2825. JsrtContext * context = JsrtContext::GetCurrent();
  2826. context->OnScriptLoad(scriptFunction, utf8SourceInfo, &se);
  2827. return JsNoError;
  2828. });
  2829. if (errorCode != JsNoError)
  2830. {
  2831. return errorCode;
  2832. }
  2833. return ContextAPIWrapper<false>([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  2834. if (scriptFunction == nullptr)
  2835. {
  2836. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  2837. HandleScriptCompileError(scriptContext, &se, sourceUrl);
  2838. return JsErrorScriptCompile;
  2839. }
  2840. if (parseOnly)
  2841. {
  2842. PARAM_NOT_NULL(result);
  2843. *result = scriptFunction;
  2844. }
  2845. else
  2846. {
  2847. Js::Arguments args(0, nullptr);
  2848. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  2849. Js::Var varThis;
  2850. if (PHASE_FORCE1(Js::EvalCompilePhase))
  2851. {
  2852. varThis = Js::JavascriptOperators::OP_GetThis(scriptContext->GetLibrary()->GetUndefined(), kmodGlobal, scriptContext);
  2853. args.Info.Flags = (Js::CallFlags)Js::CallFlags::CallFlags_Eval;
  2854. args.Info.Count = 1;
  2855. args.Values = &varThis;
  2856. }
  2857. #endif
  2858. #if ENABLE_TTD
  2859. TTD::TTDJsRTFunctionCallActionPopperRecorder callInfoPopper;
  2860. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
  2861. {
  2862. TTD::NSLogEvents::EventLogEntry* callEvent = scriptContext->GetThreadContext()->TTDLog->RecordJsRTCallFunction(_actionEntryPopper, scriptContext->GetThreadContext()->TTDRootNestingCount, scriptFunction, args.Info.Count, args.Values);
  2863. callInfoPopper.InitializeForRecording(scriptContext, scriptContext->GetThreadContext()->TTDLog->GetCurrentWallTime(), callEvent);
  2864. if(scriptContext->GetThreadContext()->TTDRootNestingCount == 0)
  2865. {
  2866. TTD::EventLog* elog = scriptContext->GetThreadContext()->TTDLog;
  2867. elog->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
  2868. TTD::ExecutionInfoManager* emanager = scriptContext->GetThreadContext()->TTDExecutionInfo;
  2869. if(emanager != nullptr)
  2870. {
  2871. emanager->ResetCallStackForTopLevelCall(elog->GetLastEventTime());
  2872. }
  2873. }
  2874. }
  2875. #endif
  2876. Js::Var varResult = scriptFunction->CallRootFunction(args, scriptContext, true);
  2877. if (result != nullptr)
  2878. {
  2879. *result = varResult;
  2880. }
  2881. #if ENABLE_TTD
  2882. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext))
  2883. {
  2884. _actionEntryPopper.SetResult(result);
  2885. }
  2886. #endif
  2887. }
  2888. return JsNoError;
  2889. });
  2890. }
  2891. JsErrorCode RunScriptCore(const char *script, JsSourceContext sourceContext,
  2892. const char *sourceUrl, bool parseOnly, JsParseScriptAttributes parseAttributes,
  2893. bool isSourceModule, JsValueRef *result)
  2894. {
  2895. utf8::NarrowToWide url((LPCSTR)sourceUrl);
  2896. if (!url)
  2897. {
  2898. return JsErrorOutOfMemory;
  2899. }
  2900. return RunScriptCore(nullptr, reinterpret_cast<const byte*>(script), strlen(script),
  2901. LoadScriptFlag_Utf8Source, sourceContext, url, parseOnly, parseAttributes,
  2902. isSourceModule, result);
  2903. }
  2904. JsErrorCode RunScriptCore(const WCHAR *script, JsSourceContext sourceContext,
  2905. const WCHAR *sourceUrl, bool parseOnly, JsParseScriptAttributes parseAttributes,
  2906. bool isSourceModule, JsValueRef *result)
  2907. {
  2908. return RunScriptCore(nullptr, reinterpret_cast<const byte*>(script),
  2909. wcslen(script) * sizeof(WCHAR),
  2910. LoadScriptFlag_None, sourceContext, sourceUrl, parseOnly,
  2911. parseAttributes, isSourceModule, result);
  2912. }
  2913. #ifdef _WIN32
  2914. CHAKRA_API JsParseScript(_In_z_ const WCHAR * script, _In_ JsSourceContext sourceContext,
  2915. _In_z_ const WCHAR *sourceUrl, _Out_ JsValueRef * result)
  2916. {
  2917. return RunScriptCore(script, sourceContext, sourceUrl, true,
  2918. JsParseScriptAttributeNone, false /*isModule*/, result);
  2919. }
  2920. CHAKRA_API JsParseScriptWithAttributes(
  2921. _In_z_ const WCHAR *script,
  2922. _In_ JsSourceContext sourceContext,
  2923. _In_z_ const WCHAR *sourceUrl,
  2924. _In_ JsParseScriptAttributes parseAttributes,
  2925. _Out_ JsValueRef *result)
  2926. {
  2927. return RunScriptCore(script, sourceContext, sourceUrl, true,
  2928. parseAttributes, false /*isModule*/, result);
  2929. }
  2930. CHAKRA_API JsRunScript(_In_z_ const WCHAR * script, _In_ JsSourceContext sourceContext,
  2931. _In_z_ const WCHAR *sourceUrl, _Out_ JsValueRef * result)
  2932. {
  2933. return RunScriptCore(script, sourceContext, sourceUrl, false,
  2934. JsParseScriptAttributeNone, false /*isModule*/, result);
  2935. }
  2936. CHAKRA_API JsExperimentalApiRunModule(_In_z_ const WCHAR * script,
  2937. _In_ JsSourceContext sourceContext, _In_z_ const WCHAR *sourceUrl,
  2938. _Out_ JsValueRef * result)
  2939. {
  2940. return RunScriptCore(script, sourceContext, sourceUrl, false,
  2941. JsParseScriptAttributeNone, true, result);
  2942. }
  2943. #endif
  2944. JsErrorCode JsSerializeScriptCore(const byte *script, size_t cb,
  2945. LoadScriptFlag loadScriptFlag, BYTE *functionTable, int functionTableSize,
  2946. unsigned char *buffer, unsigned int *bufferSize, JsValueRef scriptSource)
  2947. {
  2948. Js::JavascriptFunction *function;
  2949. CompileScriptException se;
  2950. JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  2951. PARAM_NOT_NULL(script);
  2952. PARAM_NOT_NULL(bufferSize);
  2953. if (*bufferSize > 0)
  2954. {
  2955. PARAM_NOT_NULL(buffer);
  2956. ZeroMemory(buffer, *bufferSize);
  2957. }
  2958. if (scriptContext->IsScriptContextInDebugMode())
  2959. {
  2960. return JsErrorCannotSerializeDebugScript;
  2961. }
  2962. SourceContextInfo * sourceContextInfo = scriptContext->GetSourceContextInfo(JS_SOURCE_CONTEXT_NONE, nullptr);
  2963. Assert(sourceContextInfo != nullptr);
  2964. const int chsize = (loadScriptFlag & LoadScriptFlag_Utf8Source) ? sizeof(utf8char_t) : sizeof(WCHAR);
  2965. SRCINFO si = {
  2966. /* sourceContextInfo */ sourceContextInfo,
  2967. /* dlnHost */ 0,
  2968. /* ulColumnHost */ 0,
  2969. /* lnMinHost */ 0,
  2970. /* ichMinHost */ 0,
  2971. /* ichLimHost */ static_cast<ULONG>(cb / chsize), // OK to truncate since this is used to limit sourceText in debugDocument/compilation errors.
  2972. /* ulCharOffset */ 0,
  2973. /* mod */ kmodGlobal,
  2974. /* grfsi */ 0
  2975. };
  2976. bool isSerializeByteCodeForLibrary = false;
  2977. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  2978. isSerializeByteCodeForLibrary = JsrtContext::GetCurrent()->GetRuntime()->IsSerializeByteCodeForLibrary();
  2979. #endif
  2980. Js::Utf8SourceInfo* sourceInfo = nullptr;
  2981. loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_disableDeferredParse);
  2982. if (isSerializeByteCodeForLibrary)
  2983. {
  2984. loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_isByteCodeBufferForLibrary);
  2985. }
  2986. else
  2987. {
  2988. loadScriptFlag = (LoadScriptFlag)(loadScriptFlag | LoadScriptFlag_Expression);
  2989. }
  2990. function = scriptContext->LoadScript(script, cb, &si, &se, &sourceInfo,
  2991. Js::Constants::GlobalCode, loadScriptFlag, scriptSource);
  2992. return JsNoError;
  2993. });
  2994. if (errorCode != JsNoError)
  2995. {
  2996. return errorCode;
  2997. }
  2998. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode {
  2999. if (function == nullptr)
  3000. {
  3001. HandleScriptCompileError(scriptContext, &se);
  3002. return JsErrorScriptCompile;
  3003. }
  3004. // Could we have a deserialized function in this case?
  3005. // If we are going to serialize it, a check isn't to expensive
  3006. if (CONFIG_FLAG(ForceSerialized) && function->GetFunctionProxy() != nullptr) {
  3007. function->GetFunctionProxy()->EnsureDeserialized();
  3008. }
  3009. Js::FunctionBody *functionBody = function->GetFunctionBody();
  3010. const Js::Utf8SourceInfo *sourceInfo = functionBody->GetUtf8SourceInfo();
  3011. size_t cSourceCodeLength = sourceInfo->GetCbLength(_u("JsSerializeScript"));
  3012. // truncation of code length can lead to accessing random memory. Reject the call.
  3013. if (cSourceCodeLength > DWORD_MAX)
  3014. {
  3015. return JsErrorOutOfMemory;
  3016. }
  3017. LPCUTF8 utf8Code = sourceInfo->GetSource(_u("JsSerializeScript"));
  3018. DWORD dwFlags = 0;
  3019. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  3020. dwFlags = JsrtContext::GetCurrent()->GetRuntime()->IsSerializeByteCodeForLibrary() ? GENERATE_BYTE_CODE_BUFFER_LIBRARY : 0;
  3021. #endif
  3022. BEGIN_TEMP_ALLOCATOR(tempAllocator, scriptContext, _u("ByteCodeSerializer"));
  3023. // We cast buffer size to DWORD* because on Windows, DWORD = unsigned long = unsigned int
  3024. // On 64-bit clang on linux, this is not true, unsigned long is larger than unsigned int
  3025. // However, the PAL defines DWORD for us on linux as unsigned int so the cast is safe here.
  3026. HRESULT hr = Js::ByteCodeSerializer::SerializeToBuffer(scriptContext,
  3027. tempAllocator, static_cast<DWORD>(cSourceCodeLength), utf8Code,
  3028. functionBody, functionBody->GetHostSrcInfo(), false, &buffer,
  3029. (DWORD*) bufferSize, dwFlags);
  3030. END_TEMP_ALLOCATOR(tempAllocator, scriptContext);
  3031. if (SUCCEEDED(hr))
  3032. {
  3033. return JsNoError;
  3034. }
  3035. else
  3036. {
  3037. return JsErrorScriptCompile;
  3038. }
  3039. });
  3040. }
  3041. CHAKRA_API JsSerializeScript(_In_z_ const WCHAR *script, _Out_writes_to_opt_(*bufferSize,
  3042. *bufferSize) unsigned char *buffer,
  3043. _Inout_ unsigned int *bufferSize)
  3044. {
  3045. return JsSerializeScriptCore((const byte*)script, wcslen(script) * sizeof(WCHAR),
  3046. LoadScriptFlag_None, nullptr, 0, buffer, bufferSize, nullptr);
  3047. }
  3048. template <typename TLoadCallback, typename TUnloadCallback>
  3049. JsErrorCode RunSerializedScriptCore(
  3050. TLoadCallback scriptLoadCallback, TUnloadCallback scriptUnloadCallback,
  3051. JsSourceContext scriptLoadSourceContext, // only used by scriptLoadCallback
  3052. unsigned char *buffer, Js::ArrayBuffer* bufferVal,
  3053. JsSourceContext sourceContext, const WCHAR *sourceUrl,
  3054. bool parseOnly, JsValueRef *result)
  3055. {
  3056. Js::JavascriptFunction *function;
  3057. JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
  3058. if (result != nullptr)
  3059. {
  3060. *result = nullptr;
  3061. }
  3062. PARAM_NOT_NULL(buffer);
  3063. PARAM_NOT_NULL(sourceUrl);
  3064. Js::ISourceHolder *sourceHolder = nullptr;
  3065. PARAM_NOT_NULL(scriptLoadCallback);
  3066. PARAM_NOT_NULL(scriptUnloadCallback);
  3067. typedef Js::JsrtSourceHolder<TLoadCallback, TUnloadCallback> TSourceHolder;
  3068. sourceHolder = RecyclerNewFinalized(scriptContext->GetRecycler(), TSourceHolder,
  3069. scriptLoadCallback, scriptUnloadCallback, scriptLoadSourceContext, bufferVal);
  3070. SourceContextInfo *sourceContextInfo;
  3071. SRCINFO *hsi;
  3072. Field(Js::FunctionBody*) functionBody = nullptr;
  3073. HRESULT hr;
  3074. sourceContextInfo = scriptContext->GetSourceContextInfo(sourceContext, nullptr);
  3075. if (sourceContextInfo == nullptr)
  3076. {
  3077. sourceContextInfo = scriptContext->CreateSourceContextInfo(sourceContext, sourceUrl,
  3078. wcslen(sourceUrl), nullptr);
  3079. }
  3080. SRCINFO si = {
  3081. /* sourceContextInfo */ sourceContextInfo,
  3082. /* dlnHost */ 0,
  3083. /* ulColumnHost */ 0,
  3084. /* lnMinHost */ 0,
  3085. /* ichMinHost */ 0,
  3086. /* ichLimHost */ 0, // xplat-todo: need to compute this?
  3087. /* ulCharOffset */ 0,
  3088. /* mod */ kmodGlobal,
  3089. /* grfsi */ 0
  3090. };
  3091. uint32 flags = 0;
  3092. if (CONFIG_FLAG(CreateFunctionProxy) && !scriptContext->IsProfiling())
  3093. {
  3094. flags = fscrAllowFunctionProxy;
  3095. }
  3096. hsi = scriptContext->AddHostSrcInfo(&si);
  3097. hr = Js::ByteCodeSerializer::DeserializeFromBuffer(scriptContext, flags, sourceHolder,
  3098. hsi, buffer, nullptr, &functionBody);
  3099. if (FAILED(hr))
  3100. {
  3101. return JsErrorBadSerializedScript;
  3102. }
  3103. function = scriptContext->GetLibrary()->CreateScriptFunction(functionBody);
  3104. JsrtContext * context = JsrtContext::GetCurrent();
  3105. context->OnScriptLoad(function, functionBody->GetUtf8SourceInfo(), nullptr);
  3106. return JsNoError;
  3107. });
  3108. if (errorCode != JsNoError)
  3109. {
  3110. return errorCode;
  3111. }
  3112. return ContextAPIWrapper_NoRecord<false>([&](Js::ScriptContext* scriptContext) -> JsErrorCode {
  3113. if (parseOnly)
  3114. {
  3115. PARAM_NOT_NULL(result);
  3116. *result = function;
  3117. }
  3118. else
  3119. {
  3120. Js::Var varResult = function->CallRootFunction(Js::Arguments(0, nullptr), scriptContext, true);
  3121. if (result != nullptr)
  3122. {
  3123. *result = varResult;
  3124. }
  3125. }
  3126. return JsNoError;
  3127. });
  3128. }
  3129. static void CHAKRA_CALLBACK DummyScriptUnloadCallback(_In_ JsSourceContext sourceContext)
  3130. {
  3131. // Do nothing
  3132. }
  3133. #ifdef _WIN32
  3134. static bool CHAKRA_CALLBACK DummyScriptLoadSourceCallback(_In_ JsSourceContext sourceContext, _Outptr_result_z_ const WCHAR** scriptBuffer)
  3135. {
  3136. // sourceContext is actually the script source pointer
  3137. *scriptBuffer = reinterpret_cast<const WCHAR*>(sourceContext);
  3138. return true;
  3139. }
  3140. CHAKRA_API JsParseSerializedScript(_In_z_ const WCHAR * script, _In_ unsigned char *buffer,
  3141. _In_ JsSourceContext sourceContext,
  3142. _In_z_ const WCHAR *sourceUrl,
  3143. _Out_ JsValueRef * result)
  3144. {
  3145. return RunSerializedScriptCore(
  3146. DummyScriptLoadSourceCallback, DummyScriptUnloadCallback,
  3147. reinterpret_cast<JsSourceContext>(script), // use script source pointer as scriptLoadSourceContext
  3148. buffer, nullptr, sourceContext, sourceUrl, true, result);
  3149. }
  3150. CHAKRA_API JsRunSerializedScript(_In_z_ const WCHAR * script, _In_ unsigned char *buffer,
  3151. _In_ JsSourceContext sourceContext,
  3152. _In_z_ const WCHAR *sourceUrl,
  3153. _Out_ JsValueRef * result)
  3154. {
  3155. return RunSerializedScriptCore(
  3156. DummyScriptLoadSourceCallback, DummyScriptUnloadCallback,
  3157. reinterpret_cast<JsSourceContext>(script), // use script source pointer as scriptLoadSourceContext
  3158. buffer, nullptr, sourceContext, sourceUrl, false, result);
  3159. }
  3160. CHAKRA_API JsParseSerializedScriptWithCallback(_In_ JsSerializedScriptLoadSourceCallback scriptLoadCallback,
  3161. _In_ JsSerializedScriptUnloadCallback scriptUnloadCallback,
  3162. _In_ unsigned char *buffer, _In_ JsSourceContext sourceContext,
  3163. _In_z_ const WCHAR *sourceUrl, _Out_ JsValueRef * result)
  3164. {
  3165. return RunSerializedScriptCore(
  3166. scriptLoadCallback, scriptUnloadCallback,
  3167. sourceContext, // use the same user provided sourceContext as scriptLoadSourceContext
  3168. buffer, nullptr, sourceContext, sourceUrl, true, result);
  3169. }
  3170. CHAKRA_API JsRunSerializedScriptWithCallback(_In_ JsSerializedScriptLoadSourceCallback scriptLoadCallback,
  3171. _In_ JsSerializedScriptUnloadCallback scriptUnloadCallback,
  3172. _In_ unsigned char *buffer, _In_ JsSourceContext sourceContext,
  3173. _In_z_ const WCHAR *sourceUrl, _Out_opt_ JsValueRef * result)
  3174. {
  3175. return RunSerializedScriptCore(
  3176. scriptLoadCallback, scriptUnloadCallback,
  3177. sourceContext, // use the same user provided sourceContext as scriptLoadSourceContext
  3178. buffer, nullptr, sourceContext, sourceUrl, false, result);
  3179. }
  3180. #endif // _WIN32
  3181. /////////////////////
  3182. CHAKRA_API JsTTDCreateRecordRuntime(_In_ JsRuntimeAttributes attributes, _In_ size_t snapInterval, _In_ size_t snapHistoryLength,
  3183. _In_ TTDOpenResourceStreamCallback openResourceStream, _In_ JsTTDWriteBytesToStreamCallback writeBytesToStream, _In_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream,
  3184. _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtime)
  3185. {
  3186. #if !ENABLE_TTD
  3187. return JsErrorCategoryUsage;
  3188. #else
  3189. if(snapInterval > UINT32_MAX || snapHistoryLength > UINT32_MAX)
  3190. {
  3191. return JsErrorInvalidArgument;
  3192. }
  3193. return CreateRuntimeCore(attributes, nullptr, 0, true, false, false, (uint32)snapInterval, (uint32)snapHistoryLength,
  3194. openResourceStream, nullptr, writeBytesToStream, flushAndCloseStream,
  3195. threadService, runtime);
  3196. #endif
  3197. }
  3198. CHAKRA_API JsTTDCreateReplayRuntime(_In_ JsRuntimeAttributes attributes, _In_reads_(infoUriCount) const char* infoUri, _In_ size_t infoUriCount, _In_ bool enableDebugging,
  3199. _In_ TTDOpenResourceStreamCallback openResourceStream, _In_ JsTTDReadBytesFromStreamCallback readBytesFromStream, _In_ JsTTDFlushAndCloseStreamCallback flushAndCloseStream,
  3200. _In_opt_ JsThreadServiceCallback threadService, _Out_ JsRuntimeHandle *runtime)
  3201. {
  3202. #if !ENABLE_TTD
  3203. return JsErrorCategoryUsage;
  3204. #else
  3205. return CreateRuntimeCore(attributes, infoUri, infoUriCount, false, true, enableDebugging, UINT_MAX, UINT_MAX,
  3206. openResourceStream, readBytesFromStream, nullptr, flushAndCloseStream,
  3207. threadService, runtime);
  3208. #endif
  3209. }
  3210. CHAKRA_API JsTTDCreateContext(_In_ JsRuntimeHandle runtimeHandle, _In_ bool useRuntimeTTDMode, _Out_ JsContextRef *newContext)
  3211. {
  3212. #if !ENABLE_TTD
  3213. return JsErrorCategoryUsage;
  3214. #else
  3215. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  3216. PARAM_NOT_NULL(newContext);
  3217. VALIDATE_INCOMING_RUNTIME_HANDLE(runtimeHandle);
  3218. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  3219. ThreadContext * threadContext = runtime->GetThreadContext();
  3220. TTDAssert(threadContext->IsRuntimeInTTDMode(), "Need to create in TTD Mode.");
  3221. bool inRecord = false;
  3222. bool activelyRecording = false;
  3223. bool inReplay = false;
  3224. TTDRecorder dummyActionEntryPopper;
  3225. if(useRuntimeTTDMode)
  3226. {
  3227. threadContext->TTDLog->GetModesForExplicitContextCreate(inRecord, activelyRecording, inReplay);
  3228. }
  3229. return CreateContextCore(runtimeHandle, dummyActionEntryPopper, inRecord, activelyRecording, inReplay, newContext);
  3230. });
  3231. #endif
  3232. }
  3233. CHAKRA_API JsTTDNotifyContextDestroy(_In_ JsContextRef context)
  3234. {
  3235. #if !ENABLE_TTD
  3236. return JsErrorCategoryUsage;
  3237. #else
  3238. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  3239. if(threadContext && threadContext->IsRuntimeInTTDMode())
  3240. {
  3241. Js::ScriptContext* ctx = static_cast<JsrtContext*>(context)->GetScriptContext();
  3242. threadContext->TTDContext->NotifyCtxDestroyInRecord(ctx);
  3243. }
  3244. return JsNoError;
  3245. #endif
  3246. }
  3247. CHAKRA_API JsTTDStart()
  3248. {
  3249. #if !ENABLE_TTD
  3250. return JsErrorCategoryUsage;
  3251. #else
  3252. JsrtContext *currentContext = JsrtContext::GetCurrent();
  3253. JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
  3254. TTDAssert(cCheck == JsNoError, "Must have valid context when starting TTD.");
  3255. Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
  3256. TTDAssert(scriptContext->IsTTDRecordOrReplayModeEnabled(), "Need to create in TTD Record Mode.");
  3257. #if ENABLE_NATIVE_CODEGEN
  3258. TTDAssert(JITManager::GetJITManager() == nullptr || !JITManager::GetJITManager()->IsOOPJITEnabled(), "TTD cannot run with OOP JIT yet!!!");
  3259. #endif
  3260. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  3261. {
  3262. if(scriptContext->IsTTDRecordModeEnabled())
  3263. {
  3264. scriptContext->GetThreadContext()->TTDLog->DoSnapshotExtract();
  3265. }
  3266. //Want to verify that we are at top-level of dispatch
  3267. scriptContext->GetThreadContext()->TTDLog->PushMode(TTD::TTDMode::CurrentlyEnabled);
  3268. return JsNoError;
  3269. });
  3270. #endif
  3271. }
  3272. CHAKRA_API JsTTDStop()
  3273. {
  3274. #if !ENABLE_TTD
  3275. return JsErrorCategoryUsage;
  3276. #else
  3277. JsrtContext *currentContext = JsrtContext::GetCurrent();
  3278. JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
  3279. TTDAssert(cCheck == JsNoError, "Must have valid context when starting TTD.");
  3280. Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
  3281. TTDAssert(scriptContext->IsTTDRecordOrReplayModeEnabled(), "Need to create in TTD mode.");
  3282. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  3283. {
  3284. scriptContext->GetThreadContext()->TTDLog->PopMode(TTD::TTDMode::CurrentlyEnabled);
  3285. if(scriptContext->IsTTDRecordModeEnabled())
  3286. {
  3287. scriptContext->GetThreadContext()->TTDLog->UnloadAllLogData();
  3288. }
  3289. return JsNoError;
  3290. });
  3291. #endif
  3292. }
  3293. CHAKRA_API JsTTDPauseTimeTravelBeforeRuntimeOperation()
  3294. {
  3295. #if !ENABLE_TTD
  3296. return JsErrorCategoryUsage;
  3297. #else
  3298. JsrtContext *currentContext = JsrtContext::GetCurrent();
  3299. JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
  3300. TTDAssert(cCheck == JsNoError, "Must have valid context when changing debugger mode.");
  3301. Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
  3302. ThreadContext* threadContext = scriptContext->GetThreadContext();
  3303. if(threadContext->IsRuntimeInTTDMode())
  3304. {
  3305. threadContext->TTDLog->PushMode(TTD::TTDMode::ExcludedExecutionDebuggerAction);
  3306. }
  3307. return JsNoError;
  3308. #endif
  3309. }
  3310. CHAKRA_API JsTTDReStartTimeTravelAfterRuntimeOperation()
  3311. {
  3312. #if !ENABLE_TTD
  3313. return JsErrorCategoryUsage;
  3314. #else
  3315. JsrtContext *currentContext = JsrtContext::GetCurrent();
  3316. JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
  3317. TTDAssert(cCheck == JsNoError, "Must have valid context when changing debugger mode.");
  3318. Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
  3319. ThreadContext* threadContext = scriptContext->GetThreadContext();
  3320. if(threadContext->IsRuntimeInTTDMode())
  3321. {
  3322. threadContext->TTDLog->PopMode(TTD::TTDMode::ExcludedExecutionDebuggerAction);
  3323. }
  3324. return JsNoError;
  3325. #endif
  3326. }
  3327. CHAKRA_API JsTTDNotifyYield()
  3328. {
  3329. #if !ENABLE_TTD
  3330. return JsErrorCategoryUsage;
  3331. #else
  3332. JsrtContext *currentContext = JsrtContext::GetCurrent();
  3333. JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
  3334. if(cCheck != JsNoError)
  3335. {
  3336. return JsNoError; //we are ok just aren't going to do any TTD related work
  3337. }
  3338. Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
  3339. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  3340. {
  3341. if(scriptContext->IsTTDRecordModeEnabled())
  3342. {
  3343. scriptContext->GetThreadContext()->TTDLog->RecordJsRTEventLoopYieldPoint();
  3344. }
  3345. return JsNoError;
  3346. });
  3347. #endif
  3348. }
  3349. CHAKRA_API JsTTDNotifyLongLivedReferenceAdd(_In_ JsValueRef value)
  3350. {
  3351. #if !ENABLE_TTD
  3352. return JsErrorCategoryUsage;
  3353. #else
  3354. return GlobalAPIWrapper([&](TTDRecorder& _actionEntryPopper) -> JsErrorCode
  3355. {
  3356. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  3357. if(threadContext == nullptr)
  3358. {
  3359. return JsErrorNoCurrentContext;
  3360. }
  3361. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(value);
  3362. if(obj->GetScriptContext()->IsTTDRecordModeEnabled())
  3363. {
  3364. if(obj->GetScriptContext()->ShouldPerformRecordAction())
  3365. {
  3366. threadContext->TTDLog->RecordJsRTAddWeakRootRef(_actionEntryPopper, (Js::Var)value);
  3367. }
  3368. threadContext->TTDContext->AddRootRef_Record(TTD_CONVERT_OBJ_TO_LOG_PTR_ID(obj), obj);
  3369. }
  3370. return JsNoError;
  3371. });
  3372. #endif
  3373. }
  3374. CHAKRA_API JsTTDHostExit(_In_ int statusCode)
  3375. {
  3376. #if !ENABLE_TTD
  3377. return JsErrorCategoryUsage;
  3378. #else
  3379. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  3380. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTHostExitProcess, statusCode);
  3381. return JsNoError;
  3382. });
  3383. #endif
  3384. }
  3385. CHAKRA_API JsTTDRawBufferCopySyncIndirect(_In_ JsValueRef dst, _In_ size_t dstIndex, _In_ JsValueRef src, _In_ size_t srcIndex, _In_ size_t count)
  3386. {
  3387. #if !ENABLE_TTD
  3388. return JsErrorCategoryUsage;
  3389. #else
  3390. if(dstIndex > UINT32_MAX || srcIndex > UINT32_MAX || count > UINT32_MAX)
  3391. {
  3392. return JsErrorInvalidArgument;
  3393. }
  3394. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  3395. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferCopySync, dst, (uint32)dstIndex, src, (uint32)srcIndex, (uint32)count);
  3396. return JsNoError;
  3397. });
  3398. #endif
  3399. }
  3400. CHAKRA_API JsTTDRawBufferModifySyncIndirect(_In_ JsValueRef buffer, _In_ size_t index, _In_ size_t count)
  3401. {
  3402. #if !ENABLE_TTD
  3403. return JsErrorCategoryUsage;
  3404. #else
  3405. if(index > UINT32_MAX || count > UINT32_MAX)
  3406. {
  3407. return JsErrorInvalidArgument;
  3408. }
  3409. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  3410. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferModifySync, buffer, (uint32)index, (uint32)count);
  3411. return JsNoError;
  3412. });
  3413. #endif
  3414. }
  3415. CHAKRA_API JsTTDRawBufferAsyncModificationRegister(_In_ JsValueRef instance, _In_ byte* initialModPos)
  3416. {
  3417. #if !ENABLE_TTD
  3418. return JsErrorCategoryUsage;
  3419. #else
  3420. JsValueRef addRefObj = nullptr;
  3421. JsErrorCode addRefResult = ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  3422. if (scriptContext->IsTTDRecordModeEnabled())
  3423. {
  3424. TTDAssert(Js::ArrayBuffer::Is(instance), "Not array buffer object!!!");
  3425. Js::ArrayBuffer* dstBuff = Js::ArrayBuffer::FromVar(instance);
  3426. addRefObj = dstBuff;
  3427. TTDAssert(dstBuff->GetBuffer() <= initialModPos && initialModPos < dstBuff->GetBuffer() + dstBuff->GetByteLength(), "Not array buffer object!!!");
  3428. TTDAssert(initialModPos - dstBuff->GetBuffer() < UINT32_MAX, "This is really big!!!");
  3429. ptrdiff_t index = initialModPos - Js::ArrayBuffer::FromVar(instance)->GetBuffer();
  3430. scriptContext->TTDContextInfo->AddToAsyncPendingList(dstBuff, (uint32)index);
  3431. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferAsyncModificationRegister, instance, (uint32)index);
  3432. }
  3433. return JsNoError;
  3434. });
  3435. if(addRefResult != JsNoError)
  3436. {
  3437. return addRefResult;
  3438. }
  3439. //We need to root add ref so we can find this during replay!!!
  3440. if(addRefObj == nullptr)
  3441. {
  3442. return JsNoError;
  3443. }
  3444. else
  3445. {
  3446. return JsAddRef(addRefObj, nullptr);
  3447. }
  3448. #endif
  3449. }
  3450. CHAKRA_API JsTTDRawBufferAsyncModifyComplete(_In_ byte* finalModPos)
  3451. {
  3452. #if !ENABLE_TTD
  3453. return JsErrorCategoryUsage;
  3454. #else
  3455. JsValueRef releaseObj = nullptr;
  3456. JsErrorCode releaseStatus = ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  3457. if (scriptContext->IsTTDRecordModeEnabled())
  3458. {
  3459. TTD::TTDPendingAsyncBufferModification pendingAsyncInfo = { 0 };
  3460. scriptContext->TTDContextInfo->GetFromAsyncPendingList(&pendingAsyncInfo, finalModPos);
  3461. Js::ArrayBuffer* dstBuff = Js::ArrayBuffer::FromVar(pendingAsyncInfo.ArrayBufferVar);
  3462. releaseObj = dstBuff;
  3463. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTRawBufferAsyncModifyComplete, pendingAsyncInfo, finalModPos);
  3464. }
  3465. return JsNoError;
  3466. });
  3467. if(releaseStatus != JsNoError)
  3468. {
  3469. return releaseStatus;
  3470. }
  3471. //We need to root release ref so we can free this in replay if needed!!!
  3472. if(releaseObj == nullptr)
  3473. {
  3474. return JsNoError;
  3475. }
  3476. else
  3477. {
  3478. return JsRelease(releaseObj, nullptr);
  3479. }
  3480. #endif
  3481. }
  3482. CHAKRA_API JsTTDCheckAndAssertIfTTDRunning(_In_ const char* msg)
  3483. {
  3484. #if ENABLE_TTD
  3485. JsrtContext* context = JsrtContext::GetCurrent();
  3486. TTDAssert(context == nullptr || !context->GetScriptContext()->ShouldPerformRecordAction(), msg);
  3487. #endif
  3488. return JsNoError;
  3489. }
  3490. CHAKRA_API JsTTDGetSnapTimeTopLevelEventMove(_In_ JsRuntimeHandle runtimeHandle,
  3491. _In_ JsTTDMoveMode moveMode, _In_opt_ uint32_t kthEvent,
  3492. _Inout_ int64_t* targetEventTime, _Out_ int64_t* targetStartSnapTime,
  3493. _Out_opt_ int64_t* targetEndSnapTime)
  3494. {
  3495. #if !ENABLE_TTD
  3496. return JsErrorCategoryUsage;
  3497. #else
  3498. JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
  3499. ThreadContext* threadContext = runtime->GetThreadContext();
  3500. *targetStartSnapTime = -1;
  3501. if(targetEndSnapTime != nullptr)
  3502. {
  3503. *targetEndSnapTime = -1;
  3504. }
  3505. TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
  3506. //If we requested a move to a specific event then extract the event count and try to find it
  3507. if((moveMode & JsTTDMoveMode::JsTTDMoveFirstEvent) == JsTTDMoveMode::JsTTDMoveFirstEvent)
  3508. {
  3509. *targetEventTime = threadContext->TTDLog->GetFirstEventTimeInLog();
  3510. if(*targetEventTime == -1)
  3511. {
  3512. return JsErrorCategoryUsage;
  3513. }
  3514. }
  3515. else if((moveMode & JsTTDMoveMode::JsTTDMoveLastEvent) == JsTTDMoveMode::JsTTDMoveLastEvent)
  3516. {
  3517. *targetEventTime = threadContext->TTDLog->GetLastEventTimeInLog();
  3518. if(*targetEventTime == -1)
  3519. {
  3520. return JsErrorCategoryUsage;
  3521. }
  3522. }
  3523. else if((moveMode & JsTTDMoveMode::JsTTDMoveKthEvent) == JsTTDMoveMode::JsTTDMoveKthEvent)
  3524. {
  3525. *targetEventTime = threadContext->TTDLog->GetKthEventTimeInLog(kthEvent);
  3526. if(*targetEventTime == -1)
  3527. {
  3528. return JsErrorCategoryUsage;
  3529. }
  3530. }
  3531. else
  3532. {
  3533. ;
  3534. }
  3535. #ifdef __APPLE__
  3536. //TODO: Explicit cast of ptr since compiler gets confused -- resolve in PAL later
  3537. static_assert(sizeof(int64_t) == sizeof(int64), "int64_t and int64 size mis-match");
  3538. *targetStartSnapTime = threadContext->TTDLog->FindSnapTimeForEventTime(*targetEventTime, (int64*)targetEndSnapTime);
  3539. #else
  3540. *targetStartSnapTime = threadContext->TTDLog->FindSnapTimeForEventTime(*targetEventTime, targetEndSnapTime);
  3541. #endif
  3542. return JsNoError;
  3543. #endif
  3544. }
  3545. CHAKRA_API JsTTDGetSnapShotBoundInterval(_In_ JsRuntimeHandle runtimeHandle, _In_ int64_t targetEventTime, _Out_ int64_t* startSnapTime, _Out_ int64_t* endSnapTime)
  3546. {
  3547. #if !ENABLE_TTD
  3548. return JsErrorCategoryUsage;
  3549. #else
  3550. JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
  3551. ThreadContext* threadContext = runtime->GetThreadContext();
  3552. TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
  3553. #ifdef __APPLE__
  3554. //TODO: Explicit cast of ptr since compiler gets confused -- resolve in PAL later
  3555. static_assert(sizeof(int64_t) == sizeof(int64), "int64_t and int64 size mis-match");
  3556. threadContext->TTDLog->GetSnapShotBoundInterval(targetEventTime, (int64*)startSnapTime, (int64*)endSnapTime);
  3557. #else
  3558. threadContext->TTDLog->GetSnapShotBoundInterval(targetEventTime, startSnapTime, endSnapTime);
  3559. #endif
  3560. return JsNoError;
  3561. #endif
  3562. }
  3563. CHAKRA_API JsTTDGetPreviousSnapshotInterval(_In_ JsRuntimeHandle runtimeHandle, _In_ int64_t currentSnapStartTime, _Out_ int64_t* previousSnapTime)
  3564. {
  3565. #if !ENABLE_TTD
  3566. return JsErrorCategoryUsage;
  3567. #else
  3568. JsrtRuntime * runtime = JsrtRuntime::FromHandle(runtimeHandle);
  3569. ThreadContext * threadContext = runtime->GetThreadContext();
  3570. TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
  3571. *previousSnapTime = threadContext->TTDLog->GetPreviousSnapshotInterval(currentSnapStartTime);
  3572. return JsNoError;
  3573. #endif
  3574. }
  3575. #if ENABLE_TTD
  3576. //Helper method for resetting breakpoint info around snapshot inflate
  3577. JsErrorCode TTDHandleBreakpointInfoAndInflate(int64_t snapTime, JsrtRuntime* runtime, ThreadContext* threadContext)
  3578. {
  3579. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  3580. {
  3581. if(threadContext->TTDLog->IsDebugModeFlagSet())
  3582. {
  3583. threadContext->TTDExecutionInfo->LoadPreservedBPInfo(threadContext);
  3584. }
  3585. threadContext->TTDLog->DoSnapshotInflate(snapTime);
  3586. threadContext->TTDLog->ResetCallStackForTopLevelCall(-1);
  3587. if(threadContext->TTDExecutionInfo != nullptr)
  3588. {
  3589. threadContext->TTDExecutionInfo->ResetCallStackForTopLevelCall(-1);
  3590. }
  3591. return JsNoError;
  3592. });
  3593. }
  3594. #endif
  3595. CHAKRA_API JsTTDPreExecuteSnapShotInterval(_In_ JsRuntimeHandle runtimeHandle, _In_ int64_t startSnapTime, _In_ int64_t endSnapTime, _In_ JsTTDMoveMode moveMode, _Out_ int64_t* newTargetEventTime)
  3596. {
  3597. #if !ENABLE_TTD
  3598. return JsErrorCategoryUsage;
  3599. #else
  3600. *newTargetEventTime = -1;
  3601. JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
  3602. ThreadContext* threadContext = runtime->GetThreadContext();
  3603. TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
  3604. TTD::EventLog* elog = threadContext->TTDLog;
  3605. TTD::ExecutionInfoManager* emanager = threadContext->TTDExecutionInfo;
  3606. JsErrorCode res = JsNoError;
  3607. JsErrorCode inflateStatus = TTDHandleBreakpointInfoAndInflate(startSnapTime, runtime, threadContext);
  3608. if(inflateStatus != JsNoError)
  3609. {
  3610. return inflateStatus;
  3611. }
  3612. //If we are in the "active" segment set the continue breakpoint
  3613. if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment)
  3614. {
  3615. GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  3616. {
  3617. emanager->SetBPInfoForActiveSegmentContinueScan(threadContext->TTDContext);
  3618. return JsNoError;
  3619. });
  3620. }
  3621. elog->PushMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
  3622. elog->PushMode(TTD::TTDMode::DebuggerLogBreakpoints);
  3623. try
  3624. {
  3625. if(endSnapTime == -1)
  3626. {
  3627. elog->ReplayRootEventsToTime(TTD_EVENT_MAXTIME);
  3628. }
  3629. else
  3630. {
  3631. elog->ReplayRootEventsToTime(endSnapTime);
  3632. }
  3633. }
  3634. catch(TTD::TTDebuggerAbortException abortException)
  3635. {
  3636. //If we hit the end of the log or we hit a terminal exception that is fine -- anything else is a problem
  3637. if(!abortException.IsEndOfLog() && !abortException.IsTopLevelException())
  3638. {
  3639. res = JsErrorFatal;
  3640. }
  3641. }
  3642. catch(...) //we are replaying something that should be known to execute successfully so encountering any error is very bad
  3643. {
  3644. res = JsErrorFatal;
  3645. TTDAssert(false, "Unexpected fatal Error");
  3646. }
  3647. elog->PopMode(TTD::TTDMode::DebuggerLogBreakpoints);
  3648. elog->PopMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
  3649. //If we are in the "active" segment un-set the continue breakpoint
  3650. if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinueInActiveBreakpointSegment)
  3651. {
  3652. GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  3653. {
  3654. emanager->ClearBPInfoForActiveSegmentContinueScan(threadContext->TTDContext);
  3655. return JsNoError;
  3656. });
  3657. }
  3658. if((moveMode & JsTTDMoveMode::JsTTDMoveScanIntervalForContinue) == JsTTDMoveMode::JsTTDMoveScanIntervalForContinue)
  3659. {
  3660. bool bpFound = emanager->TryFindAndSetPreviousBP();
  3661. if(bpFound)
  3662. {
  3663. *newTargetEventTime = emanager->GetPendingTTDBPTargetEventTime();
  3664. }
  3665. }
  3666. return res;
  3667. #endif
  3668. }
  3669. CHAKRA_API JsTTDMoveToTopLevelEvent(_In_ JsRuntimeHandle runtimeHandle, _In_ JsTTDMoveMode moveMode, _In_ int64_t snapshotTime, _In_ int64_t eventTime)
  3670. {
  3671. #if !ENABLE_TTD
  3672. return JsErrorCategoryUsage;
  3673. #else
  3674. JsrtRuntime* runtime = JsrtRuntime::FromHandle(runtimeHandle);
  3675. ThreadContext* threadContext = runtime->GetThreadContext();
  3676. TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
  3677. TTD::EventLog* elog = threadContext->TTDLog;
  3678. JsErrorCode res = JsNoError;
  3679. JsErrorCode inflateStatus = TTDHandleBreakpointInfoAndInflate(snapshotTime, runtime, threadContext);
  3680. if(inflateStatus != JsNoError)
  3681. {
  3682. return inflateStatus;
  3683. }
  3684. elog->PushMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
  3685. try
  3686. {
  3687. elog->ReplayRootEventsToTime(eventTime);
  3688. elog->DoRtrSnapIfNeeded();
  3689. }
  3690. catch(...) //we are replaying something that should be known to execute successfully so encountering any error is very bad
  3691. {
  3692. res = JsErrorFatal;
  3693. TTDAssert(false, "Unexpected fatal Error");
  3694. }
  3695. elog->PopMode(TTD::TTDMode::DebuggerSuppressBreakpoints);
  3696. return res;
  3697. #endif
  3698. }
  3699. CHAKRA_API JsTTDReplayExecution(_Inout_ JsTTDMoveMode* moveMode, _Out_ int64_t* rootEventTime)
  3700. {
  3701. #if !ENABLE_TTD
  3702. return JsErrorCategoryUsage;
  3703. #else
  3704. JsrtContext *currentContext = JsrtContext::GetCurrent();
  3705. JsErrorCode cCheck = CheckContext(currentContext, JSRT_MAYBE_TRUE);
  3706. TTDAssert(cCheck == JsNoError, "This shouldn't happen!!!");
  3707. Js::ScriptContext* scriptContext = currentContext->GetScriptContext();
  3708. ThreadContext* threadContext = scriptContext->GetThreadContext();
  3709. TTDAssert(threadContext->IsRuntimeInTTDMode(), "Should only happen in TT debugging mode.");
  3710. TTD::EventLog* elog = threadContext->TTDLog;
  3711. TTD::ExecutionInfoManager* emanager = threadContext->TTDExecutionInfo;
  3712. if(emanager != nullptr)
  3713. {
  3714. JsErrorCode bpstatus = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode
  3715. {
  3716. if((*moveMode & JsTTDMoveMode::JsTTDMoveBreakOnEntry) == JsTTDMoveMode::JsTTDMoveBreakOnEntry)
  3717. {
  3718. emanager->SetBreakOnFirstUserCode();
  3719. }
  3720. //Set the active BP info from the manager (so we will hit the BP in step back operations)
  3721. emanager->SetActiveBPInfoAsNeeded(threadContext->TTDContext);
  3722. return JsNoError;
  3723. });
  3724. if(bpstatus != JsNoError)
  3725. {
  3726. return bpstatus;
  3727. }
  3728. }
  3729. *moveMode = JsTTDMoveMode::JsTTDMoveNone;
  3730. *rootEventTime = -1;
  3731. JsErrorCode res = JsNoError;
  3732. try
  3733. {
  3734. elog->ReplayRootEventsToTime(TTD_EVENT_MAXTIME);
  3735. }
  3736. catch(TTD::TTDebuggerAbortException abortException)
  3737. {
  3738. //if the debugger bails out with a move time request set info on the requested event time here
  3739. //rest of breakpoint info should have been set by the debugger callback before aborting
  3740. if (abortException.IsEventTimeMove() || abortException.IsTopLevelException())
  3741. {
  3742. *moveMode = (JsTTDMoveMode)abortException.GetMoveMode();
  3743. *rootEventTime = abortException.GetTargetEventTime();
  3744. //Check if we are tracking execution and, if so, set the exception locaiton so we can access it later
  3745. if(emanager != nullptr && abortException.IsTopLevelException())
  3746. {
  3747. emanager->SetPendingTTDUnhandledException();
  3748. }
  3749. }
  3750. res = abortException.IsTopLevelException() ? JsErrorCategoryScript : JsNoError;
  3751. }
  3752. catch(...)
  3753. {
  3754. res = JsErrorFatal;
  3755. TTDAssert(false, "Unexpected fatal Error");
  3756. }
  3757. return res;
  3758. #endif
  3759. }
  3760. #ifdef _CHAKRACOREBUILD
  3761. template <class SrcChar, class DstChar>
  3762. static void CastCopy(const SrcChar* src, DstChar* dst, size_t count)
  3763. {
  3764. const SrcChar* end = src + count;
  3765. while (src < end)
  3766. {
  3767. *dst++ = static_cast<DstChar>(*src++);
  3768. }
  3769. }
  3770. CHAKRA_API JsCreateString(
  3771. _In_ const char *content,
  3772. _In_ size_t length,
  3773. _Out_ JsValueRef *value)
  3774. {
  3775. PARAM_NOT_NULL(content);
  3776. PARAM_NOT_NULL(value);
  3777. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  3778. Js::JavascriptString *stringValue = Js::LiteralStringWithPropertyStringPtr::
  3779. NewFromCString(content, (CharCount)length, scriptContext->GetLibrary());
  3780. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue->GetSz(), stringValue->GetLength());
  3781. *value = stringValue;
  3782. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value);
  3783. return JsNoError;
  3784. });
  3785. }
  3786. CHAKRA_API JsCreateStringUtf16(
  3787. _In_ const uint16_t *content,
  3788. _In_ size_t length,
  3789. _Out_ JsValueRef *value)
  3790. {
  3791. PARAM_NOT_NULL(content);
  3792. PARAM_NOT_NULL(value);
  3793. return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  3794. Js::JavascriptString *stringValue = Js::LiteralStringWithPropertyStringPtr::
  3795. NewFromWideString((const char16 *)content, (CharCount)length, scriptContext->GetLibrary());
  3796. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue->GetSz(), stringValue->GetLength());
  3797. *value = stringValue;
  3798. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, value);
  3799. return JsNoError;
  3800. });
  3801. }
  3802. template <class CopyFunc>
  3803. JsErrorCode WriteStringCopy(
  3804. JsValueRef value,
  3805. int start,
  3806. int length,
  3807. _Out_opt_ size_t* written,
  3808. const CopyFunc& copyFunc)
  3809. {
  3810. if (written)
  3811. {
  3812. *written = 0; // init to 0 for default
  3813. }
  3814. const char16* str = nullptr;
  3815. size_t strLength = 0;
  3816. JsErrorCode errorCode = JsStringToPointer(value, &str, &strLength);
  3817. if (errorCode != JsNoError)
  3818. {
  3819. return errorCode;
  3820. }
  3821. if (start < 0 || (size_t)start > strLength)
  3822. {
  3823. return JsErrorInvalidArgument; // start out of range, no chars written
  3824. }
  3825. size_t count = min(static_cast<size_t>(length), strLength - start);
  3826. if (count == 0)
  3827. {
  3828. return JsNoError; // no chars written
  3829. }
  3830. errorCode = copyFunc(str + start, count, written);
  3831. if (errorCode != JsNoError)
  3832. {
  3833. return errorCode;
  3834. }
  3835. if (written)
  3836. {
  3837. *written = count;
  3838. }
  3839. return JsNoError;
  3840. }
  3841. CHAKRA_API JsCopyStringUtf16(
  3842. _In_ JsValueRef value,
  3843. _In_ int start,
  3844. _In_ int length,
  3845. _Out_opt_ uint16_t* buffer,
  3846. _Out_opt_ size_t* written)
  3847. {
  3848. PARAM_NOT_NULL(value);
  3849. VALIDATE_JSREF(value);
  3850. return WriteStringCopy(value, start, length, written,
  3851. [buffer](const char16* src, size_t count, size_t *needed)
  3852. {
  3853. if (buffer)
  3854. {
  3855. memmove(buffer, src, sizeof(char16) * count);
  3856. }
  3857. return JsNoError;
  3858. });
  3859. }
  3860. CHAKRA_API JsCopyString(
  3861. _In_ JsValueRef value,
  3862. _Out_opt_ char* buffer,
  3863. _In_ size_t bufferSize,
  3864. _Out_opt_ size_t* length)
  3865. {
  3866. PARAM_NOT_NULL(value);
  3867. VALIDATE_JSREF(value);
  3868. const char16* str = nullptr;
  3869. size_t strLength = 0;
  3870. JsErrorCode errorCode = JsStringToPointer(value, &str, &strLength);
  3871. if (errorCode != JsNoError)
  3872. {
  3873. return errorCode;
  3874. }
  3875. utf8::WideToNarrow utf8Str(str, strLength, buffer, bufferSize);
  3876. if (length)
  3877. {
  3878. *length = utf8Str.Length();
  3879. }
  3880. return JsNoError;
  3881. }
  3882. _ALWAYSINLINE JsErrorCode CompileRun(
  3883. JsValueRef scriptVal,
  3884. JsSourceContext sourceContext,
  3885. JsValueRef sourceUrl,
  3886. JsParseScriptAttributes parseAttributes,
  3887. _Out_ JsValueRef *result,
  3888. bool parseOnly)
  3889. {
  3890. PARAM_NOT_NULL(scriptVal);
  3891. VALIDATE_JSREF(scriptVal);
  3892. PARAM_NOT_NULL(sourceUrl);
  3893. bool isExternalArray = Js::ExternalArrayBuffer::Is(scriptVal),
  3894. isString = false;
  3895. bool isUtf8 = !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded);
  3896. LoadScriptFlag scriptFlag = LoadScriptFlag_None;
  3897. const byte* script;
  3898. size_t cb;
  3899. const WCHAR *url;
  3900. if (isExternalArray)
  3901. {
  3902. script = ((Js::ExternalArrayBuffer*)(scriptVal))->GetBuffer();
  3903. cb = ((Js::ExternalArrayBuffer*)(scriptVal))->GetByteLength();
  3904. scriptFlag = (LoadScriptFlag)(isUtf8 ?
  3905. LoadScriptFlag_ExternalArrayBuffer | LoadScriptFlag_Utf8Source :
  3906. LoadScriptFlag_ExternalArrayBuffer);
  3907. }
  3908. else
  3909. {
  3910. isString = Js::JavascriptString::Is(scriptVal);
  3911. if (!isString)
  3912. {
  3913. return JsErrorInvalidArgument;
  3914. }
  3915. }
  3916. JsErrorCode error = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  3917. if (isString)
  3918. {
  3919. Js::JavascriptString* jsString = Js::JavascriptString::FromVar(scriptVal);
  3920. script = (const byte*)jsString->GetSz();
  3921. // JavascriptString is 2 bytes (WCHAR/char16)
  3922. cb = jsString->GetLength() * sizeof(WCHAR);
  3923. }
  3924. if (!Js::JavascriptString::Is(sourceUrl))
  3925. {
  3926. return JsErrorInvalidArgument;
  3927. }
  3928. url = Js::JavascriptString::FromVar(sourceUrl)->GetSz();
  3929. return JsNoError;
  3930. });
  3931. if (error != JsNoError)
  3932. {
  3933. return error;
  3934. }
  3935. return RunScriptCore(scriptVal, script, cb, scriptFlag,
  3936. sourceContext, url, parseOnly, parseAttributes, false, result);
  3937. }
  3938. CHAKRA_API JsParse(
  3939. _In_ JsValueRef scriptVal,
  3940. _In_ JsSourceContext sourceContext,
  3941. _In_ JsValueRef sourceUrl,
  3942. _In_ JsParseScriptAttributes parseAttributes,
  3943. _Out_ JsValueRef *result)
  3944. {
  3945. return CompileRun(scriptVal, sourceContext, sourceUrl, parseAttributes,
  3946. result, true);
  3947. }
  3948. CHAKRA_API JsRun(
  3949. _In_ JsValueRef scriptVal,
  3950. _In_ JsSourceContext sourceContext,
  3951. _In_ JsValueRef sourceUrl,
  3952. _In_ JsParseScriptAttributes parseAttributes,
  3953. _Out_ JsValueRef *result)
  3954. {
  3955. return CompileRun(scriptVal, sourceContext, sourceUrl, parseAttributes,
  3956. result, false);
  3957. }
  3958. CHAKRA_API JsCreatePropertyId(
  3959. _In_z_ const char *name,
  3960. _In_ size_t length,
  3961. _Out_ JsPropertyIdRef *propertyId)
  3962. {
  3963. PARAM_NOT_NULL(name);
  3964. utf8::NarrowToWide wname(name, length);
  3965. if (!wname)
  3966. {
  3967. return JsErrorOutOfMemory;
  3968. }
  3969. return JsGetPropertyIdFromNameInternal(wname, wname.Length(), propertyId);
  3970. }
  3971. CHAKRA_API JsCopyPropertyId(
  3972. _In_ JsPropertyIdRef propertyId,
  3973. _Out_ char* buffer,
  3974. _In_ size_t bufferSize,
  3975. _Out_ size_t* length)
  3976. {
  3977. PARAM_NOT_NULL(propertyId);
  3978. const char16* str = nullptr;
  3979. JsErrorCode errorCode = JsGetPropertyNameFromId(propertyId, &str);
  3980. if (errorCode != JsNoError)
  3981. {
  3982. return errorCode;
  3983. }
  3984. utf8::WideToNarrow utf8Str(str);
  3985. if (!buffer)
  3986. {
  3987. if (length)
  3988. {
  3989. *length = utf8Str.Length();
  3990. }
  3991. }
  3992. else
  3993. {
  3994. size_t count = min(bufferSize, utf8Str.Length());
  3995. // Try to copy whole characters if buffer size insufficient
  3996. auto maxFitChars = utf8::ByteIndexIntoCharacterIndex(
  3997. (LPCUTF8)(const char*)utf8Str, count,
  3998. utf8::DecodeOptions::doChunkedEncoding);
  3999. count = utf8::CharacterIndexToByteIndex(
  4000. (LPCUTF8)(const char*)utf8Str, utf8Str.Length(), maxFitChars);
  4001. memmove(buffer, utf8Str, sizeof(char) * count);
  4002. if (length)
  4003. {
  4004. *length = count;
  4005. }
  4006. }
  4007. return JsNoError;
  4008. }
  4009. CHAKRA_API JsSerialize(
  4010. _In_ JsValueRef scriptVal,
  4011. _Out_ JsValueRef *bufferVal,
  4012. _In_ JsParseScriptAttributes parseAttributes)
  4013. {
  4014. PARAM_NOT_NULL(scriptVal);
  4015. PARAM_NOT_NULL(bufferVal);
  4016. VALIDATE_JSREF(scriptVal);
  4017. *bufferVal = nullptr;
  4018. bool isExternalArray = Js::ExternalArrayBuffer::Is(scriptVal),
  4019. isString = false;
  4020. bool isUtf8 = !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded);
  4021. if (!isExternalArray)
  4022. {
  4023. isString = Js::JavascriptString::Is(scriptVal);
  4024. if (!isString)
  4025. {
  4026. return JsErrorInvalidArgument;
  4027. }
  4028. }
  4029. LoadScriptFlag scriptFlag;
  4030. const byte* script = isExternalArray ?
  4031. ((Js::ExternalArrayBuffer*)(scriptVal))->GetBuffer() :
  4032. (const byte*)((Js::JavascriptString*)(scriptVal))->GetSz();
  4033. const size_t cb = isExternalArray ?
  4034. ((Js::ExternalArrayBuffer*)(scriptVal))->GetByteLength() :
  4035. ((Js::JavascriptString*)(scriptVal))->GetLength();
  4036. if (isExternalArray && isUtf8)
  4037. {
  4038. scriptFlag = (LoadScriptFlag) (LoadScriptFlag_ExternalArrayBuffer | LoadScriptFlag_Utf8Source);
  4039. }
  4040. else if (isUtf8)
  4041. {
  4042. scriptFlag = (LoadScriptFlag) (LoadScriptFlag_Utf8Source);
  4043. }
  4044. else
  4045. {
  4046. scriptFlag = LoadScriptFlag_None;
  4047. }
  4048. unsigned int bufferSize = 0;
  4049. JsErrorCode errorCode = JsSerializeScriptCore(script, cb, scriptFlag, nullptr,
  4050. 0, nullptr, &bufferSize, scriptVal);
  4051. if (errorCode != JsNoError)
  4052. {
  4053. return errorCode;
  4054. }
  4055. if (bufferSize == 0)
  4056. {
  4057. return JsErrorScriptCompile;
  4058. }
  4059. if ((errorCode = JsCreateArrayBuffer(bufferSize, bufferVal)) == JsNoError)
  4060. {
  4061. byte* buffer = ((Js::ArrayBuffer*)(*bufferVal))->GetBuffer();
  4062. errorCode = JsSerializeScriptCore(script, cb, scriptFlag, nullptr,
  4063. 0, buffer, &bufferSize, scriptVal);
  4064. }
  4065. return errorCode;
  4066. }
  4067. CHAKRA_API JsParseSerialized(
  4068. _In_ JsValueRef bufferVal,
  4069. _In_ JsSerializedLoadScriptCallback scriptLoadCallback,
  4070. _In_ JsSourceContext sourceContext,
  4071. _In_ JsValueRef sourceUrl,
  4072. _Out_ JsValueRef *result)
  4073. {
  4074. PARAM_NOT_NULL(bufferVal);
  4075. PARAM_NOT_NULL(sourceUrl);
  4076. const WCHAR *url;
  4077. if (Js::JavascriptString::Is(sourceUrl))
  4078. {
  4079. url = ((Js::JavascriptString*)(sourceUrl))->GetSz();
  4080. }
  4081. else
  4082. {
  4083. return JsErrorInvalidArgument;
  4084. }
  4085. // JsParseSerialized only accepts ArrayBuffer (incl. ExternalArrayBuffer)
  4086. if (!Js::ExternalArrayBuffer::Is(bufferVal))
  4087. {
  4088. return JsErrorInvalidArgument;
  4089. }
  4090. Js::ArrayBuffer* arrayBuffer = Js::ArrayBuffer::FromVar(bufferVal);
  4091. byte* buffer = arrayBuffer->GetBuffer();
  4092. return RunSerializedScriptCore(
  4093. scriptLoadCallback, DummyScriptUnloadCallback,
  4094. sourceContext,// use the same user provided sourceContext as scriptLoadSourceContext
  4095. buffer, arrayBuffer, sourceContext, url, true, result);
  4096. }
  4097. CHAKRA_API JsRunSerialized(
  4098. _In_ JsValueRef bufferVal,
  4099. _In_ JsSerializedLoadScriptCallback scriptLoadCallback,
  4100. _In_ JsSourceContext sourceContext,
  4101. _In_ JsValueRef sourceUrl,
  4102. _Out_ JsValueRef *result)
  4103. {
  4104. PARAM_NOT_NULL(bufferVal);
  4105. const WCHAR *url;
  4106. if (sourceUrl && Js::JavascriptString::Is(sourceUrl))
  4107. {
  4108. url = ((Js::JavascriptString*)(sourceUrl))->GetSz();
  4109. }
  4110. else
  4111. {
  4112. return JsErrorInvalidArgument;
  4113. }
  4114. // JsParseSerialized only accepts ArrayBuffer (incl. ExternalArrayBuffer)
  4115. if (!Js::ExternalArrayBuffer::Is(bufferVal))
  4116. {
  4117. return JsErrorInvalidArgument;
  4118. }
  4119. Js::ArrayBuffer* arrayBuffer = Js::ArrayBuffer::FromVar(bufferVal);
  4120. byte* buffer = arrayBuffer->GetBuffer();
  4121. return RunSerializedScriptCore(
  4122. scriptLoadCallback, DummyScriptUnloadCallback,
  4123. sourceContext, // use the same user provided sourceContext as scriptLoadSourceContext
  4124. buffer, arrayBuffer, sourceContext, url, false, result);
  4125. }
  4126. CHAKRA_API JsCreatePromise(_Out_ JsValueRef *promise, _Out_ JsValueRef *resolve, _Out_ JsValueRef *reject)
  4127. {
  4128. return ContextAPIWrapper<JSRT_MAYBE_TRUE>([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  4129. PERFORM_JSRT_TTD_RECORD_ACTION_NOT_IMPLEMENTED(scriptContext);
  4130. PARAM_NOT_NULL(promise);
  4131. PARAM_NOT_NULL(resolve);
  4132. PARAM_NOT_NULL(reject);
  4133. *promise = nullptr;
  4134. *resolve = nullptr;
  4135. *reject = nullptr;
  4136. Js::JavascriptPromiseResolveOrRejectFunction *jsResolve = nullptr;
  4137. Js::JavascriptPromiseResolveOrRejectFunction *jsReject = nullptr;
  4138. Js::JavascriptPromise *jsPromise = scriptContext->GetLibrary()->CreatePromise();
  4139. Js::JavascriptPromise::InitializePromise(jsPromise, &jsResolve, &jsReject, scriptContext);
  4140. *promise = (JsValueRef)jsPromise;
  4141. *resolve = (JsValueRef)jsResolve;
  4142. *reject = (JsValueRef)jsReject;
  4143. return JsNoError;
  4144. });
  4145. }
  4146. CHAKRA_API JsCreateWeakReference(
  4147. _In_ JsValueRef value,
  4148. _Out_ JsWeakRef* weakRef)
  4149. {
  4150. VALIDATE_JSREF(value);
  4151. PARAM_NOT_NULL(weakRef);
  4152. *weakRef = nullptr;
  4153. if (Js::TaggedNumber::Is(value))
  4154. {
  4155. return JsNoWeakRefRequired;
  4156. }
  4157. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  4158. ThreadContext* threadContext = ThreadContext::GetContextForCurrentThread();
  4159. if (threadContext == nullptr)
  4160. {
  4161. return JsErrorNoCurrentContext;
  4162. }
  4163. Recycler* recycler = threadContext->GetRecycler();
  4164. if (recycler->IsInObjectBeforeCollectCallback())
  4165. {
  4166. return JsErrorInObjectBeforeCollectCallback;
  4167. }
  4168. RecyclerHeapObjectInfo dummyObjectInfo;
  4169. if (!recycler->FindHeapObject(value, Memory::FindHeapObjectFlags::FindHeapObjectFlags_NoFlags, dummyObjectInfo))
  4170. {
  4171. // value is not recyler-allocated
  4172. return JsErrorInvalidArgument;
  4173. }
  4174. recycler->FindOrCreateWeakReferenceHandle<char>(
  4175. reinterpret_cast<char*>(value),
  4176. reinterpret_cast<Memory::RecyclerWeakReference<char>**>(weakRef));
  4177. return JsNoError;
  4178. });
  4179. }
  4180. CHAKRA_API JsGetWeakReferenceValue(
  4181. _In_ JsWeakRef weakRef,
  4182. _Out_ JsValueRef* value)
  4183. {
  4184. VALIDATE_JSREF(weakRef);
  4185. PARAM_NOT_NULL(value);
  4186. *value = JS_INVALID_REFERENCE;
  4187. return GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
  4188. Memory::RecyclerWeakReference<char>* recyclerWeakReference =
  4189. reinterpret_cast<Memory::RecyclerWeakReference<char>*>(weakRef);
  4190. *value = reinterpret_cast<JsValueRef>(recyclerWeakReference->Get());
  4191. return JsNoError;
  4192. });
  4193. }
  4194. CHAKRA_API JsGetAndClearExceptionWithMetadata(_Out_ JsValueRef *metadata)
  4195. {
  4196. PARAM_NOT_NULL(metadata);
  4197. *metadata = nullptr;
  4198. JsrtContext *currentContext = JsrtContext::GetCurrent();
  4199. if (currentContext == nullptr)
  4200. {
  4201. return JsErrorNoCurrentContext;
  4202. }
  4203. Js::ScriptContext *scriptContext = currentContext->GetScriptContext();
  4204. Assert(scriptContext != nullptr);
  4205. if (scriptContext->GetRecycler() && scriptContext->GetRecycler()->IsHeapEnumInProgress())
  4206. {
  4207. return JsErrorHeapEnumInProgress;
  4208. }
  4209. else if (scriptContext->GetThreadContext()->IsInThreadServiceCallback())
  4210. {
  4211. return JsErrorInThreadServiceCallback;
  4212. }
  4213. if (scriptContext->GetThreadContext()->IsExecutionDisabled())
  4214. {
  4215. return JsErrorInDisabledState;
  4216. }
  4217. HRESULT hr = S_OK;
  4218. Js::JavascriptExceptionObject *recordedException = nullptr;
  4219. BEGIN_TRANSLATE_OOM_TO_HRESULT
  4220. if (scriptContext->HasRecordedException())
  4221. {
  4222. recordedException = scriptContext->GetAndClearRecordedException();
  4223. }
  4224. END_TRANSLATE_OOM_TO_HRESULT(hr)
  4225. if (hr == E_OUTOFMEMORY)
  4226. {
  4227. recordedException = scriptContext->GetThreadContext()->GetRecordedException();
  4228. }
  4229. if (recordedException == nullptr)
  4230. {
  4231. return JsErrorInvalidArgument;
  4232. }
  4233. Js::Var exception = recordedException->GetThrownObject(nullptr);
  4234. if (exception == nullptr)
  4235. {
  4236. // TODO: How does this early bailout impact TTD?
  4237. return JsErrorInvalidArgument;
  4238. }
  4239. return ContextAPIWrapper<false>([&](Js::ScriptContext* scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {
  4240. Js::Var exceptionMetadata = Js::JavascriptExceptionMetadata::CreateMetadataVar(scriptContext);
  4241. Js::JavascriptOperators::OP_SetProperty(exceptionMetadata, Js::PropertyIds::exception, exception, scriptContext);
  4242. Js::FunctionBody *functionBody = recordedException->GetFunctionBody();
  4243. if (functionBody == nullptr)
  4244. {
  4245. // This is probably a parse error. We can get the error location metadata from the thrown object.
  4246. Js::JavascriptExceptionMetadata::PopulateMetadataFromCompileException(exceptionMetadata, exception, scriptContext);
  4247. }
  4248. else
  4249. {
  4250. if (!Js::JavascriptExceptionMetadata::PopulateMetadataFromException(exceptionMetadata, recordedException, scriptContext))
  4251. {
  4252. return JsErrorInvalidArgument;
  4253. }
  4254. }
  4255. *metadata = exceptionMetadata;
  4256. #if ENABLE_TTD
  4257. if (hr != E_OUTOFMEMORY)
  4258. {
  4259. PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTGetAndClearExceptionWithMetadata);
  4260. PERFORM_JSRT_TTD_RECORD_ACTION_RESULT(scriptContext, metadata);
  4261. }
  4262. #endif
  4263. return JsNoError;
  4264. });
  4265. }
  4266. CHAKRA_API JsCopyStringOneByte(
  4267. _In_ JsValueRef value,
  4268. _In_ int start,
  4269. _In_ int length,
  4270. _Out_opt_ char* buffer,
  4271. _Out_opt_ size_t* written)
  4272. {
  4273. PARAM_NOT_NULL(value);
  4274. VALIDATE_JSREF(value);
  4275. return WriteStringCopy(value, start, length, written,
  4276. [buffer](const char16* src, size_t count, size_t *needed)
  4277. {
  4278. if (buffer)
  4279. {
  4280. for (size_t i = 0; i < count; i++)
  4281. {
  4282. buffer[i] = (char)src[i];
  4283. }
  4284. }
  4285. return JsNoError;
  4286. });
  4287. }
  4288. CHAKRA_API JsGetDataViewInfo(
  4289. _In_ JsValueRef dataView,
  4290. _Out_opt_ JsValueRef *arrayBuffer,
  4291. _Out_opt_ unsigned int *byteOffset,
  4292. _Out_opt_ unsigned int *byteLength)
  4293. {
  4294. VALIDATE_JSREF(dataView);
  4295. BEGIN_JSRT_NO_EXCEPTION
  4296. {
  4297. if (!Js::DataView::Is(dataView))
  4298. {
  4299. RETURN_NO_EXCEPTION(JsErrorInvalidArgument);
  4300. }
  4301. Js::DataView* dv = Js::DataView::FromVar(dataView);
  4302. if (arrayBuffer != nullptr) {
  4303. *arrayBuffer = dv->GetArrayBuffer();
  4304. }
  4305. if (byteOffset != nullptr) {
  4306. *byteOffset = dv->GetByteOffset();
  4307. }
  4308. if (byteLength != nullptr) {
  4309. *byteLength = dv->GetLength();
  4310. }
  4311. }
  4312. #if ENABLE_TTD
  4313. Js::ScriptContext* scriptContext = Js::RecyclableObject::FromVar(dataView)->GetScriptContext();
  4314. if(PERFORM_JSRT_TTD_RECORD_ACTION_CHECK(scriptContext) && arrayBuffer != nullptr)
  4315. {
  4316. scriptContext->GetThreadContext()->TTDLog->RecordJsRTGetDataViewInfo(dataView, *arrayBuffer);
  4317. }
  4318. #endif
  4319. END_JSRT_NO_EXCEPTION
  4320. }
  4321. #endif // _CHAKRACOREBUILD