1 Star 0 Fork 1

王布衣 / pkg

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
vm.go 108.26 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605
package goja
import (
"fmt"
"math"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"gitee.com/quant1x/pkg/goja/unistring"
)
const (
maxInt = 1 << 53
tryPanicMarker = -2
)
type valueStack []Value
type stash struct {
values []Value
extraArgs []Value
names map[unistring.String]uint32
obj *Object
outer *stash
// If this is a top-level function stash, sets the type of the function. If set, dynamic var declarations
// created by direct eval go here.
funcType funcType
}
type context struct {
prg *Program
stash *stash
privEnv *privateEnv
newTarget Value
result Value
pc, sb int
args int
}
type tryFrame struct {
// holds an uncaught exception for the 'finally' block
exception *Exception
callStackLen, iterLen, refLen uint32
sp int32
stash *stash
privEnv *privateEnv
catchPos, finallyPos, finallyRet int32
}
type execCtx struct {
context
stack []Value
tryStack []tryFrame
iterStack []iterStackItem
refStack []ref
}
func (vm *vm) suspend(ectx *execCtx, tryStackLen, iterStackLen, refStackLen uint32) {
vm.saveCtx(&ectx.context)
ectx.stack = append(ectx.stack[:0], vm.stack[vm.sb-1:vm.sp]...)
if len(vm.tryStack) > int(tryStackLen) {
ectx.tryStack = append(ectx.tryStack[:0], vm.tryStack[tryStackLen:]...)
vm.tryStack = vm.tryStack[:tryStackLen]
sp := int32(vm.sb - 1)
for i := range ectx.tryStack {
tf := &ectx.tryStack[i]
tf.iterLen -= iterStackLen
tf.refLen -= refStackLen
tf.sp -= sp
}
}
if len(vm.iterStack) > int(iterStackLen) {
ectx.iterStack = append(ectx.iterStack[:0], vm.iterStack[iterStackLen:]...)
vm.iterStack = vm.iterStack[:iterStackLen]
}
if len(vm.refStack) > int(refStackLen) {
ectx.refStack = append(ectx.refStack[:0], vm.refStack[refStackLen:]...)
vm.refStack = vm.refStack[:refStackLen]
}
}
func (vm *vm) resume(ctx *execCtx) {
vm.restoreCtx(&ctx.context)
sp := vm.sp
vm.sb = sp + 1
vm.stack.expand(sp + len(ctx.stack))
copy(vm.stack[sp:], ctx.stack)
vm.sp += len(ctx.stack)
for i := range ctx.tryStack {
tf := &ctx.tryStack[i]
tf.callStackLen = uint32(len(vm.callStack))
tf.iterLen += uint32(len(vm.iterStack))
tf.refLen += uint32(len(vm.refStack))
tf.sp += int32(sp)
}
vm.tryStack = append(vm.tryStack, ctx.tryStack...)
vm.iterStack = append(vm.iterStack, ctx.iterStack...)
vm.refStack = append(vm.refStack, ctx.refStack...)
}
type iterStackItem struct {
val Value
f iterNextFunc
iter *iteratorRecord
}
type ref interface {
get() Value
set(Value)
init(Value)
refname() unistring.String
}
type stashRef struct {
n unistring.String
v *[]Value
idx int
}
func (r *stashRef) get() Value {
return nilSafe((*r.v)[r.idx])
}
func (r *stashRef) set(v Value) {
(*r.v)[r.idx] = v
}
func (r *stashRef) init(v Value) {
r.set(v)
}
func (r *stashRef) refname() unistring.String {
return r.n
}
type thisRef struct {
v *[]Value
idx int
}
func (r *thisRef) get() Value {
v := (*r.v)[r.idx]
if v == nil {
panic(referenceError("Must call super constructor in derived class before accessing 'this'"))
}
return v
}
func (r *thisRef) set(v Value) {
ptr := &(*r.v)[r.idx]
if *ptr != nil {
panic(referenceError("Super constructor may only be called once"))
}
*ptr = v
}
func (r *thisRef) init(v Value) {
r.set(v)
}
func (r *thisRef) refname() unistring.String {
return thisBindingName
}
type stashRefLex struct {
stashRef
}
func (r *stashRefLex) get() Value {
v := (*r.v)[r.idx]
if v == nil {
panic(errAccessBeforeInit)
}
return v
}
func (r *stashRefLex) set(v Value) {
p := &(*r.v)[r.idx]
if *p == nil {
panic(errAccessBeforeInit)
}
*p = v
}
func (r *stashRefLex) init(v Value) {
(*r.v)[r.idx] = v
}
type stashRefConst struct {
stashRefLex
strictConst bool
}
func (r *stashRefConst) set(v Value) {
if r.strictConst {
panic(errAssignToConst)
}
}
type objRef struct {
base *Object
name unistring.String
this Value
strict bool
binding bool
}
func (r *objRef) get() Value {
return r.base.self.getStr(r.name, r.this)
}
func (r *objRef) set(v Value) {
if r.strict && r.binding && !r.base.self.hasOwnPropertyStr(r.name) {
panic(referenceError(fmt.Sprintf("%s is not defined", r.name)))
}
if r.this != nil {
r.base.setStr(r.name, v, r.this, r.strict)
} else {
r.base.self.setOwnStr(r.name, v, r.strict)
}
}
func (r *objRef) init(v Value) {
if r.this != nil {
r.base.setStr(r.name, v, r.this, r.strict)
} else {
r.base.self.setOwnStr(r.name, v, r.strict)
}
}
func (r *objRef) refname() unistring.String {
return r.name
}
type privateRefRes struct {
base *Object
name *resolvedPrivateName
}
func (p *privateRefRes) get() Value {
return (*getPrivatePropRes)(p.name)._get(p.base, p.base.runtime.vm)
}
func (p *privateRefRes) set(value Value) {
(*setPrivatePropRes)(p.name)._set(p.base, value, p.base.runtime.vm)
}
func (p *privateRefRes) init(value Value) {
panic("not supported")
}
func (p *privateRefRes) refname() unistring.String {
return p.name.string()
}
type privateRefId struct {
base *Object
id *privateId
}
func (p *privateRefId) get() Value {
return p.base.runtime.vm.getPrivateProp(p.base, p.id.name, p.id.typ, p.id.idx, p.id.isMethod)
}
func (p *privateRefId) set(value Value) {
p.base.runtime.vm.setPrivateProp(p.base, p.id.name, p.id.typ, p.id.idx, p.id.isMethod, value)
}
func (p *privateRefId) init(value Value) {
panic("not supported")
}
func (p *privateRefId) refname() unistring.String {
return p.id.string()
}
type unresolvedRef struct {
runtime *Runtime
name unistring.String
}
func (r *unresolvedRef) get() Value {
r.runtime.throwReferenceError(r.name)
panic("Unreachable")
}
func (r *unresolvedRef) set(Value) {
r.get()
}
func (r *unresolvedRef) init(Value) {
r.get()
}
func (r *unresolvedRef) refname() unistring.String {
return r.name
}
type vm struct {
r *Runtime
prg *Program
pc int
stack valueStack
sp, sb, args int
stash *stash
privEnv *privateEnv
callStack []context
iterStack []iterStackItem
refStack []ref
tryStack []tryFrame
newTarget Value
result Value
maxCallStackSize int
stashAllocs int
interrupted uint32
interruptVal interface{}
interruptLock sync.Mutex
curAsyncRunner *asyncRunner
profTracker *profTracker
}
type instruction interface {
exec(*vm)
}
func intToValue(i int64) Value {
if idx := 256 + i; idx >= 0 && idx < 256 {
return intCache[idx]
}
if i >= -maxInt && i <= maxInt {
return valueInt(i)
}
return valueFloat(i)
}
func floatToInt(f float64) (result int64, ok bool) {
if (f != 0 || !math.Signbit(f)) && !math.IsInf(f, 0) && f == math.Trunc(f) && f >= -maxInt && f <= maxInt {
return int64(f), true
}
return 0, false
}
func floatToValue(f float64) (result Value) {
if i, ok := floatToInt(f); ok {
return intToValue(i)
}
switch {
case f == 0:
return _negativeZero
case math.IsNaN(f):
return _NaN
case math.IsInf(f, 1):
return _positiveInf
case math.IsInf(f, -1):
return _negativeInf
}
return valueFloat(f)
}
func assertInt64(v Value) (int64, bool) {
num := v.ToNumber()
if i, ok := num.(valueInt); ok {
return int64(i), true
}
if f, ok := num.(valueFloat); ok {
if i, ok := floatToInt(float64(f)); ok {
return i, true
}
}
return 0, false
}
func (s *valueStack) expand(idx int) {
if idx < len(*s) {
return
}
idx++
if idx < cap(*s) {
*s = (*s)[:idx]
} else {
var newCap int
if idx < 1024 {
newCap = idx * 2
} else {
newCap = (idx + 1025) &^ 1023
}
n := make([]Value, idx, newCap)
copy(n, *s)
*s = n
}
}
func stashObjHas(obj *Object, name unistring.String) bool {
if obj.self.hasPropertyStr(name) {
if unscopables, ok := obj.self.getSym(SymUnscopables, nil).(*Object); ok {
if b := unscopables.self.getStr(name, nil); b != nil {
return !b.ToBoolean()
}
}
return true
}
return false
}
func (s *stash) isVariable() bool {
return s.funcType != funcNone
}
func (s *stash) initByIdx(idx uint32, v Value) {
if s.obj != nil {
panic("Attempt to init by idx into an object scope")
}
s.values[idx] = v
}
func (s *stash) initByName(name unistring.String, v Value) {
if idx, exists := s.names[name]; exists {
s.values[idx&^maskTyp] = v
} else {
panic(referenceError(fmt.Sprintf("%s is not defined", name)))
}
}
func (s *stash) getByIdx(idx uint32) Value {
return s.values[idx]
}
func (s *stash) getByName(name unistring.String) (v Value, exists bool) {
if s.obj != nil {
if stashObjHas(s.obj, name) {
return nilSafe(s.obj.self.getStr(name, nil)), true
}
return nil, false
}
if idx, exists := s.names[name]; exists {
v := s.values[idx&^maskTyp]
if v == nil {
if idx&maskVar == 0 {
panic(errAccessBeforeInit)
} else {
v = _undefined
}
}
return v, true
}
return nil, false
}
func (s *stash) getRefByName(name unistring.String, strict bool) ref {
if obj := s.obj; obj != nil {
if stashObjHas(obj, name) {
return &objRef{
base: obj,
name: name,
strict: strict,
binding: true,
}
}
} else {
if idx, exists := s.names[name]; exists {
if idx&maskVar == 0 {
if idx&maskConst == 0 {
return &stashRefLex{
stashRef: stashRef{
n: name,
v: &s.values,
idx: int(idx &^ maskTyp),
},
}
} else {
return &stashRefConst{
stashRefLex: stashRefLex{
stashRef: stashRef{
n: name,
v: &s.values,
idx: int(idx &^ maskTyp),
},
},
strictConst: strict || (idx&maskStrict != 0),
}
}
} else {
return &stashRef{
n: name,
v: &s.values,
idx: int(idx &^ maskTyp),
}
}
}
}
return nil
}
func (s *stash) createBinding(name unistring.String, deletable bool) {
if s.names == nil {
s.names = make(map[unistring.String]uint32)
}
if _, exists := s.names[name]; !exists {
idx := uint32(len(s.names)) | maskVar
if deletable {
idx |= maskDeletable
}
s.names[name] = idx
s.values = append(s.values, _undefined)
}
}
func (s *stash) createLexBinding(name unistring.String, isConst bool) {
if s.names == nil {
s.names = make(map[unistring.String]uint32)
}
if _, exists := s.names[name]; !exists {
idx := uint32(len(s.names))
if isConst {
idx |= maskConst | maskStrict
}
s.names[name] = idx
s.values = append(s.values, nil)
}
}
func (s *stash) deleteBinding(name unistring.String) {
delete(s.names, name)
}
func (vm *vm) newStash() {
vm.stash = &stash{
outer: vm.stash,
}
vm.stashAllocs++
}
func (vm *vm) init() {
vm.sb = -1
vm.stash = &vm.r.global.stash
vm.maxCallStackSize = math.MaxInt32
}
func (vm *vm) halted() bool {
pc := vm.pc
return pc < 0 || pc >= len(vm.prg.code)
}
func (vm *vm) run() {
if vm.profTracker != nil && !vm.runWithProfiler() {
return
}
count := 0
interrupted := false
for {
if count == 0 {
if atomic.LoadInt32(&globalProfiler.enabled) == 1 && !vm.runWithProfiler() {
return
}
count = 100
} else {
count--
}
if interrupted = atomic.LoadUint32(&vm.interrupted) != 0; interrupted {
break
}
pc := vm.pc
if pc < 0 || pc >= len(vm.prg.code) {
break
}
vm.prg.code[pc].exec(vm)
}
if interrupted {
vm.interruptLock.Lock()
v := &InterruptedError{
iface: vm.interruptVal,
}
v.stack = vm.captureStack(nil, 0)
vm.interruptLock.Unlock()
panic(v)
}
}
func (vm *vm) runWithProfiler() bool {
pt := vm.profTracker
if pt == nil {
pt = globalProfiler.p.registerVm()
vm.profTracker = pt
defer func() {
atomic.StoreInt32(&vm.profTracker.finished, 1)
vm.profTracker = nil
}()
}
interrupted := false
for {
if interrupted = atomic.LoadUint32(&vm.interrupted) != 0; interrupted {
return true
}
pc := vm.pc
if pc < 0 || pc >= len(vm.prg.code) {
break
}
vm.prg.code[pc].exec(vm)
req := atomic.LoadInt32(&pt.req)
if req == profReqStop {
return true
}
if req == profReqDoSample {
pt.stop = time.Now()
pt.numFrames = len(vm.r.CaptureCallStack(len(pt.frames), pt.frames[:0]))
pt.frames[0].pc = pc
atomic.StoreInt32(&pt.req, profReqSampleReady)
}
}
return false
}
func (vm *vm) Interrupt(v interface{}) {
vm.interruptLock.Lock()
vm.interruptVal = v
atomic.StoreUint32(&vm.interrupted, 1)
vm.interruptLock.Unlock()
}
func (vm *vm) ClearInterrupt() {
atomic.StoreUint32(&vm.interrupted, 0)
}
func getFuncName(stack []Value, sb int) unistring.String {
if sb > 0 {
if f, ok := stack[sb-1].(*Object); ok {
if _, isProxy := f.self.(*proxyObject); isProxy {
return "proxy"
}
return nilSafe(f.self.getStr("name", nil)).string()
}
}
return ""
}
func (vm *vm) captureStack(stack []StackFrame, ctxOffset int) []StackFrame {
// Unroll the context stack
if vm.prg != nil || vm.sb > 0 {
var funcName unistring.String
if vm.prg != nil {
funcName = vm.prg.funcName
} else {
funcName = getFuncName(vm.stack, vm.sb)
}
stack = append(stack, StackFrame{prg: vm.prg, pc: vm.pc, funcName: funcName})
}
for i := len(vm.callStack) - 1; i > ctxOffset-1; i-- {
frame := &vm.callStack[i]
if frame.prg != nil || frame.sb > 0 {
var funcName unistring.String
if prg := frame.prg; prg != nil {
funcName = prg.funcName
} else {
funcName = getFuncName(vm.stack, frame.sb)
}
stack = append(stack, StackFrame{prg: vm.callStack[i].prg, pc: frame.pc, funcName: funcName})
}
}
if ctxOffset == 0 && vm.curAsyncRunner != nil {
stack = vm.captureAsyncStack(stack, vm.curAsyncRunner)
}
return stack
}
func (vm *vm) captureAsyncStack(stack []StackFrame, runner *asyncRunner) []StackFrame {
if promise, _ := runner.promiseCap.promise.self.(*Promise); promise != nil {
if len(promise.fulfillReactions) == 1 {
if r := promise.fulfillReactions[0].asyncRunner; r != nil {
ctx := &r.gen.ctx
if ctx.prg != nil || ctx.sb > 0 {
var funcName unistring.String
if prg := ctx.prg; prg != nil {
funcName = prg.funcName
} else {
funcName = getFuncName(ctx.stack, 1)
}
stack = append(stack, StackFrame{prg: ctx.prg, pc: ctx.pc, funcName: funcName})
}
stack = vm.captureAsyncStack(stack, r)
}
}
}
return stack
}
func (vm *vm) pushTryFrame(catchPos, finallyPos int32) {
vm.tryStack = append(vm.tryStack, tryFrame{
callStackLen: uint32(len(vm.callStack)),
iterLen: uint32(len(vm.iterStack)),
refLen: uint32(len(vm.refStack)),
sp: int32(vm.sp),
stash: vm.stash,
privEnv: vm.privEnv,
catchPos: catchPos,
finallyPos: finallyPos,
finallyRet: -1,
})
}
func (vm *vm) popTryFrame() {
vm.tryStack = vm.tryStack[:len(vm.tryStack)-1]
}
func (vm *vm) restoreStacks(iterLen, refLen uint32) (ex *Exception) {
// Restore other stacks
iterTail := vm.iterStack[iterLen:]
for i := len(iterTail) - 1; i >= 0; i-- {
if iter := iterTail[i].iter; iter != nil {
ex1 := vm.try(func() {
iter.returnIter()
})
if ex1 != nil && ex == nil {
ex = ex1
}
}
iterTail[i] = iterStackItem{}
}
vm.iterStack = vm.iterStack[:iterLen]
refTail := vm.refStack[refLen:]
for i := range refTail {
refTail[i] = nil
}
vm.refStack = vm.refStack[:refLen]
return
}
func (vm *vm) handleThrow(arg interface{}) *Exception {
ex := vm.exceptionFromValue(arg)
for len(vm.tryStack) > 0 {
tf := &vm.tryStack[len(vm.tryStack)-1]
if tf.catchPos == -1 && tf.finallyPos == -1 || ex == nil && tf.catchPos != tryPanicMarker {
tf.exception = nil
vm.popTryFrame()
continue
}
if int(tf.callStackLen) < len(vm.callStack) {
ctx := &vm.callStack[tf.callStackLen]
vm.prg, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args =
ctx.prg, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args
vm.callStack = vm.callStack[:tf.callStackLen]
}
vm.sp = int(tf.sp)
vm.stash = tf.stash
vm.privEnv = tf.privEnv
_ = vm.restoreStacks(tf.iterLen, tf.refLen)
if tf.catchPos == tryPanicMarker {
break
}
if tf.catchPos >= 0 {
// exception is caught
vm.push(ex.val)
vm.pc = int(tf.catchPos)
tf.catchPos = -1
return nil
}
if tf.finallyPos >= 0 {
// no 'catch' block, but there is a 'finally' block
tf.exception = ex
vm.pc = int(tf.finallyPos)
tf.finallyPos = -1
tf.finallyRet = -1
return nil
}
}
if ex == nil {
panic(arg)
}
return ex
}
// Calls to this method must be made from the run() loop and must be the last statement before 'return'.
// In all other cases exceptions must be thrown using panic().
func (vm *vm) throw(v interface{}) {
if ex := vm.handleThrow(v); ex != nil {
panic(ex)
}
}
func (vm *vm) try(f func()) (ex *Exception) {
vm.pushTryFrame(tryPanicMarker, -1)
defer vm.popTryFrame()
defer func() {
if x := recover(); x != nil {
ex = vm.handleThrow(x)
}
}()
f()
return
}
func (vm *vm) runTry() (ex *Exception) {
vm.pushTryFrame(tryPanicMarker, -1)
defer vm.popTryFrame()
for {
ex = vm.runTryInner()
if ex != nil || vm.halted() {
return
}
}
}
func (vm *vm) runTryInner() (ex *Exception) {
defer func() {
if x := recover(); x != nil {
ex = vm.handleThrow(x)
}
}()
vm.run()
return
}
func (vm *vm) push(v Value) {
vm.stack.expand(vm.sp)
vm.stack[vm.sp] = v
vm.sp++
}
func (vm *vm) pop() Value {
vm.sp--
return vm.stack[vm.sp]
}
func (vm *vm) peek() Value {
return vm.stack[vm.sp-1]
}
func (vm *vm) saveCtx(ctx *context) {
ctx.prg, ctx.stash, ctx.privEnv, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args =
vm.prg, vm.stash, vm.privEnv, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args
}
func (vm *vm) pushCtx() {
if len(vm.callStack) > vm.maxCallStackSize {
ex := &StackOverflowError{}
ex.stack = vm.captureStack(nil, 0)
panic(ex)
}
vm.callStack = append(vm.callStack, context{})
ctx := &vm.callStack[len(vm.callStack)-1]
vm.saveCtx(ctx)
}
func (vm *vm) restoreCtx(ctx *context) {
vm.prg, vm.stash, vm.privEnv, vm.newTarget, vm.result, vm.pc, vm.sb, vm.args =
ctx.prg, ctx.stash, ctx.privEnv, ctx.newTarget, ctx.result, ctx.pc, ctx.sb, ctx.args
}
func (vm *vm) popCtx() {
l := len(vm.callStack) - 1
ctx := &vm.callStack[l]
vm.restoreCtx(ctx)
if ctx.prg != nil {
*ctx = context{}
}
vm.callStack = vm.callStack[:l]
}
func (vm *vm) toCallee(v Value) *Object {
if obj, ok := v.(*Object); ok {
return obj
}
switch unresolved := v.(type) {
case valueUnresolved:
unresolved.throw()
panic("Unreachable")
case memberUnresolved:
panic(vm.r.NewTypeError("Object has no member '%s'", unresolved.ref))
}
panic(vm.r.NewTypeError("Value is not an object: %s", v.toString()))
}
type loadVal uint32
func (l loadVal) exec(vm *vm) {
vm.push(vm.prg.values[l])
vm.pc++
}
type _loadUndef struct{}
var loadUndef _loadUndef
func (_loadUndef) exec(vm *vm) {
vm.push(_undefined)
vm.pc++
}
type _loadNil struct{}
var loadNil _loadNil
func (_loadNil) exec(vm *vm) {
vm.push(nil)
vm.pc++
}
type _saveResult struct{}
var saveResult _saveResult
func (_saveResult) exec(vm *vm) {
vm.sp--
vm.result = vm.stack[vm.sp]
vm.pc++
}
type _clearResult struct{}
var clearResult _clearResult
func (_clearResult) exec(vm *vm) {
vm.result = _undefined
vm.pc++
}
type _loadGlobalObject struct{}
var loadGlobalObject _loadGlobalObject
func (_loadGlobalObject) exec(vm *vm) {
vm.push(vm.r.globalObject)
vm.pc++
}
type loadStack int
func (l loadStack) exec(vm *vm) {
// l > 0 -- var<l-1>
// l == 0 -- this
if l > 0 {
vm.push(nilSafe(vm.stack[vm.sb+vm.args+int(l)]))
} else {
vm.push(vm.stack[vm.sb])
}
vm.pc++
}
type loadStack1 int
func (l loadStack1) exec(vm *vm) {
// args are in stash
// l > 0 -- var<l-1>
// l == 0 -- this
if l > 0 {
vm.push(nilSafe(vm.stack[vm.sb+int(l)]))
} else {
vm.push(vm.stack[vm.sb])
}
vm.pc++
}
type loadStackLex int
func (l loadStackLex) exec(vm *vm) {
// l < 0 -- arg<-l-1>
// l > 0 -- var<l-1>
// l == 0 -- this
var p *Value
if l <= 0 {
arg := int(-l)
if arg > vm.args {
vm.push(_undefined)
vm.pc++
return
} else {
p = &vm.stack[vm.sb+arg]
}
} else {
p = &vm.stack[vm.sb+vm.args+int(l)]
}
if *p == nil {
vm.throw(errAccessBeforeInit)
return
}
vm.push(*p)
vm.pc++
}
type loadStack1Lex int
func (l loadStack1Lex) exec(vm *vm) {
p := &vm.stack[vm.sb+int(l)]
if *p == nil {
vm.throw(errAccessBeforeInit)
return
}
vm.push(*p)
vm.pc++
}
type _loadCallee struct{}
var loadCallee _loadCallee
func (_loadCallee) exec(vm *vm) {
vm.push(vm.stack[vm.sb-1])
vm.pc++
}
func (vm *vm) storeStack(s int) {
// l > 0 -- var<l-1>
if s > 0 {
vm.stack[vm.sb+vm.args+s] = vm.stack[vm.sp-1]
} else {
panic("Illegal stack var index")
}
vm.pc++
}
func (vm *vm) storeStack1(s int) {
// args are in stash
// l > 0 -- var<l-1>
if s > 0 {
vm.stack[vm.sb+s] = vm.stack[vm.sp-1]
} else {
panic("Illegal stack var index")
}
vm.pc++
}
func (vm *vm) storeStackLex(s int) {
// l < 0 -- arg<-l-1>
// l > 0 -- var<l-1>
var p *Value
if s < 0 {
p = &vm.stack[vm.sb-s]
} else {
p = &vm.stack[vm.sb+vm.args+s]
}
if *p != nil {
*p = vm.stack[vm.sp-1]
} else {
panic(errAccessBeforeInit)
}
vm.pc++
}
func (vm *vm) storeStack1Lex(s int) {
// args are in stash
// s > 0 -- var<l-1>
if s <= 0 {
panic("Illegal stack var index")
}
p := &vm.stack[vm.sb+s]
if *p != nil {
*p = vm.stack[vm.sp-1]
} else {
panic(errAccessBeforeInit)
}
vm.pc++
}
func (vm *vm) initStack(s int) {
if s <= 0 {
vm.stack[vm.sb-s] = vm.stack[vm.sp-1]
} else {
vm.stack[vm.sb+vm.args+s] = vm.stack[vm.sp-1]
}
vm.pc++
}
func (vm *vm) initStack1(s int) {
if s <= 0 {
panic("Illegal stack var index")
}
vm.stack[vm.sb+s] = vm.stack[vm.sp-1]
vm.pc++
}
type storeStack int
func (s storeStack) exec(vm *vm) {
vm.storeStack(int(s))
}
type storeStack1 int
func (s storeStack1) exec(vm *vm) {
vm.storeStack1(int(s))
}
type storeStackLex int
func (s storeStackLex) exec(vm *vm) {
vm.storeStackLex(int(s))
}
type storeStack1Lex int
func (s storeStack1Lex) exec(vm *vm) {
vm.storeStack1Lex(int(s))
}
type initStack int
func (s initStack) exec(vm *vm) {
vm.initStack(int(s))
}
type initStackP int
func (s initStackP) exec(vm *vm) {
vm.initStack(int(s))
vm.sp--
}
type initStack1 int
func (s initStack1) exec(vm *vm) {
vm.initStack1(int(s))
}
type initStack1P int
func (s initStack1P) exec(vm *vm) {
vm.initStack1(int(s))
vm.sp--
}
type storeStackP int
func (s storeStackP) exec(vm *vm) {
vm.storeStack(int(s))
vm.sp--
}
type storeStack1P int
func (s storeStack1P) exec(vm *vm) {
vm.storeStack1(int(s))
vm.sp--
}
type storeStackLexP int
func (s storeStackLexP) exec(vm *vm) {
vm.storeStackLex(int(s))
vm.sp--
}
type storeStack1LexP int
func (s storeStack1LexP) exec(vm *vm) {
vm.storeStack1Lex(int(s))
vm.sp--
}
type _toNumber struct{}
var toNumber _toNumber
func (_toNumber) exec(vm *vm) {
vm.stack[vm.sp-1] = vm.stack[vm.sp-1].ToNumber()
vm.pc++
}
type _add struct{}
var add _add
func (_add) exec(vm *vm) {
right := vm.stack[vm.sp-1]
left := vm.stack[vm.sp-2]
if o, ok := left.(*Object); ok {
left = o.toPrimitive()
}
if o, ok := right.(*Object); ok {
right = o.toPrimitive()
}
var ret Value
leftString, isLeftString := left.(String)
rightString, isRightString := right.(String)
if isLeftString || isRightString {
if !isLeftString {
leftString = left.toString()
}
if !isRightString {
rightString = right.toString()
}
ret = leftString.Concat(rightString)
} else {
if leftInt, ok := left.(valueInt); ok {
if rightInt, ok := right.(valueInt); ok {
ret = intToValue(int64(leftInt) + int64(rightInt))
} else {
ret = floatToValue(float64(leftInt) + right.ToFloat())
}
} else {
ret = floatToValue(left.ToFloat() + right.ToFloat())
}
}
vm.stack[vm.sp-2] = ret
vm.sp--
vm.pc++
}
type _sub struct{}
var sub _sub
func (_sub) exec(vm *vm) {
right := vm.stack[vm.sp-1]
left := vm.stack[vm.sp-2]
var result Value
if left, ok := left.(valueInt); ok {
if right, ok := right.(valueInt); ok {
result = intToValue(int64(left) - int64(right))
goto end
}
}
result = floatToValue(left.ToFloat() - right.ToFloat())
end:
vm.sp--
vm.stack[vm.sp-1] = result
vm.pc++
}
type _mul struct{}
var mul _mul
func (_mul) exec(vm *vm) {
left := vm.stack[vm.sp-2]
right := vm.stack[vm.sp-1]
var result Value
if left, ok := assertInt64(left); ok {
if right, ok := assertInt64(right); ok {
if left == 0 && right == -1 || left == -1 && right == 0 {
result = _negativeZero
goto end
}
res := left * right
// check for overflow
if left == 0 || right == 0 || res/left == right {
result = intToValue(res)
goto end
}
}
}
result = floatToValue(left.ToFloat() * right.ToFloat())
end:
vm.sp--
vm.stack[vm.sp-1] = result
vm.pc++
}
type _exp struct{}
var exp _exp
func (_exp) exec(vm *vm) {
vm.sp--
vm.stack[vm.sp-1] = pow(vm.stack[vm.sp-1], vm.stack[vm.sp])
vm.pc++
}
type _div struct{}
var div _div
func (_div) exec(vm *vm) {
left := vm.stack[vm.sp-2].ToFloat()
right := vm.stack[vm.sp-1].ToFloat()
var result Value
if math.IsNaN(left) || math.IsNaN(right) {
result = _NaN
goto end
}
if math.IsInf(left, 0) && math.IsInf(right, 0) {
result = _NaN
goto end
}
if left == 0 && right == 0 {
result = _NaN
goto end
}
if math.IsInf(left, 0) {
if math.Signbit(left) == math.Signbit(right) {
result = _positiveInf
goto end
} else {
result = _negativeInf
goto end
}
}
if math.IsInf(right, 0) {
if math.Signbit(left) == math.Signbit(right) {
result = _positiveZero
goto end
} else {
result = _negativeZero
goto end
}
}
if right == 0 {
if math.Signbit(left) == math.Signbit(right) {
result = _positiveInf
goto end
} else {
result = _negativeInf
goto end
}
}
result = floatToValue(left / right)
end:
vm.sp--
vm.stack[vm.sp-1] = result
vm.pc++
}
type _mod struct{}
var mod _mod
func (_mod) exec(vm *vm) {
left := vm.stack[vm.sp-2]
right := vm.stack[vm.sp-1]
var result Value
if leftInt, ok := assertInt64(left); ok {
if rightInt, ok := assertInt64(right); ok {
if rightInt == 0 {
result = _NaN
goto end
}
r := leftInt % rightInt
if r == 0 && leftInt < 0 {
result = _negativeZero
} else {
result = intToValue(leftInt % rightInt)
}
goto end
}
}
result = floatToValue(math.Mod(left.ToFloat(), right.ToFloat()))
end:
vm.sp--
vm.stack[vm.sp-1] = result
vm.pc++
}
type _neg struct{}
var neg _neg
func (_neg) exec(vm *vm) {
operand := vm.stack[vm.sp-1]
var result Value
if i, ok := assertInt64(operand); ok {
if i == 0 {
result = _negativeZero
} else {
result = valueInt(-i)
}
} else {
f := operand.ToFloat()
if !math.IsNaN(f) {
f = -f
}
result = valueFloat(f)
}
vm.stack[vm.sp-1] = result
vm.pc++
}
type _plus struct{}
var plus _plus
func (_plus) exec(vm *vm) {
vm.stack[vm.sp-1] = vm.stack[vm.sp-1].ToNumber()
vm.pc++
}
type _inc struct{}
var inc _inc
func (_inc) exec(vm *vm) {
v := vm.stack[vm.sp-1]
if i, ok := assertInt64(v); ok {
v = intToValue(i + 1)
goto end
}
v = valueFloat(v.ToFloat() + 1)
end:
vm.stack[vm.sp-1] = v
vm.pc++
}
type _dec struct{}
var dec _dec
func (_dec) exec(vm *vm) {
v := vm.stack[vm.sp-1]
if i, ok := assertInt64(v); ok {
v = intToValue(i - 1)
goto end
}
v = valueFloat(v.ToFloat() - 1)
end:
vm.stack[vm.sp-1] = v
vm.pc++
}
type _and struct{}
var and _and
func (_and) exec(vm *vm) {
left := toInt32(vm.stack[vm.sp-2])
right := toInt32(vm.stack[vm.sp-1])
vm.stack[vm.sp-2] = intToValue(int64(left & right))
vm.sp--
vm.pc++
}
type _or struct{}
var or _or
func (_or) exec(vm *vm) {
left := toInt32(vm.stack[vm.sp-2])
right := toInt32(vm.stack[vm.sp-1])
vm.stack[vm.sp-2] = intToValue(int64(left | right))
vm.sp--
vm.pc++
}
type _xor struct{}
var xor _xor
func (_xor) exec(vm *vm) {
left := toInt32(vm.stack[vm.sp-2])
right := toInt32(vm.stack[vm.sp-1])
vm.stack[vm.sp-2] = intToValue(int64(left ^ right))
vm.sp--
vm.pc++
}
type _bnot struct{}
var bnot _bnot
func (_bnot) exec(vm *vm) {
op := toInt32(vm.stack[vm.sp-1])
vm.stack[vm.sp-1] = intToValue(int64(^op))
vm.pc++
}
type _sal struct{}
var sal _sal
func (_sal) exec(vm *vm) {
left := toInt32(vm.stack[vm.sp-2])
right := toUint32(vm.stack[vm.sp-1])
vm.stack[vm.sp-2] = intToValue(int64(left << (right & 0x1F)))
vm.sp--
vm.pc++
}
type _sar struct{}
var sar _sar
func (_sar) exec(vm *vm) {
left := toInt32(vm.stack[vm.sp-2])
right := toUint32(vm.stack[vm.sp-1])
vm.stack[vm.sp-2] = intToValue(int64(left >> (right & 0x1F)))
vm.sp--
vm.pc++
}
type _shr struct{}
var shr _shr
func (_shr) exec(vm *vm) {
left := toUint32(vm.stack[vm.sp-2])
right := toUint32(vm.stack[vm.sp-1])
vm.stack[vm.sp-2] = intToValue(int64(left >> (right & 0x1F)))
vm.sp--
vm.pc++
}
type jump int32
func (j jump) exec(vm *vm) {
vm.pc += int(j)
}
type _toPropertyKey struct{}
func (_toPropertyKey) exec(vm *vm) {
p := vm.sp - 1
vm.stack[p] = toPropertyKey(vm.stack[p])
vm.pc++
}
type _toString struct{}
func (_toString) exec(vm *vm) {
p := vm.sp - 1
vm.stack[p] = vm.stack[p].toString()
vm.pc++
}
type _getElemRef struct{}
var getElemRef _getElemRef
func (_getElemRef) exec(vm *vm) {
obj := vm.stack[vm.sp-2].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-1])
vm.refStack = append(vm.refStack, &objRef{
base: obj,
name: propName.string(),
})
vm.sp -= 2
vm.pc++
}
type _getElemRefRecv struct{}
var getElemRefRecv _getElemRefRecv
func (_getElemRefRecv) exec(vm *vm) {
obj := vm.stack[vm.sp-1].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-2])
vm.refStack = append(vm.refStack, &objRef{
base: obj,
name: propName.string(),
this: vm.stack[vm.sp-3],
})
vm.sp -= 3
vm.pc++
}
type _getElemRefStrict struct{}
var getElemRefStrict _getElemRefStrict
func (_getElemRefStrict) exec(vm *vm) {
obj := vm.stack[vm.sp-2].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-1])
vm.refStack = append(vm.refStack, &objRef{
base: obj,
name: propName.string(),
strict: true,
})
vm.sp -= 2
vm.pc++
}
type _getElemRefRecvStrict struct{}
var getElemRefRecvStrict _getElemRefRecvStrict
func (_getElemRefRecvStrict) exec(vm *vm) {
obj := vm.stack[vm.sp-1].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-2])
vm.refStack = append(vm.refStack, &objRef{
base: obj,
name: propName.string(),
this: vm.stack[vm.sp-3],
strict: true,
})
vm.sp -= 3
vm.pc++
}
type _setElem struct{}
var setElem _setElem
func (_setElem) exec(vm *vm) {
obj := vm.stack[vm.sp-3].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-2])
val := vm.stack[vm.sp-1]
obj.setOwn(propName, val, false)
vm.sp -= 2
vm.stack[vm.sp-1] = val
vm.pc++
}
type _setElem1 struct{}
var setElem1 _setElem1
func (_setElem1) exec(vm *vm) {
obj := vm.stack[vm.sp-3].ToObject(vm.r)
propName := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
obj.setOwn(propName, val, true)
vm.sp -= 2
vm.pc++
}
type _setElem1Named struct{}
var setElem1Named _setElem1Named
func (_setElem1Named) exec(vm *vm) {
receiver := vm.stack[vm.sp-3]
base := receiver.ToObject(vm.r)
propName := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
vm.r.toObject(val).self.defineOwnPropertyStr("name", PropertyDescriptor{
Value: funcName("", propName),
Configurable: FLAG_TRUE,
}, true)
base.set(propName, val, receiver, true)
vm.sp -= 2
vm.pc++
}
type defineMethod struct {
enumerable bool
}
func (d *defineMethod) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-3])
propName := vm.stack[vm.sp-2]
method := vm.r.toObject(vm.stack[vm.sp-1])
method.self.defineOwnPropertyStr("name", PropertyDescriptor{
Value: funcName("", propName),
Configurable: FLAG_TRUE,
}, true)
obj.defineOwnProperty(propName, PropertyDescriptor{
Value: method,
Writable: FLAG_TRUE,
Configurable: FLAG_TRUE,
Enumerable: ToFlag(d.enumerable),
}, true)
vm.sp -= 2
vm.pc++
}
type _setElemP struct{}
var setElemP _setElemP
func (_setElemP) exec(vm *vm) {
obj := vm.stack[vm.sp-3].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-2])
val := vm.stack[vm.sp-1]
obj.setOwn(propName, val, false)
vm.sp -= 3
vm.pc++
}
type _setElemStrict struct{}
var setElemStrict _setElemStrict
func (_setElemStrict) exec(vm *vm) {
propName := toPropertyKey(vm.stack[vm.sp-2])
receiver := vm.stack[vm.sp-3]
val := vm.stack[vm.sp-1]
if receiverObj, ok := receiver.(*Object); ok {
receiverObj.setOwn(propName, val, true)
} else {
base := receiver.ToObject(vm.r)
base.set(propName, val, receiver, true)
}
vm.sp -= 2
vm.stack[vm.sp-1] = val
vm.pc++
}
type _setElemRecv struct{}
var setElemRecv _setElemRecv
func (_setElemRecv) exec(vm *vm) {
receiver := vm.stack[vm.sp-4]
propName := toPropertyKey(vm.stack[vm.sp-3])
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
if obj, ok := o.(*Object); ok {
obj.set(propName, val, receiver, false)
} else {
base := o.ToObject(vm.r)
base.set(propName, val, receiver, false)
}
vm.sp -= 3
vm.stack[vm.sp-1] = val
vm.pc++
}
type _setElemRecvStrict struct{}
var setElemRecvStrict _setElemRecvStrict
func (_setElemRecvStrict) exec(vm *vm) {
receiver := vm.stack[vm.sp-4]
propName := toPropertyKey(vm.stack[vm.sp-3])
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
if obj, ok := o.(*Object); ok {
obj.set(propName, val, receiver, true)
} else {
base := o.ToObject(vm.r)
base.set(propName, val, receiver, true)
}
vm.sp -= 3
vm.stack[vm.sp-1] = val
vm.pc++
}
type _setElemStrictP struct{}
var setElemStrictP _setElemStrictP
func (_setElemStrictP) exec(vm *vm) {
propName := toPropertyKey(vm.stack[vm.sp-2])
receiver := vm.stack[vm.sp-3]
val := vm.stack[vm.sp-1]
if receiverObj, ok := receiver.(*Object); ok {
receiverObj.setOwn(propName, val, true)
} else {
base := receiver.ToObject(vm.r)
base.set(propName, val, receiver, true)
}
vm.sp -= 3
vm.pc++
}
type _setElemRecvP struct{}
var setElemRecvP _setElemRecvP
func (_setElemRecvP) exec(vm *vm) {
receiver := vm.stack[vm.sp-4]
propName := toPropertyKey(vm.stack[vm.sp-3])
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
if obj, ok := o.(*Object); ok {
obj.set(propName, val, receiver, false)
} else {
base := o.ToObject(vm.r)
base.set(propName, val, receiver, false)
}
vm.sp -= 4
vm.pc++
}
type _setElemRecvStrictP struct{}
var setElemRecvStrictP _setElemRecvStrictP
func (_setElemRecvStrictP) exec(vm *vm) {
receiver := vm.stack[vm.sp-4]
propName := toPropertyKey(vm.stack[vm.sp-3])
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
if obj, ok := o.(*Object); ok {
obj.set(propName, val, receiver, true)
} else {
base := o.ToObject(vm.r)
base.set(propName, val, receiver, true)
}
vm.sp -= 4
vm.pc++
}
type _deleteElem struct{}
var deleteElem _deleteElem
func (_deleteElem) exec(vm *vm) {
obj := vm.stack[vm.sp-2].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-1])
if obj.delete(propName, false) {
vm.stack[vm.sp-2] = valueTrue
} else {
vm.stack[vm.sp-2] = valueFalse
}
vm.sp--
vm.pc++
}
type _deleteElemStrict struct{}
var deleteElemStrict _deleteElemStrict
func (_deleteElemStrict) exec(vm *vm) {
obj := vm.stack[vm.sp-2].ToObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-1])
obj.delete(propName, true)
vm.stack[vm.sp-2] = valueTrue
vm.sp--
vm.pc++
}
type deleteProp unistring.String
func (d deleteProp) exec(vm *vm) {
obj := vm.stack[vm.sp-1].ToObject(vm.r)
if obj.self.deleteStr(unistring.String(d), false) {
vm.stack[vm.sp-1] = valueTrue
} else {
vm.stack[vm.sp-1] = valueFalse
}
vm.pc++
}
type deletePropStrict unistring.String
func (d deletePropStrict) exec(vm *vm) {
obj := vm.stack[vm.sp-1].ToObject(vm.r)
obj.self.deleteStr(unistring.String(d), true)
vm.stack[vm.sp-1] = valueTrue
vm.pc++
}
type getPropRef unistring.String
func (p getPropRef) exec(vm *vm) {
vm.refStack = append(vm.refStack, &objRef{
base: vm.stack[vm.sp-1].ToObject(vm.r),
name: unistring.String(p),
})
vm.sp--
vm.pc++
}
type getPropRefRecv unistring.String
func (p getPropRefRecv) exec(vm *vm) {
vm.refStack = append(vm.refStack, &objRef{
this: vm.stack[vm.sp-2],
base: vm.stack[vm.sp-1].ToObject(vm.r),
name: unistring.String(p),
})
vm.sp -= 2
vm.pc++
}
type getPropRefStrict unistring.String
func (p getPropRefStrict) exec(vm *vm) {
vm.refStack = append(vm.refStack, &objRef{
base: vm.stack[vm.sp-1].ToObject(vm.r),
name: unistring.String(p),
strict: true,
})
vm.sp--
vm.pc++
}
type getPropRefRecvStrict unistring.String
func (p getPropRefRecvStrict) exec(vm *vm) {
vm.refStack = append(vm.refStack, &objRef{
this: vm.stack[vm.sp-2],
base: vm.stack[vm.sp-1].ToObject(vm.r),
name: unistring.String(p),
strict: true,
})
vm.sp -= 2
vm.pc++
}
type setProp unistring.String
func (p setProp) exec(vm *vm) {
val := vm.stack[vm.sp-1]
vm.stack[vm.sp-2].ToObject(vm.r).self.setOwnStr(unistring.String(p), val, false)
vm.stack[vm.sp-2] = val
vm.sp--
vm.pc++
}
type setPropP unistring.String
func (p setPropP) exec(vm *vm) {
val := vm.stack[vm.sp-1]
vm.stack[vm.sp-2].ToObject(vm.r).self.setOwnStr(unistring.String(p), val, false)
vm.sp -= 2
vm.pc++
}
type setPropStrict unistring.String
func (p setPropStrict) exec(vm *vm) {
receiver := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
propName := unistring.String(p)
if receiverObj, ok := receiver.(*Object); ok {
receiverObj.self.setOwnStr(propName, val, true)
} else {
base := receiver.ToObject(vm.r)
base.setStr(propName, val, receiver, true)
}
vm.stack[vm.sp-2] = val
vm.sp--
vm.pc++
}
type setPropRecv unistring.String
func (p setPropRecv) exec(vm *vm) {
receiver := vm.stack[vm.sp-3]
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
propName := unistring.String(p)
if obj, ok := o.(*Object); ok {
obj.setStr(propName, val, receiver, false)
} else {
base := o.ToObject(vm.r)
base.setStr(propName, val, receiver, false)
}
vm.stack[vm.sp-3] = val
vm.sp -= 2
vm.pc++
}
type setPropRecvStrict unistring.String
func (p setPropRecvStrict) exec(vm *vm) {
receiver := vm.stack[vm.sp-3]
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
propName := unistring.String(p)
if obj, ok := o.(*Object); ok {
obj.setStr(propName, val, receiver, true)
} else {
base := o.ToObject(vm.r)
base.setStr(propName, val, receiver, true)
}
vm.stack[vm.sp-3] = val
vm.sp -= 2
vm.pc++
}
type setPropRecvP unistring.String
func (p setPropRecvP) exec(vm *vm) {
receiver := vm.stack[vm.sp-3]
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
propName := unistring.String(p)
if obj, ok := o.(*Object); ok {
obj.setStr(propName, val, receiver, false)
} else {
base := o.ToObject(vm.r)
base.setStr(propName, val, receiver, false)
}
vm.sp -= 3
vm.pc++
}
type setPropRecvStrictP unistring.String
func (p setPropRecvStrictP) exec(vm *vm) {
receiver := vm.stack[vm.sp-3]
o := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
propName := unistring.String(p)
if obj, ok := o.(*Object); ok {
obj.setStr(propName, val, receiver, true)
} else {
base := o.ToObject(vm.r)
base.setStr(propName, val, receiver, true)
}
vm.sp -= 3
vm.pc++
}
type setPropStrictP unistring.String
func (p setPropStrictP) exec(vm *vm) {
receiver := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
propName := unistring.String(p)
if receiverObj, ok := receiver.(*Object); ok {
receiverObj.self.setOwnStr(propName, val, true)
} else {
base := receiver.ToObject(vm.r)
base.setStr(propName, val, receiver, true)
}
vm.sp -= 2
vm.pc++
}
type putProp unistring.String
func (p putProp) exec(vm *vm) {
vm.r.toObject(vm.stack[vm.sp-2]).self._putProp(unistring.String(p), vm.stack[vm.sp-1], true, true, true)
vm.sp--
vm.pc++
}
// used in class declarations instead of putProp because DefineProperty must be observable by Proxy
type definePropKeyed unistring.String
func (p definePropKeyed) exec(vm *vm) {
vm.r.toObject(vm.stack[vm.sp-2]).self.defineOwnPropertyStr(unistring.String(p), PropertyDescriptor{
Value: vm.stack[vm.sp-1],
Writable: FLAG_TRUE,
Configurable: FLAG_TRUE,
Enumerable: FLAG_TRUE,
}, true)
vm.sp--
vm.pc++
}
type defineProp struct{}
func (defineProp) exec(vm *vm) {
vm.r.toObject(vm.stack[vm.sp-3]).defineOwnProperty(vm.stack[vm.sp-2], PropertyDescriptor{
Value: vm.stack[vm.sp-1],
Writable: FLAG_TRUE,
Configurable: FLAG_TRUE,
Enumerable: FLAG_TRUE,
}, true)
vm.sp -= 2
vm.pc++
}
type defineMethodKeyed struct {
key unistring.String
enumerable bool
}
func (d *defineMethodKeyed) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-2])
method := vm.r.toObject(vm.stack[vm.sp-1])
obj.self.defineOwnPropertyStr(d.key, PropertyDescriptor{
Value: method,
Writable: FLAG_TRUE,
Configurable: FLAG_TRUE,
Enumerable: ToFlag(d.enumerable),
}, true)
vm.sp--
vm.pc++
}
type _setProto struct{}
var setProto _setProto
func (_setProto) exec(vm *vm) {
vm.r.setObjectProto(vm.stack[vm.sp-2], vm.stack[vm.sp-1])
vm.sp--
vm.pc++
}
type defineGetterKeyed struct {
key unistring.String
enumerable bool
}
func (s *defineGetterKeyed) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-2])
val := vm.stack[vm.sp-1]
method := vm.r.toObject(val)
method.self.defineOwnPropertyStr("name", PropertyDescriptor{
Value: asciiString("get ").Concat(stringValueFromRaw(s.key)),
Configurable: FLAG_TRUE,
}, true)
descr := PropertyDescriptor{
Getter: val,
Configurable: FLAG_TRUE,
Enumerable: ToFlag(s.enumerable),
}
obj.self.defineOwnPropertyStr(s.key, descr, true)
vm.sp--
vm.pc++
}
type defineSetterKeyed struct {
key unistring.String
enumerable bool
}
func (s *defineSetterKeyed) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-2])
val := vm.stack[vm.sp-1]
method := vm.r.toObject(val)
method.self.defineOwnPropertyStr("name", PropertyDescriptor{
Value: asciiString("set ").Concat(stringValueFromRaw(s.key)),
Configurable: FLAG_TRUE,
}, true)
descr := PropertyDescriptor{
Setter: val,
Configurable: FLAG_TRUE,
Enumerable: ToFlag(s.enumerable),
}
obj.self.defineOwnPropertyStr(s.key, descr, true)
vm.sp--
vm.pc++
}
type defineGetter struct {
enumerable bool
}
func (s *defineGetter) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-3])
propName := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
method := vm.r.toObject(val)
method.self.defineOwnPropertyStr("name", PropertyDescriptor{
Value: funcName("get ", propName),
Configurable: FLAG_TRUE,
}, true)
descr := PropertyDescriptor{
Getter: val,
Configurable: FLAG_TRUE,
Enumerable: ToFlag(s.enumerable),
}
obj.defineOwnProperty(propName, descr, true)
vm.sp -= 2
vm.pc++
}
type defineSetter struct {
enumerable bool
}
func (s *defineSetter) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-3])
propName := vm.stack[vm.sp-2]
val := vm.stack[vm.sp-1]
method := vm.r.toObject(val)
method.self.defineOwnPropertyStr("name", PropertyDescriptor{
Value: funcName("set ", propName),
Configurable: FLAG_TRUE,
}, true)
descr := PropertyDescriptor{
Setter: val,
Configurable: FLAG_TRUE,
Enumerable: FLAG_TRUE,
}
obj.defineOwnProperty(propName, descr, true)
vm.sp -= 2
vm.pc++
}
type getProp unistring.String
func (g getProp) exec(vm *vm) {
v := vm.stack[vm.sp-1]
obj := v.baseObject(vm.r)
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", g))
return
}
vm.stack[vm.sp-1] = nilSafe(obj.self.getStr(unistring.String(g), v))
vm.pc++
}
type getPropRecv unistring.String
func (g getPropRecv) exec(vm *vm) {
recv := vm.stack[vm.sp-2]
v := vm.stack[vm.sp-1]
obj := v.baseObject(vm.r)
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", g))
return
}
vm.stack[vm.sp-2] = nilSafe(obj.self.getStr(unistring.String(g), recv))
vm.sp--
vm.pc++
}
type getPropRecvCallee unistring.String
func (g getPropRecvCallee) exec(vm *vm) {
recv := vm.stack[vm.sp-2]
v := vm.stack[vm.sp-1]
obj := v.baseObject(vm.r)
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", g))
return
}
n := unistring.String(g)
prop := obj.self.getStr(n, recv)
if prop == nil {
prop = memberUnresolved{valueUnresolved{r: vm.r, ref: n}}
}
vm.stack[vm.sp-1] = prop
vm.pc++
}
type getPropCallee unistring.String
func (g getPropCallee) exec(vm *vm) {
v := vm.stack[vm.sp-1]
obj := v.baseObject(vm.r)
n := unistring.String(g)
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined or null", n))
return
}
prop := obj.self.getStr(n, v)
if prop == nil {
prop = memberUnresolved{valueUnresolved{r: vm.r, ref: n}}
}
vm.push(prop)
vm.pc++
}
type _getElem struct{}
var getElem _getElem
func (_getElem) exec(vm *vm) {
v := vm.stack[vm.sp-2]
obj := v.baseObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-1])
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
return
}
vm.stack[vm.sp-2] = nilSafe(obj.get(propName, v))
vm.sp--
vm.pc++
}
type _getElemRecv struct{}
var getElemRecv _getElemRecv
func (_getElemRecv) exec(vm *vm) {
recv := vm.stack[vm.sp-3]
propName := toPropertyKey(vm.stack[vm.sp-2])
v := vm.stack[vm.sp-1]
obj := v.baseObject(vm.r)
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
return
}
vm.stack[vm.sp-3] = nilSafe(obj.get(propName, recv))
vm.sp -= 2
vm.pc++
}
type _getKey struct{}
var getKey _getKey
func (_getKey) exec(vm *vm) {
v := vm.stack[vm.sp-2]
obj := v.baseObject(vm.r)
propName := vm.stack[vm.sp-1]
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
return
}
vm.stack[vm.sp-2] = nilSafe(obj.get(propName, v))
vm.sp--
vm.pc++
}
type _getElemCallee struct{}
var getElemCallee _getElemCallee
func (_getElemCallee) exec(vm *vm) {
v := vm.stack[vm.sp-2]
obj := v.baseObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-1])
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
return
}
prop := obj.get(propName, v)
if prop == nil {
prop = memberUnresolved{valueUnresolved{r: vm.r, ref: propName.string()}}
}
vm.stack[vm.sp-1] = prop
vm.pc++
}
type _getElemRecvCallee struct{}
var getElemRecvCallee _getElemRecvCallee
func (_getElemRecvCallee) exec(vm *vm) {
recv := vm.stack[vm.sp-3]
v := vm.stack[vm.sp-2]
obj := v.baseObject(vm.r)
propName := toPropertyKey(vm.stack[vm.sp-1])
if obj == nil {
vm.throw(vm.r.NewTypeError("Cannot read property '%s' of undefined", propName.String()))
return
}
prop := obj.get(propName, recv)
if prop == nil {
prop = memberUnresolved{valueUnresolved{r: vm.r, ref: propName.string()}}
}
vm.stack[vm.sp-2] = prop
vm.sp--
vm.pc++
}
type _dup struct{}
var dup _dup
func (_dup) exec(vm *vm) {
vm.push(vm.stack[vm.sp-1])
vm.pc++
}
type dupN uint32
func (d dupN) exec(vm *vm) {
vm.push(vm.stack[vm.sp-1-int(d)])
vm.pc++
}
type rdupN uint32
func (d rdupN) exec(vm *vm) {
vm.stack[vm.sp-1-int(d)] = vm.stack[vm.sp-1]
vm.pc++
}
type dupLast uint32
func (d dupLast) exec(vm *vm) {
e := vm.sp + int(d)
vm.stack.expand(e)
copy(vm.stack[vm.sp:e], vm.stack[vm.sp-int(d):])
vm.sp = e
vm.pc++
}
type _newObject struct{}
var newObject _newObject
func (_newObject) exec(vm *vm) {
vm.push(vm.r.NewObject())
vm.pc++
}
type newArray uint32
func (l newArray) exec(vm *vm) {
values := make([]Value, 0, l)
vm.push(vm.r.newArrayValues(values))
vm.pc++
}
type _pushArrayItem struct{}
var pushArrayItem _pushArrayItem
func (_pushArrayItem) exec(vm *vm) {
arr := vm.stack[vm.sp-2].(*Object).self.(*arrayObject)
if arr.length < math.MaxUint32 {
arr.length++
} else {
vm.throw(vm.r.newError(vm.r.getRangeError(), "Invalid array length"))
return
}
val := vm.stack[vm.sp-1]
arr.values = append(arr.values, val)
if val != nil {
arr.objCount++
}
vm.sp--
vm.pc++
}
type _pushArraySpread struct{}
var pushArraySpread _pushArraySpread
func (_pushArraySpread) exec(vm *vm) {
arr := vm.stack[vm.sp-2].(*Object).self.(*arrayObject)
vm.r.getIterator(vm.stack[vm.sp-1], nil).iterate(func(val Value) {
if arr.length < math.MaxUint32 {
arr.length++
} else {
vm.throw(vm.r.newError(vm.r.getRangeError(), "Invalid array length"))
return
}
arr.values = append(arr.values, val)
arr.objCount++
})
vm.sp--
vm.pc++
}
type _pushSpread struct{}
var pushSpread _pushSpread
func (_pushSpread) exec(vm *vm) {
vm.sp--
obj := vm.stack[vm.sp]
vm.r.getIterator(obj, nil).iterate(func(val Value) {
vm.push(val)
})
vm.pc++
}
type _newArrayFromIter struct{}
var newArrayFromIter _newArrayFromIter
func (_newArrayFromIter) exec(vm *vm) {
var values []Value
l := len(vm.iterStack) - 1
iter := vm.iterStack[l].iter
vm.iterStack[l] = iterStackItem{}
vm.iterStack = vm.iterStack[:l]
if iter.iterator != nil {
iter.iterate(func(val Value) {
values = append(values, val)
})
}
vm.push(vm.r.newArrayValues(values))
vm.pc++
}
type newRegexp struct {
pattern *regexpPattern
src String
}
func (n *newRegexp) exec(vm *vm) {
vm.push(vm.r.newRegExpp(n.pattern.clone(), n.src, vm.r.getRegExpPrototype()).val)
vm.pc++
}
func (vm *vm) setLocalLex(s int) {
v := vm.stack[vm.sp-1]
level := s >> 24
idx := uint32(s & 0x00FFFFFF)
stash := vm.stash
for i := 0; i < level; i++ {
stash = stash.outer
}
p := &stash.values[idx]
if *p == nil {
panic(errAccessBeforeInit)
}
*p = v
vm.pc++
}
func (vm *vm) initLocal(s int) {
v := vm.stack[vm.sp-1]
level := s >> 24
idx := uint32(s & 0x00FFFFFF)
stash := vm.stash
for i := 0; i < level; i++ {
stash = stash.outer
}
stash.initByIdx(idx, v)
vm.pc++
}
type storeStash uint32
func (s storeStash) exec(vm *vm) {
vm.initLocal(int(s))
}
type storeStashP uint32
func (s storeStashP) exec(vm *vm) {
vm.initLocal(int(s))
vm.sp--
}
type storeStashLex uint32
func (s storeStashLex) exec(vm *vm) {
vm.setLocalLex(int(s))
}
type storeStashLexP uint32
func (s storeStashLexP) exec(vm *vm) {
vm.setLocalLex(int(s))
vm.sp--
}
type initStash uint32
func (s initStash) exec(vm *vm) {
vm.initLocal(int(s))
}
type initStashP uint32
func (s initStashP) exec(vm *vm) {
vm.initLocal(int(s))
vm.sp--
}
type initGlobalP unistring.String
func (s initGlobalP) exec(vm *vm) {
vm.sp--
vm.r.global.stash.initByName(unistring.String(s), vm.stack[vm.sp])
vm.pc++
}
type initGlobal unistring.String
func (s initGlobal) exec(vm *vm) {
vm.r.global.stash.initByName(unistring.String(s), vm.stack[vm.sp])
vm.pc++
}
type resolveVar1 unistring.String
func (s resolveVar1) exec(vm *vm) {
name := unistring.String(s)
var ref ref
for stash := vm.stash; stash != nil; stash = stash.outer {
ref = stash.getRefByName(name, false)
if ref != nil {
goto end
}
}
ref = &objRef{
base: vm.r.globalObject,
name: name,
binding: true,
}
end:
vm.refStack = append(vm.refStack, ref)
vm.pc++
}
type deleteVar unistring.String
func (d deleteVar) exec(vm *vm) {
name := unistring.String(d)
ret := true
for stash := vm.stash; stash != nil; stash = stash.outer {
if stash.obj != nil {
if stashObjHas(stash.obj, name) {
ret = stash.obj.self.deleteStr(name, false)
goto end
}
} else {
if idx, exists := stash.names[name]; exists {
if idx&(maskVar|maskDeletable) == maskVar|maskDeletable {
stash.deleteBinding(name)
} else {
ret = false
}
goto end
}
}
}
if vm.r.globalObject.self.hasPropertyStr(name) {
ret = vm.r.globalObject.self.deleteStr(name, false)
}
end:
if ret {
vm.push(valueTrue)
} else {
vm.push(valueFalse)
}
vm.pc++
}
type deleteGlobal unistring.String
func (d deleteGlobal) exec(vm *vm) {
name := unistring.String(d)
var ret bool
if vm.r.globalObject.self.hasPropertyStr(name) {
ret = vm.r.globalObject.self.deleteStr(name, false)
if ret {
delete(vm.r.global.varNames, name)
}
} else {
ret = true
}
if ret {
vm.push(valueTrue)
} else {
vm.push(valueFalse)
}
vm.pc++
}
type resolveVar1Strict unistring.String
func (s resolveVar1Strict) exec(vm *vm) {
name := unistring.String(s)
var ref ref
for stash := vm.stash; stash != nil; stash = stash.outer {
ref = stash.getRefByName(name, true)
if ref != nil {
goto end
}
}
if vm.r.globalObject.self.hasPropertyStr(name) {
ref = &objRef{
base: vm.r.globalObject,
name: name,
binding: true,
strict: true,
}
goto end
}
ref = &unresolvedRef{
runtime: vm.r,
name: name,
}
end:
vm.refStack = append(vm.refStack, ref)
vm.pc++
}
type setGlobal unistring.String
func (s setGlobal) exec(vm *vm) {
vm.r.setGlobal(unistring.String(s), vm.peek(), false)
vm.pc++
}
type setGlobalStrict unistring.String
func (s setGlobalStrict) exec(vm *vm) {
vm.r.setGlobal(unistring.String(s), vm.peek(), true)
vm.pc++
}
// Load a var from stash
type loadStash uint32
func (g loadStash) exec(vm *vm) {
level := int(g >> 24)
idx := uint32(g & 0x00FFFFFF)
stash := vm.stash
for i := 0; i < level; i++ {
stash = stash.outer
}
vm.push(nilSafe(stash.getByIdx(idx)))
vm.pc++
}
// Load a lexical binding from stash
type loadStashLex uint32
func (g loadStashLex) exec(vm *vm) {
level := int(g >> 24)
idx := uint32(g & 0x00FFFFFF)
stash := vm.stash
for i := 0; i < level; i++ {
stash = stash.outer
}
v := stash.getByIdx(idx)
if v == nil {
vm.throw(errAccessBeforeInit)
return
}
vm.push(v)
vm.pc++
}
// scan dynamic stashes up to the given level (encoded as 8 most significant bits of idx), if not found
// return the indexed var binding value from stash
type loadMixed struct {
name unistring.String
idx uint32
callee bool
}
func (g *loadMixed) exec(vm *vm) {
level := int(g.idx >> 24)
idx := g.idx & 0x00FFFFFF
stash := vm.stash
name := g.name
for i := 0; i < level; i++ {
if v, found := stash.getByName(name); found {
if g.callee {
if stash.obj != nil {
vm.push(stash.obj)
} else {
vm.push(_undefined)
}
}
vm.push(v)
goto end
}
stash = stash.outer
}
if g.callee {
vm.push(_undefined)
}
if stash != nil {
vm.push(nilSafe(stash.getByIdx(idx)))
}
end:
vm.pc++
}
// scan dynamic stashes up to the given level (encoded as 8 most significant bits of idx), if not found
// return the indexed lexical binding value from stash
type loadMixedLex loadMixed
func (g *loadMixedLex) exec(vm *vm) {
level := int(g.idx >> 24)
idx := g.idx & 0x00FFFFFF
stash := vm.stash
name := g.name
for i := 0; i < level; i++ {
if v, found := stash.getByName(name); found {
if g.callee {
if stash.obj != nil {
vm.push(stash.obj)
} else {
vm.push(_undefined)
}
}
vm.push(v)
goto end
}
stash = stash.outer
}
if g.callee {
vm.push(_undefined)
}
if stash != nil {
v := stash.getByIdx(idx)
if v == nil {
vm.throw(errAccessBeforeInit)
return
}
vm.push(v)
}
end:
vm.pc++
}
// scan dynamic stashes up to the given level (encoded as 8 most significant bits of idx), if not found
// return the indexed var binding value from stack
type loadMixedStack struct {
name unistring.String
idx int
level uint8
callee bool
}
// same as loadMixedStack, but the args have been moved to stash (therefore stack layout is different)
type loadMixedStack1 loadMixedStack
func (g *loadMixedStack) exec(vm *vm) {
stash := vm.stash
name := g.name
level := int(g.level)
for i := 0; i < level; i++ {
if v, found := stash.getByName(name); found {
if g.callee {
if stash.obj != nil {
vm.push(stash.obj)
} else {
vm.push(_undefined)
}
}
vm.push(v)
goto end
}
stash = stash.outer
}
if g.callee {
vm.push(_undefined)
}
loadStack(g.idx).exec(vm)
return
end:
vm.pc++
}
func (g *loadMixedStack1) exec(vm *vm) {
stash := vm.stash
name := g.name
level := int(g.level)
for i := 0; i < level; i++ {
if v, found := stash.getByName(name); found {
if g.callee {
if stash.obj != nil {
vm.push(stash.obj)
} else {
vm.push(_undefined)
}
}
vm.push(v)
goto end
}
stash = stash.outer
}
if g.callee {
vm.push(_undefined)
}
loadStack1(g.idx).exec(vm)
return
end:
vm.pc++
}
type loadMixedStackLex loadMixedStack
// same as loadMixedStackLex but when the arguments have been moved into stash
type loadMixedStack1Lex loadMixedStack
func (g *loadMixedStackLex) exec(vm *vm) {
stash := vm.stash
name := g.name
level := int(g.level)
for i := 0; i < level; i++ {
if v, found := stash.getByName(name); found {
if g.callee {
if stash.obj != nil {
vm.push(stash.obj)
} else {
vm.push(_undefined)
}
}
vm.push(v)
goto end
}
stash = stash.outer
}
if g.callee {
vm.push(_undefined)
}
loadStackLex(g.idx).exec(vm)
return
end:
vm.pc++
}
func (g *loadMixedStack1Lex) exec(vm *vm) {
stash := vm.stash
name := g.name
level := int(g.level)
for i := 0; i < level; i++ {
if v, found := stash.getByName(name); found {
if g.callee {
if stash.obj != nil {
vm.push(stash.obj)
} else {
vm.push(_undefined)
}
}
vm.push(v)
goto end
}
stash = stash.outer
}
if g.callee {
vm.push(_undefined)
}
loadStack1Lex(g.idx).exec(vm)
return
end:
vm.pc++
}
type resolveMixed struct {
name unistring.String
idx uint32
typ varType
strict bool
}
func newStashRef(typ varType, name unistring.String, v *[]Value, idx int) ref {
switch typ {
case varTypeVar:
return &stashRef{
n: name,
v: v,
idx: idx,
}
case varTypeLet:
return &stashRefLex{
stashRef: stashRef{
n: name,
v: v,
idx: idx,
},
}
case varTypeConst, varTypeStrictConst:
return &stashRefConst{
stashRefLex: stashRefLex{
stashRef: stashRef{
n: name,
v: v,
idx: idx,
},
},
strictConst: typ == varTypeStrictConst,
}
}
panic("unsupported var type")
}
func (r *resolveMixed) exec(vm *vm) {
level := int(r.idx >> 24)
idx := r.idx & 0x00FFFFFF
stash := vm.stash
var ref ref
for i := 0; i < level; i++ {
ref = stash.getRefByName(r.name, r.strict)
if ref != nil {
goto end
}
stash = stash.outer
}
if stash != nil {
ref = newStashRef(r.typ, r.name, &stash.values, int(idx))
goto end
}
ref = &unresolvedRef{
runtime: vm.r,
name: r.name,
}
end:
vm.refStack = append(vm.refStack, ref)
vm.pc++
}
type resolveMixedStack struct {
name unistring.String
idx int
typ varType
level uint8
strict bool
}
type resolveMixedStack1 resolveMixedStack
func (r *resolveMixedStack) exec(vm *vm) {
level := int(r.level)
stash := vm.stash
var ref ref
var idx int
for i := 0; i < level; i++ {
ref = stash.getRefByName(r.name, r.strict)
if ref != nil {
goto end
}
stash = stash.outer
}
if r.idx > 0 {
idx = vm.sb + vm.args + r.idx
} else {
idx = vm.sb - r.idx
}
ref = newStashRef(r.typ, r.name, (*[]Value)(&vm.stack), idx)
end:
vm.refStack = append(vm.refStack, ref)
vm.pc++
}
func (r *resolveMixedStack1) exec(vm *vm) {
level := int(r.level)
stash := vm.stash
var ref ref
for i := 0; i < level; i++ {
ref = stash.getRefByName(r.name, r.strict)
if ref != nil {
goto end
}
stash = stash.outer
}
ref = newStashRef(r.typ, r.name, (*[]Value)(&vm.stack), vm.sb+r.idx)
end:
vm.refStack = append(vm.refStack, ref)
vm.pc++
}
type _getValue struct{}
var getValue _getValue
func (_getValue) exec(vm *vm) {
ref := vm.refStack[len(vm.refStack)-1]
if v := ref.get(); v != nil {
vm.push(v)
} else {
vm.throw(vm.r.newReferenceError(ref.refname()))
return
}
vm.pc++
}
type _putValue struct{}
var putValue _putValue
func (_putValue) exec(vm *vm) {
l := len(vm.refStack) - 1
ref := vm.refStack[l]
vm.refStack[l] = nil
vm.refStack = vm.refStack[:l]
ref.set(vm.stack[vm.sp-1])
vm.pc++
}
type _putValueP struct{}
var putValueP _putValueP
func (_putValueP) exec(vm *vm) {
l := len(vm.refStack) - 1
ref := vm.refStack[l]
vm.refStack[l] = nil
vm.refStack = vm.refStack[:l]
ref.set(vm.stack[vm.sp-1])
vm.sp--
vm.pc++
}
type _initValueP struct{}
var initValueP _initValueP
func (_initValueP) exec(vm *vm) {
l := len(vm.refStack) - 1
ref := vm.refStack[l]
vm.refStack[l] = nil
vm.refStack = vm.refStack[:l]
ref.init(vm.stack[vm.sp-1])
vm.sp--
vm.pc++
}
type loadDynamic unistring.String
func (n loadDynamic) exec(vm *vm) {
name := unistring.String(n)
var val Value
for stash := vm.stash; stash != nil; stash = stash.outer {
if v, exists := stash.getByName(name); exists {
val = v
break
}
}
if val == nil {
val = vm.r.globalObject.self.getStr(name, nil)
if val == nil {
vm.throw(vm.r.newReferenceError(name))
return
}
}
vm.push(val)
vm.pc++
}
type loadDynamicRef unistring.String
func (n loadDynamicRef) exec(vm *vm) {
name := unistring.String(n)
var val Value
for stash := vm.stash; stash != nil; stash = stash.outer {
if v, exists := stash.getByName(name); exists {
val = v
break
}
}
if val == nil {
val = vm.r.globalObject.self.getStr(name, nil)
if val == nil {
val = valueUnresolved{r: vm.r, ref: name}
}
}
vm.push(val)
vm.pc++
}
type loadDynamicCallee unistring.String
func (n loadDynamicCallee) exec(vm *vm) {
name := unistring.String(n)
var val Value
var callee *Object
for stash := vm.stash; stash != nil; stash = stash.outer {
if v, exists := stash.getByName(name); exists {
callee = stash.obj
val = v
break
}
}
if val == nil {
val = vm.r.globalObject.self.getStr(name, nil)
if val == nil {
val = valueUnresolved{r: vm.r, ref: name}
}
}
if callee != nil {
vm.push(callee)
} else {
vm.push(_undefined)
}
vm.push(val)
vm.pc++
}
type _pop struct{}
var pop _pop
func (_pop) exec(vm *vm) {
vm.sp--
vm.pc++
}
func (vm *vm) callEval(n int, strict bool) {
if vm.r.toObject(vm.stack[vm.sp-n-1]) == vm.r.global.Eval {
if n > 0 {
srcVal := vm.stack[vm.sp-n]
if src, ok := srcVal.(String); ok {
ret := vm.r.eval(src, true, strict)
vm.stack[vm.sp-n-2] = ret
} else {
vm.stack[vm.sp-n-2] = srcVal
}
} else {
vm.stack[vm.sp-n-2] = _undefined
}
vm.sp -= n + 1
vm.pc++
} else {
call(n).exec(vm)
}
}
type callEval uint32
func (numargs callEval) exec(vm *vm) {
vm.callEval(int(numargs), false)
}
type callEvalStrict uint32
func (numargs callEvalStrict) exec(vm *vm) {
vm.callEval(int(numargs), true)
}
type _callEvalVariadic struct{}
var callEvalVariadic _callEvalVariadic
func (_callEvalVariadic) exec(vm *vm) {
vm.callEval(vm.countVariadicArgs()-2, false)
}
type _callEvalVariadicStrict struct{}
var callEvalVariadicStrict _callEvalVariadicStrict
func (_callEvalVariadicStrict) exec(vm *vm) {
vm.callEval(vm.countVariadicArgs()-2, true)
}
type _boxThis struct{}
var boxThis _boxThis
func (_boxThis) exec(vm *vm) {
v := vm.stack[vm.sb]
if v == _undefined || v == _null {
vm.stack[vm.sb] = vm.r.globalObject
} else {
vm.stack[vm.sb] = v.ToObject(vm.r)
}
vm.pc++
}
var variadicMarker Value = newSymbol(asciiString("[variadic marker]"))
type _startVariadic struct{}
var startVariadic _startVariadic
func (_startVariadic) exec(vm *vm) {
vm.push(variadicMarker)
vm.pc++
}
type _callVariadic struct{}
var callVariadic _callVariadic
func (vm *vm) countVariadicArgs() int {
count := 0
for i := vm.sp - 1; i >= 0; i-- {
if vm.stack[i] == variadicMarker {
return count
}
count++
}
panic("Variadic marker was not found. Compiler bug.")
}
func (_callVariadic) exec(vm *vm) {
call(vm.countVariadicArgs() - 2).exec(vm)
}
type _endVariadic struct{}
var endVariadic _endVariadic
func (_endVariadic) exec(vm *vm) {
vm.sp--
vm.stack[vm.sp-1] = vm.stack[vm.sp]
vm.pc++
}
type call uint32
func (numargs call) exec(vm *vm) {
// this
// callee
// arg0
// ...
// arg<numargs-1>
n := int(numargs)
v := vm.stack[vm.sp-n-1] // callee
obj := vm.toCallee(v)
obj.self.vmCall(vm, n)
}
func (vm *vm) clearStack() {
sp := vm.sp
stackTail := vm.stack[sp:]
for i := range stackTail {
stackTail[i] = nil
}
vm.stack = vm.stack[:sp]
}
type enterBlock struct {
names map[unistring.String]uint32
stashSize uint32
stackSize uint32
}
func (e *enterBlock) exec(vm *vm) {
if e.stashSize > 0 {
vm.newStash()
vm.stash.values = make([]Value, e.stashSize)
if len(e.names) > 0 {
vm.stash.names = e.names
}
}
ss := int(e.stackSize)
vm.stack.expand(vm.sp + ss - 1)
vv := vm.stack[vm.sp : vm.sp+ss]
for i := range vv {
vv[i] = nil
}
vm.sp += ss
vm.pc++
}
type enterCatchBlock struct {
names map[unistring.String]uint32
stashSize uint32
stackSize uint32
}
func (e *enterCatchBlock) exec(vm *vm) {
vm.newStash()
vm.stash.values = make([]Value, e.stashSize)
if len(e.names) > 0 {
vm.stash.names = e.names
}
vm.sp--
vm.stash.values[0] = vm.stack[vm.sp]
ss := int(e.stackSize)
vm.stack.expand(vm.sp + ss - 1)
vv := vm.stack[vm.sp : vm.sp+ss]
for i := range vv {
vv[i] = nil
}
vm.sp += ss
vm.pc++
}
type leaveBlock struct {
stackSize uint32
popStash bool
}
func (l *leaveBlock) exec(vm *vm) {
if l.popStash {
vm.stash = vm.stash.outer
}
if ss := l.stackSize; ss > 0 {
vm.sp -= int(ss)
}
vm.pc++
}
type enterFunc struct {
names map[unistring.String]uint32
stashSize uint32
stackSize uint32
numArgs uint32
funcType funcType
argsToStash bool
extensible bool
}
func (e *enterFunc) exec(vm *vm) {
// Input stack:
//
// callee
// this
// arg0
// ...
// argN
// <- sp
// Output stack:
//
// this <- sb
// <local stack vars...>
// <- sp
sp := vm.sp
vm.sb = sp - vm.args - 1
vm.newStash()
stash := vm.stash
stash.funcType = e.funcType
stash.values = make([]Value, e.stashSize)
if len(e.names) > 0 {
if e.extensible {
m := make(map[unistring.String]uint32, len(e.names))
for name, idx := range e.names {
m[name] = idx
}
stash.names = m
} else {
stash.names = e.names
}
}
ss := int(e.stackSize)
ea := 0
if e.argsToStash {
offset := vm.args - int(e.numArgs)
copy(stash.values, vm.stack[sp-vm.args:sp])
if offset > 0 {
vm.stash.extraArgs = make([]Value, offset)
copy(stash.extraArgs, vm.stack[sp-offset:])
} else {
vv := stash.values[vm.args:e.numArgs]
for i := range vv {
vv[i] = _undefined
}
}
sp -= vm.args
} else {
d := int(e.numArgs) - vm.args
if d > 0 {
ss += d
ea = d
vm.args = int(e.numArgs)
}
}
vm.stack.expand(sp + ss - 1)
if ea > 0 {
vv := vm.stack[sp : vm.sp+ea]
for i := range vv {
vv[i] = _undefined
}
}
vv := vm.stack[sp+ea : sp+ss]
for i := range vv {
vv[i] = nil
}
vm.sp = sp + ss
vm.pc++
}
// Similar to enterFunc, but for when arguments may be accessed before they are initialised,
// e.g. by an eval() code or from a closure, or from an earlier initialiser code.
// In this case the arguments remain on stack, first argsToCopy of them are copied to the stash.
type enterFunc1 struct {
names map[unistring.String]uint32
stashSize uint32
numArgs uint32
argsToCopy uint32
funcType funcType
extensible bool
}
func (e *enterFunc1) exec(vm *vm) {
sp := vm.sp
vm.sb = sp - vm.args - 1
vm.newStash()
stash := vm.stash
stash.funcType = e.funcType
stash.values = make([]Value, e.stashSize)
if len(e.names) > 0 {
if e.extensible {
m := make(map[unistring.String]uint32, len(e.names))
for name, idx := range e.names {
m[name] = idx
}
stash.names = m
} else {
stash.names = e.names
}
}
offset := vm.args - int(e.argsToCopy)
if offset > 0 {
copy(stash.values, vm.stack[sp-vm.args:sp-offset])
if offset := vm.args - int(e.numArgs); offset > 0 {
vm.stash.extraArgs = make([]Value, offset)
copy(stash.extraArgs, vm.stack[sp-offset:])
}
} else {
copy(stash.values, vm.stack[sp-vm.args:sp])
if int(e.argsToCopy) > vm.args {
vv := stash.values[vm.args:e.argsToCopy]
for i := range vv {
vv[i] = _undefined
}
}
}
vm.pc++
}
// Finalises the initialisers section and starts the function body which has its own
// scope. When used in conjunction with enterFunc1 adjustStack is set to true which
// causes the arguments to be removed from the stack.
type enterFuncBody struct {
enterBlock
funcType funcType
extensible bool
adjustStack bool
}
func (e *enterFuncBody) exec(vm *vm) {
if e.stashSize > 0 || e.extensible {
vm.newStash()
stash := vm.stash
stash.funcType = e.funcType
stash.values = make([]Value, e.stashSize)
if len(e.names) > 0 {
if e.extensible {
m := make(map[unistring.String]uint32, len(e.names))
for name, idx := range e.names {
m[name] = idx
}
stash.names = m
} else {
stash.names = e.names
}
}
}
sp := vm.sp
if e.adjustStack {
sp -= vm.args
}
nsp := sp + int(e.stackSize)
if e.stackSize > 0 {
vm.stack.expand(nsp - 1)
vv := vm.stack[sp:nsp]
for i := range vv {
vv[i] = nil
}
}
vm.sp = nsp
vm.pc++
}
type _ret struct{}
var ret _ret
func (_ret) exec(vm *vm) {
// callee -3
// this -2 <- sb
// retval -1
vm.stack[vm.sb-1] = vm.stack[vm.sp-1]
vm.sp = vm.sb
vm.popCtx()
vm.pc++
}
type cret uint32
func (c cret) exec(vm *vm) {
vm.stack[vm.sb] = *vm.getStashPtr(uint32(c))
ret.exec(vm)
}
type enterFuncStashless struct {
stackSize uint32
args uint32
}
func (e *enterFuncStashless) exec(vm *vm) {
sp := vm.sp
vm.sb = sp - vm.args - 1
d := int(e.args) - vm.args
if d > 0 {
ss := sp + int(e.stackSize) + d
vm.stack.expand(ss)
vv := vm.stack[sp : sp+d]
for i := range vv {
vv[i] = _undefined
}
vv = vm.stack[sp+d : ss]
for i := range vv {
vv[i] = nil
}
vm.args = int(e.args)
vm.sp = ss
} else {
if e.stackSize > 0 {
ss := sp + int(e.stackSize)
vm.stack.expand(ss)
vv := vm.stack[sp:ss]
for i := range vv {
vv[i] = nil
}
vm.sp = ss
}
}
vm.pc++
}
type newFuncInstruction interface {
getPrg() *Program
}
type newFunc struct {
prg *Program
name unistring.String
source string
length int
strict bool
}
func (n *newFunc) exec(vm *vm) {
obj := vm.r.newFunc(n.name, n.length, n.strict)
obj.prg = n.prg
obj.stash = vm.stash
obj.privEnv = vm.privEnv
obj.src = n.source
vm.push(obj.val)
vm.pc++
}
func (n *newFunc) getPrg() *Program {
return n.prg
}
type newAsyncFunc struct {
newFunc
}
func (n *newAsyncFunc) exec(vm *vm) {
obj := vm.r.newAsyncFunc(n.name, n.length, n.strict)
obj.prg = n.prg
obj.stash = vm.stash
obj.privEnv = vm.privEnv
obj.src = n.source
vm.push(obj.val)
vm.pc++
}
type newGeneratorFunc struct {
newFunc
}
func (n *newGeneratorFunc) exec(vm *vm) {
obj := vm.r.newGeneratorFunc(n.name, n.length, n.strict)
obj.prg = n.prg
obj.stash = vm.stash
obj.privEnv = vm.privEnv
obj.src = n.source
vm.push(obj.val)
vm.pc++
}
type newMethod struct {
newFunc
homeObjOffset uint32
}
func (n *newMethod) _exec(vm *vm, obj *methodFuncObject) {
obj.prg = n.prg
obj.stash = vm.stash
obj.privEnv = vm.privEnv
obj.src = n.source
if n.homeObjOffset > 0 {
obj.homeObject = vm.r.toObject(vm.stack[vm.sp-int(n.homeObjOffset)])
}
vm.push(obj.val)
vm.pc++
}
func (n *newMethod) exec(vm *vm) {
n._exec(vm, vm.r.newMethod(n.name, n.length, n.strict))
}
type newAsyncMethod struct {
newMethod
}
func (n *newAsyncMethod) exec(vm *vm) {
obj := vm.r.newAsyncMethod(n.name, n.length, n.strict)
n._exec(vm, &obj.methodFuncObject)
}
type newGeneratorMethod struct {
newMethod
}
func (n *newGeneratorMethod) exec(vm *vm) {
obj := vm.r.newGeneratorMethod(n.name, n.length, n.strict)
n._exec(vm, &obj.methodFuncObject)
}
type newArrowFunc struct {
newFunc
}
type newAsyncArrowFunc struct {
newArrowFunc
}
func getFuncObject(v Value) *Object {
if o, ok := v.(*Object); ok {
if fn, ok := o.self.(*arrowFuncObject); ok {
return fn.funcObj
}
return o
}
if v == _undefined {
return nil
}
panic(typeError("Value is not an Object"))
}
func getHomeObject(v Value) *Object {
if o, ok := v.(*Object); ok {
switch fn := o.self.(type) {
case *methodFuncObject:
return fn.homeObject
case *generatorMethodFuncObject:
return fn.homeObject
case *asyncMethodFuncObject:
return fn.homeObject
case *classFuncObject:
return o.runtime.toObject(fn.getStr("prototype", nil))
case *arrowFuncObject:
return getHomeObject(fn.funcObj)
case *asyncArrowFuncObject:
return getHomeObject(fn.funcObj)
}
}
panic(newTypeError("Compiler bug: getHomeObject() on the wrong value: %T", v))
}
func (n *newArrowFunc) _exec(vm *vm, obj *arrowFuncObject) {
obj.prg = n.prg
obj.stash = vm.stash
obj.privEnv = vm.privEnv
obj.src = n.source
if vm.sb > 0 {
obj.funcObj = getFuncObject(vm.stack[vm.sb-1])
}
vm.push(obj.val)
vm.pc++
}
func (n *newArrowFunc) exec(vm *vm) {
n._exec(vm, vm.r.newArrowFunc(n.name, n.length, n.strict))
}
func (n *newAsyncArrowFunc) exec(vm *vm) {
obj := vm.r.newAsyncArrowFunc(n.name, n.length, n.strict)
n._exec(vm, &obj.arrowFuncObject)
}
func (vm *vm) alreadyDeclared(name unistring.String) Value {
return vm.r.newError(vm.r.getSyntaxError(), "Identifier '%s' has already been declared", name)
}
func (vm *vm) checkBindVarsGlobal(names []unistring.String) {
o := vm.r.globalObject.self
sn := vm.r.global.stash.names
if bo, ok := o.(*baseObject); ok {
// shortcut
if bo.extensible {
for _, name := range names {
if _, exists := sn[name]; exists {
panic(vm.alreadyDeclared(name))
}
}
} else {
for _, name := range names {
if !bo.hasOwnPropertyStr(name) {
panic(vm.r.NewTypeError("Cannot define global variable '%s', global object is not extensible", name))
}
if _, exists := sn[name]; exists {
panic(vm.alreadyDeclared(name))
}
}
}
} else {
for _, name := range names {
if !o.hasOwnPropertyStr(name) && !o.isExtensible() {
panic(vm.r.NewTypeError("Cannot define global variable '%s', global object is not extensible", name))
}
if _, exists := sn[name]; exists {
panic(vm.alreadyDeclared(name))
}
}
}
}
func (vm *vm) createGlobalVarBindings(names []unistring.String, d bool) {
globalVarNames := vm.r.global.varNames
if globalVarNames == nil {
globalVarNames = make(map[unistring.String]struct{})
vm.r.global.varNames = globalVarNames
}
o := vm.r.globalObject.self
if bo, ok := o.(*baseObject); ok {
for _, name := range names {
if !bo.hasOwnPropertyStr(name) && bo.extensible {
bo._putProp(name, _undefined, true, true, d)
}
globalVarNames[name] = struct{}{}
}
} else {
var cf Flag
if d {
cf = FLAG_TRUE
} else {
cf = FLAG_FALSE
}
for _, name := range names {
if !o.hasOwnPropertyStr(name) && o.isExtensible() {
o.defineOwnPropertyStr(name, PropertyDescriptor{
Value: _undefined,
Writable: FLAG_TRUE,
Enumerable: FLAG_TRUE,
Configurable: cf,
}, true)
o.setOwnStr(name, _undefined, false)
}
globalVarNames[name] = struct{}{}
}
}
}
func (vm *vm) createGlobalFuncBindings(names []unistring.String, d bool) {
globalVarNames := vm.r.global.varNames
if globalVarNames == nil {
globalVarNames = make(map[unistring.String]struct{})
vm.r.global.varNames = globalVarNames
}
o := vm.r.globalObject.self
b := vm.sp - len(names)
var shortcutObj *baseObject
if o, ok := o.(*baseObject); ok {
shortcutObj = o
}
for i, name := range names {
var desc PropertyDescriptor
prop := o.getOwnPropStr(name)
desc.Value = vm.stack[b+i]
if shortcutObj != nil && prop == nil && shortcutObj.extensible {
shortcutObj._putProp(name, desc.Value, true, true, d)
} else {
if prop, ok := prop.(*valueProperty); ok && !prop.configurable {
// no-op
} else {
desc.Writable = FLAG_TRUE
desc.Enumerable = FLAG_TRUE
if d {
desc.Configurable = FLAG_TRUE
} else {
desc.Configurable = FLAG_FALSE
}
}
if shortcutObj != nil {
shortcutObj.defineOwnPropertyStr(name, desc, true)
} else {
o.defineOwnPropertyStr(name, desc, true)
o.setOwnStr(name, desc.Value, false) // not a bug, see https://262.ecma-international.org/#sec-createglobalfunctionbinding
}
}
globalVarNames[name] = struct{}{}
}
vm.sp = b
}
func (vm *vm) checkBindFuncsGlobal(names []unistring.String) {
o := vm.r.globalObject.self
sn := vm.r.global.stash.names
for _, name := range names {
if _, exists := sn[name]; exists {
panic(vm.alreadyDeclared(name))
}
prop := o.getOwnPropStr(name)
allowed := true
switch prop := prop.(type) {
case nil:
allowed = o.isExtensible()
case *valueProperty:
allowed = prop.configurable || prop.getterFunc == nil && prop.setterFunc == nil && prop.writable && prop.enumerable
}
if !allowed {
panic(vm.r.NewTypeError("Cannot redefine global function '%s'", name))
}
}
}
func (vm *vm) checkBindLexGlobal(names []unistring.String) {
o := vm.r.globalObject.self
s := &vm.r.global.stash
for _, name := range names {
if _, exists := vm.r.global.varNames[name]; exists {
goto fail
}
if _, exists := s.names[name]; exists {
goto fail
}
if prop, ok := o.getOwnPropStr(name).(*valueProperty); ok && !prop.configurable {
goto fail
}
continue
fail:
panic(vm.alreadyDeclared(name))
}
}
type bindVars struct {
names []unistring.String
deletable bool
}
func (d *bindVars) exec(vm *vm) {
var target *stash
for _, name := range d.names {
for s := vm.stash; s != nil; s = s.outer {
if idx, exists := s.names[name]; exists && idx&maskVar == 0 {
vm.throw(vm.alreadyDeclared(name))
return
}
if s.isVariable() {
target = s
break
}
}
}
if target == nil {
target = vm.stash
}
deletable := d.deletable
for _, name := range d.names {
target.createBinding(name, deletable)
}
vm.pc++
}
type bindGlobal struct {
vars, funcs, lets, consts []unistring.String
deletable bool
}
func (b *bindGlobal) exec(vm *vm) {
vm.checkBindFuncsGlobal(b.funcs)
vm.checkBindLexGlobal(b.lets)
vm.checkBindLexGlobal(b.consts)
vm.checkBindVarsGlobal(b.vars)
s := &vm.r.global.stash
for _, name := range b.lets {
s.createLexBinding(name, false)
}
for _, name := range b.consts {
s.createLexBinding(name, true)
}
vm.createGlobalFuncBindings(b.funcs, b.deletable)
vm.createGlobalVarBindings(b.vars, b.deletable)
vm.pc++
}
type jne int32
func (j jne) exec(vm *vm) {
vm.sp--
if !vm.stack[vm.sp].ToBoolean() {
vm.pc += int(j)
} else {
vm.pc++
}
}
type jeq int32
func (j jeq) exec(vm *vm) {
vm.sp--
if vm.stack[vm.sp].ToBoolean() {
vm.pc += int(j)
} else {
vm.pc++
}
}
type jeq1 int32
func (j jeq1) exec(vm *vm) {
if vm.stack[vm.sp-1].ToBoolean() {
vm.pc += int(j)
} else {
vm.sp--
vm.pc++
}
}
type jneq1 int32
func (j jneq1) exec(vm *vm) {
if !vm.stack[vm.sp-1].ToBoolean() {
vm.pc += int(j)
} else {
vm.sp--
vm.pc++
}
}
type jdef int32
func (j jdef) exec(vm *vm) {
if vm.stack[vm.sp-1] != _undefined {
vm.pc += int(j)
} else {
vm.sp--
vm.pc++
}
}
type jdefP int32
func (j jdefP) exec(vm *vm) {
if vm.stack[vm.sp-1] != _undefined {
vm.pc += int(j)
} else {
vm.pc++
}
vm.sp--
}
type jopt int32
func (j jopt) exec(vm *vm) {
switch vm.stack[vm.sp-1] {
case _null:
vm.stack[vm.sp-1] = _undefined
fallthrough
case _undefined:
vm.pc += int(j)
default:
vm.pc++
}
}
type joptc int32
func (j joptc) exec(vm *vm) {
switch vm.stack[vm.sp-1].(type) {
case valueNull, valueUndefined, memberUnresolved:
vm.sp--
vm.stack[vm.sp-1] = _undefined
vm.pc += int(j)
default:
vm.pc++
}
}
type jcoalesc int32
func (j jcoalesc) exec(vm *vm) {
switch vm.stack[vm.sp-1] {
case _undefined, _null:
vm.sp--
vm.pc++
default:
vm.pc += int(j)
}
}
type _not struct{}
var not _not
func (_not) exec(vm *vm) {
if vm.stack[vm.sp-1].ToBoolean() {
vm.stack[vm.sp-1] = valueFalse
} else {
vm.stack[vm.sp-1] = valueTrue
}
vm.pc++
}
func toPrimitiveNumber(v Value) Value {
if o, ok := v.(*Object); ok {
return o.toPrimitiveNumber()
}
return v
}
func toPrimitive(v Value) Value {
if o, ok := v.(*Object); ok {
return o.toPrimitive()
}
return v
}
func cmp(px, py Value) Value {
var ret bool
var nx, ny float64
if xs, ok := px.(String); ok {
if ys, ok := py.(String); ok {
ret = xs.CompareTo(ys) < 0
goto end
}
}
if xi, ok := px.(valueInt); ok {
if yi, ok := py.(valueInt); ok {
ret = xi < yi
goto end
}
}
nx = px.ToFloat()
ny = py.ToFloat()
if math.IsNaN(nx) || math.IsNaN(ny) {
return _undefined
}
ret = nx < ny
end:
if ret {
return valueTrue
}
return valueFalse
}
type _op_lt struct{}
var op_lt _op_lt
func (_op_lt) exec(vm *vm) {
left := toPrimitiveNumber(vm.stack[vm.sp-2])
right := toPrimitiveNumber(vm.stack[vm.sp-1])
r := cmp(left, right)
if r == _undefined {
vm.stack[vm.sp-2] = valueFalse
} else {
vm.stack[vm.sp-2] = r
}
vm.sp--
vm.pc++
}
type _op_lte struct{}
var op_lte _op_lte
func (_op_lte) exec(vm *vm) {
left := toPrimitiveNumber(vm.stack[vm.sp-2])
right := toPrimitiveNumber(vm.stack[vm.sp-1])
r := cmp(right, left)
if r == _undefined || r == valueTrue {
vm.stack[vm.sp-2] = valueFalse
} else {
vm.stack[vm.sp-2] = valueTrue
}
vm.sp--
vm.pc++
}
type _op_gt struct{}
var op_gt _op_gt
func (_op_gt) exec(vm *vm) {
left := toPrimitiveNumber(vm.stack[vm.sp-2])
right := toPrimitiveNumber(vm.stack[vm.sp-1])
r := cmp(right, left)
if r == _undefined {
vm.stack[vm.sp-2] = valueFalse
} else {
vm.stack[vm.sp-2] = r
}
vm.sp--
vm.pc++
}
type _op_gte struct{}
var op_gte _op_gte
func (_op_gte) exec(vm *vm) {
left := toPrimitiveNumber(vm.stack[vm.sp-2])
right := toPrimitiveNumber(vm.stack[vm.sp-1])
r := cmp(left, right)
if r == _undefined || r == valueTrue {
vm.stack[vm.sp-2] = valueFalse
} else {
vm.stack[vm.sp-2] = valueTrue
}
vm.sp--
vm.pc++
}
type _op_eq struct{}
var op_eq _op_eq
func (_op_eq) exec(vm *vm) {
if vm.stack[vm.sp-2].Equals(vm.stack[vm.sp-1]) {
vm.stack[vm.sp-2] = valueTrue
} else {
vm.stack[vm.sp-2] = valueFalse
}
vm.sp--
vm.pc++
}
type _op_neq struct{}
var op_neq _op_neq
func (_op_neq) exec(vm *vm) {
if vm.stack[vm.sp-2].Equals(vm.stack[vm.sp-1]) {
vm.stack[vm.sp-2] = valueFalse
} else {
vm.stack[vm.sp-2] = valueTrue
}
vm.sp--
vm.pc++
}
type _op_strict_eq struct{}
var op_strict_eq _op_strict_eq
func (_op_strict_eq) exec(vm *vm) {
if vm.stack[vm.sp-2].StrictEquals(vm.stack[vm.sp-1]) {
vm.stack[vm.sp-2] = valueTrue
} else {
vm.stack[vm.sp-2] = valueFalse
}
vm.sp--
vm.pc++
}
type _op_strict_neq struct{}
var op_strict_neq _op_strict_neq
func (_op_strict_neq) exec(vm *vm) {
if vm.stack[vm.sp-2].StrictEquals(vm.stack[vm.sp-1]) {
vm.stack[vm.sp-2] = valueFalse
} else {
vm.stack[vm.sp-2] = valueTrue
}
vm.sp--
vm.pc++
}
type _op_instanceof struct{}
var op_instanceof _op_instanceof
func (_op_instanceof) exec(vm *vm) {
left := vm.stack[vm.sp-2]
right := vm.r.toObject(vm.stack[vm.sp-1])
if instanceOfOperator(left, right) {
vm.stack[vm.sp-2] = valueTrue
} else {
vm.stack[vm.sp-2] = valueFalse
}
vm.sp--
vm.pc++
}
type _op_in struct{}
var op_in _op_in
func (_op_in) exec(vm *vm) {
left := vm.stack[vm.sp-2]
right := vm.r.toObject(vm.stack[vm.sp-1])
if right.hasProperty(left) {
vm.stack[vm.sp-2] = valueTrue
} else {
vm.stack[vm.sp-2] = valueFalse
}
vm.sp--
vm.pc++
}
type try struct {
catchOffset int32
finallyOffset int32
}
func (t try) exec(vm *vm) {
var catchPos, finallyPos int32
if t.catchOffset > 0 {
catchPos = int32(vm.pc) + t.catchOffset
} else {
catchPos = -1
}
if t.finallyOffset > 0 {
finallyPos = int32(vm.pc) + t.finallyOffset
} else {
finallyPos = -1
}
vm.pushTryFrame(catchPos, finallyPos)
vm.pc++
}
type leaveTry struct{}
func (leaveTry) exec(vm *vm) {
tf := &vm.tryStack[len(vm.tryStack)-1]
if tf.finallyPos >= 0 {
tf.finallyRet = int32(vm.pc + 1)
vm.pc = int(tf.finallyPos)
tf.finallyPos = -1
tf.catchPos = -1
} else {
vm.popTryFrame()
vm.pc++
}
}
type enterFinally struct{}
func (enterFinally) exec(vm *vm) {
tf := &vm.tryStack[len(vm.tryStack)-1]
tf.finallyPos = -1
vm.pc++
}
type leaveFinally struct{}
func (leaveFinally) exec(vm *vm) {
tf := &vm.tryStack[len(vm.tryStack)-1]
ex, ret := tf.exception, tf.finallyRet
tf.exception = nil
vm.popTryFrame()
if ex != nil {
vm.throw(ex)
return
} else {
if ret != -1 {
vm.pc = int(ret)
} else {
vm.pc++
}
}
}
type _throw struct{}
var throw _throw
func (_throw) exec(vm *vm) {
v := vm.stack[vm.sp-1]
ex := &Exception{
val: v,
}
if o, ok := v.(*Object); ok {
if e, ok := o.self.(*errorObject); ok {
if len(e.stack) > 0 {
ex.stack = e.stack
}
}
}
if ex.stack == nil {
ex.stack = vm.captureStack(make([]StackFrame, 0, len(vm.callStack)+1), 0)
}
if ex = vm.handleThrow(ex); ex != nil {
panic(ex)
}
}
type _newVariadic struct{}
var newVariadic _newVariadic
func (_newVariadic) exec(vm *vm) {
_new(vm.countVariadicArgs() - 1).exec(vm)
}
type _new uint32
func (n _new) exec(vm *vm) {
sp := vm.sp - int(n)
obj := vm.stack[sp-1]
ctor := vm.r.toConstructor(obj)
vm.stack[sp-1] = ctor(vm.stack[sp:vm.sp], nil)
vm.sp = sp
vm.pc++
}
type superCall uint32
func (s superCall) exec(vm *vm) {
l := len(vm.refStack) - 1
thisRef := vm.refStack[l]
vm.refStack[l] = nil
vm.refStack = vm.refStack[:l]
obj := vm.r.toObject(vm.stack[vm.sb-1])
var cls *classFuncObject
switch fn := obj.self.(type) {
case *classFuncObject:
cls = fn
case *arrowFuncObject:
cls, _ = fn.funcObj.self.(*classFuncObject)
}
if cls == nil {
vm.throw(vm.r.NewTypeError("wrong callee type for super()"))
return
}
sp := vm.sp - int(s)
newTarget := vm.r.toObject(vm.newTarget)
v := cls.createInstance(vm.stack[sp:vm.sp], newTarget)
thisRef.set(v)
vm.sp = sp
cls._initFields(v)
vm.push(v)
vm.pc++
}
type _superCallVariadic struct{}
var superCallVariadic _superCallVariadic
func (_superCallVariadic) exec(vm *vm) {
superCall(vm.countVariadicArgs()).exec(vm)
}
type _loadNewTarget struct{}
var loadNewTarget _loadNewTarget
func (_loadNewTarget) exec(vm *vm) {
if t := vm.newTarget; t != nil {
vm.push(t)
} else {
vm.push(_undefined)
}
vm.pc++
}
type _typeof struct{}
var typeof _typeof
func (_typeof) exec(vm *vm) {
var r Value
switch v := vm.stack[vm.sp-1].(type) {
case valueUndefined, valueUnresolved:
r = stringUndefined
case valueNull:
r = stringObjectC
case *Object:
r = v.self.typeOf()
case valueBool:
r = stringBoolean
case String:
r = stringString
case valueInt, valueFloat:
r = stringNumber
case *Symbol:
r = stringSymbol
default:
panic(newTypeError("Compiler bug: unknown type: %T", v))
}
vm.stack[vm.sp-1] = r
vm.pc++
}
type createArgsMapped uint32
func (formalArgs createArgsMapped) exec(vm *vm) {
v := &Object{runtime: vm.r}
args := &argumentsObject{}
args.extensible = true
args.prototype = vm.r.global.ObjectPrototype
args.class = "Arguments"
v.self = args
args.val = v
args.length = vm.args
args.init()
i := 0
c := int(formalArgs)
if vm.args < c {
c = vm.args
}
for ; i < c; i++ {
args._put(unistring.String(strconv.Itoa(i)), &mappedProperty{
valueProperty: valueProperty{
writable: true,
configurable: true,
enumerable: true,
},
v: &vm.stash.values[i],
})
}
for _, v := range vm.stash.extraArgs {
args._put(unistring.String(strconv.Itoa(i)), v)
i++
}
args._putProp("callee", vm.stack[vm.sb-1], true, false, true)
args._putSym(SymIterator, valueProp(vm.r.getArrayValues(), true, false, true))
vm.push(v)
vm.pc++
}
type createArgsUnmapped uint32
func (formalArgs createArgsUnmapped) exec(vm *vm) {
args := vm.r.newBaseObject(vm.r.global.ObjectPrototype, "Arguments")
i := 0
c := int(formalArgs)
if vm.args < c {
c = vm.args
}
for _, v := range vm.stash.values[:c] {
args._put(unistring.String(strconv.Itoa(i)), v)
i++
}
for _, v := range vm.stash.extraArgs {
args._put(unistring.String(strconv.Itoa(i)), v)
i++
}
args._putProp("length", intToValue(int64(vm.args)), true, false, true)
args._put("callee", vm.r.newThrowerProperty(false))
args._putSym(SymIterator, valueProp(vm.r.getArrayValues(), true, false, true))
vm.push(args.val)
vm.pc++
}
type _enterWith struct{}
var enterWith _enterWith
func (_enterWith) exec(vm *vm) {
vm.newStash()
vm.stash.obj = vm.stack[vm.sp-1].ToObject(vm.r)
vm.sp--
vm.pc++
}
type _leaveWith struct{}
var leaveWith _leaveWith
func (_leaveWith) exec(vm *vm) {
vm.stash = vm.stash.outer
vm.pc++
}
func emptyIter() (propIterItem, iterNextFunc) {
return propIterItem{}, nil
}
type _enumerate struct{}
var enumerate _enumerate
func (_enumerate) exec(vm *vm) {
v := vm.stack[vm.sp-1]
if v == _undefined || v == _null {
vm.iterStack = append(vm.iterStack, iterStackItem{f: emptyIter})
} else {
vm.iterStack = append(vm.iterStack, iterStackItem{f: enumerateRecursive(v.ToObject(vm.r))})
}
vm.sp--
vm.pc++
}
type enumNext int32
func (jmp enumNext) exec(vm *vm) {
l := len(vm.iterStack) - 1
item, n := vm.iterStack[l].f()
if n != nil {
vm.iterStack[l].val = item.name
vm.iterStack[l].f = n
vm.pc++
} else {
vm.pc += int(jmp)
}
}
type _enumGet struct{}
var enumGet _enumGet
func (_enumGet) exec(vm *vm) {
l := len(vm.iterStack) - 1
vm.push(vm.iterStack[l].val)
vm.pc++
}
type _enumPop struct{}
var enumPop _enumPop
func (_enumPop) exec(vm *vm) {
l := len(vm.iterStack) - 1
vm.iterStack[l] = iterStackItem{}
vm.iterStack = vm.iterStack[:l]
vm.pc++
}
type _enumPopClose struct{}
var enumPopClose _enumPopClose
func (_enumPopClose) exec(vm *vm) {
l := len(vm.iterStack) - 1
item := vm.iterStack[l]
vm.iterStack[l] = iterStackItem{}
vm.iterStack = vm.iterStack[:l]
if iter := item.iter; iter != nil {
iter.returnIter()
}
vm.pc++
}
type _iterateP struct{}
var iterateP _iterateP
func (_iterateP) exec(vm *vm) {
iter := vm.r.getIterator(vm.stack[vm.sp-1], nil)
vm.iterStack = append(vm.iterStack, iterStackItem{iter: iter})
vm.sp--
vm.pc++
}
type _iterate struct{}
var iterate _iterate
func (_iterate) exec(vm *vm) {
iter := vm.r.getIterator(vm.stack[vm.sp-1], nil)
vm.iterStack = append(vm.iterStack, iterStackItem{iter: iter})
vm.pc++
}
type iterNext int32
func (jmp iterNext) exec(vm *vm) {
l := len(vm.iterStack) - 1
iter := vm.iterStack[l].iter
value, ex := iter.step()
if ex == nil {
if value == nil {
vm.pc += int(jmp)
} else {
vm.iterStack[l].val = value
vm.pc++
}
} else {
l := len(vm.iterStack) - 1
vm.iterStack[l] = iterStackItem{}
vm.iterStack = vm.iterStack[:l]
vm.throw(ex.val)
return
}
}
type iterGetNextOrUndef struct{}
func (iterGetNextOrUndef) exec(vm *vm) {
l := len(vm.iterStack) - 1
iter := vm.iterStack[l].iter
var value Value
if iter.iterator != nil {
var ex *Exception
value, ex = iter.step()
if ex != nil {
l := len(vm.iterStack) - 1
vm.iterStack[l] = iterStackItem{}
vm.iterStack = vm.iterStack[:l]
vm.throw(ex.val)
return
}
}
vm.push(nilSafe(value))
vm.pc++
}
type copyStash struct{}
func (copyStash) exec(vm *vm) {
oldStash := vm.stash
newStash := &stash{
outer: oldStash.outer,
}
vm.stashAllocs++
newStash.values = append([]Value(nil), oldStash.values...)
newStash.names = oldStash.names
vm.stash = newStash
vm.pc++
}
type _throwAssignToConst struct{}
var throwAssignToConst _throwAssignToConst
func (_throwAssignToConst) exec(vm *vm) {
vm.throw(errAssignToConst)
}
func (r *Runtime) copyDataProperties(target, source Value) {
targetObj := r.toObject(target)
if source == _null || source == _undefined {
return
}
sourceObj := source.ToObject(r)
for item, next := iterateEnumerableProperties(sourceObj)(); next != nil; item, next = next() {
createDataPropertyOrThrow(targetObj, item.name, item.value)
}
}
type _copySpread struct{}
var copySpread _copySpread
func (_copySpread) exec(vm *vm) {
vm.r.copyDataProperties(vm.stack[vm.sp-2], vm.stack[vm.sp-1])
vm.sp--
vm.pc++
}
type _copyRest struct{}
var copyRest _copyRest
func (_copyRest) exec(vm *vm) {
vm.push(vm.r.NewObject())
vm.r.copyDataProperties(vm.stack[vm.sp-1], vm.stack[vm.sp-2])
vm.pc++
}
type _createDestructSrc struct{}
var createDestructSrc _createDestructSrc
func (_createDestructSrc) exec(vm *vm) {
v := vm.stack[vm.sp-1]
vm.r.checkObjectCoercible(v)
vm.push(vm.r.newDestructKeyedSource(v))
vm.pc++
}
type _checkObjectCoercible struct{}
var checkObjectCoercible _checkObjectCoercible
func (_checkObjectCoercible) exec(vm *vm) {
vm.r.checkObjectCoercible(vm.stack[vm.sp-1])
vm.pc++
}
type createArgsRestStack int
func (n createArgsRestStack) exec(vm *vm) {
var values []Value
delta := vm.args - int(n)
if delta > 0 {
values = make([]Value, delta)
copy(values, vm.stack[vm.sb+int(n)+1:])
}
vm.push(vm.r.newArrayValues(values))
vm.pc++
}
type _createArgsRestStash struct{}
var createArgsRestStash _createArgsRestStash
func (_createArgsRestStash) exec(vm *vm) {
vm.push(vm.r.newArrayValues(vm.stash.extraArgs))
vm.stash.extraArgs = nil
vm.pc++
}
type concatStrings int
func (n concatStrings) exec(vm *vm) {
strs := vm.stack[vm.sp-int(n) : vm.sp]
length := 0
allAscii := true
for i, s := range strs {
switch s := s.(type) {
case asciiString:
length += s.Length()
case unicodeString:
length += s.Length()
allAscii = false
case *importedString:
s.ensureScanned()
if s.u != nil {
strs[i] = s.u
length += s.u.Length()
allAscii = false
} else {
strs[i] = asciiString(s.s)
length += len(s.s)
}
default:
panic(unknownStringTypeErr(s))
}
}
vm.sp -= int(n) - 1
if allAscii {
var buf strings.Builder
buf.Grow(length)
for _, s := range strs {
buf.WriteString(string(s.(asciiString)))
}
vm.stack[vm.sp-1] = asciiString(buf.String())
} else {
var buf unicodeStringBuilder
buf.ensureStarted(length)
for _, s := range strs {
buf.writeString(s.(String))
}
vm.stack[vm.sp-1] = buf.String()
}
vm.pc++
}
type getTaggedTmplObject struct {
raw, cooked []Value
}
// As tagged template objects are not cached (because it's hard to ensure the cache is cleaned without using
// finalizers) this wrapper is needed to override the equality method so that two objects for the same template
// literal appeared to be equal from the code's point of view.
type taggedTemplateArray struct {
*arrayObject
idPtr *[]Value
}
func (a *taggedTemplateArray) equal(other objectImpl) bool {
if o, ok := other.(*taggedTemplateArray); ok {
return a.idPtr == o.idPtr
}
return false
}
func (c *getTaggedTmplObject) exec(vm *vm) {
cooked := vm.r.newArrayObject()
setArrayValues(cooked, c.cooked)
raw := vm.r.newArrayObject()
setArrayValues(raw, c.raw)
cooked.propValueCount = len(c.cooked)
cooked.lengthProp.writable = false
raw.propValueCount = len(c.raw)
raw.lengthProp.writable = false
raw.preventExtensions(true)
raw.val.self = &taggedTemplateArray{
arrayObject: raw,
idPtr: &c.raw,
}
cooked._putProp("raw", raw.val, false, false, false)
cooked.preventExtensions(true)
cooked.val.self = &taggedTemplateArray{
arrayObject: cooked,
idPtr: &c.cooked,
}
vm.push(cooked.val)
vm.pc++
}
type _loadSuper struct{}
var loadSuper _loadSuper
func (_loadSuper) exec(vm *vm) {
homeObject := getHomeObject(vm.stack[vm.sb-1])
if proto := homeObject.Prototype(); proto != nil {
vm.push(proto)
} else {
vm.push(_undefined)
}
vm.pc++
}
type newClass struct {
ctor *Program
name unistring.String
source string
initFields *Program
privateFields, privateMethods []unistring.String // only set when dynamic resolution is needed
numPrivateFields, numPrivateMethods uint32
length int
hasPrivateEnv bool
}
type newDerivedClass struct {
newClass
}
func (vm *vm) createPrivateType(f *classFuncObject, numFields, numMethods uint32) {
typ := &privateEnvType{}
typ.numFields = numFields
typ.numMethods = numMethods
f.privateEnvType = typ
f.privateMethods = make([]Value, numMethods)
}
func (vm *vm) fillPrivateNamesMap(typ *privateEnvType, privateFields, privateMethods []unistring.String) {
if len(privateFields) > 0 || len(privateMethods) > 0 {
penv := vm.privEnv.names
if penv == nil {
penv = make(privateNames)
vm.privEnv.names = penv
}
for idx, field := range privateFields {
penv[field] = &privateId{
typ: typ,
idx: uint32(idx),
}
}
for idx, method := range privateMethods {
penv[method] = &privateId{
typ: typ,
idx: uint32(idx),
isMethod: true,
}
}
}
}
func (c *newClass) create(protoParent, ctorParent *Object, vm *vm, derived bool) (prototype, cls *Object) {
proto := vm.r.newBaseObject(protoParent, classObject)
f := vm.r.newClassFunc(c.name, c.length, ctorParent, derived)
f._putProp("prototype", proto.val, false, false, false)
proto._putProp("constructor", f.val, true, false, true)
f.prg = c.ctor
f.stash = vm.stash
f.src = c.source
f.initFields = c.initFields
if c.hasPrivateEnv {
vm.privEnv = &privateEnv{
outer: vm.privEnv,
}
vm.createPrivateType(f, c.numPrivateFields, c.numPrivateMethods)
vm.fillPrivateNamesMap(f.privateEnvType, c.privateFields, c.privateMethods)
vm.privEnv.instanceType = f.privateEnvType
}
f.privEnv = vm.privEnv
return proto.val, f.val
}
func (c *newClass) exec(vm *vm) {
proto, cls := c.create(vm.r.global.ObjectPrototype, vm.r.getFunctionPrototype(), vm, false)
sp := vm.sp
vm.stack.expand(sp + 1)
vm.stack[sp] = proto
vm.stack[sp+1] = cls
vm.sp = sp + 2
vm.pc++
}
func (c *newDerivedClass) exec(vm *vm) {
var protoParent *Object
var superClass *Object
if o := vm.stack[vm.sp-1]; o != _null {
if sc, ok := o.(*Object); !ok || sc.self.assertConstructor() == nil {
vm.throw(vm.r.NewTypeError("Class extends value is not a constructor or null"))
return
} else {
v := sc.self.getStr("prototype", nil)
if v != _null {
if o, ok := v.(*Object); ok {
protoParent = o
} else {
vm.throw(vm.r.NewTypeError("Class extends value does not have valid prototype property"))
return
}
}
superClass = sc
}
} else {
superClass = vm.r.getFunctionPrototype()
}
proto, cls := c.create(protoParent, superClass, vm, true)
vm.stack[vm.sp-1] = proto
vm.push(cls)
vm.pc++
}
// Creates a special instance of *classFuncObject which is only used during evaluation of a class declaration
// to initialise static fields and instance private methods of another class.
type newStaticFieldInit struct {
initFields *Program
numPrivateFields, numPrivateMethods uint32
}
func (c *newStaticFieldInit) exec(vm *vm) {
f := vm.r.newClassFunc("", 0, vm.r.getFunctionPrototype(), false)
if c.numPrivateFields > 0 || c.numPrivateMethods > 0 {
vm.createPrivateType(f, c.numPrivateFields, c.numPrivateMethods)
}
f.initFields = c.initFields
f.stash = vm.stash
vm.push(f.val)
vm.pc++
}
func (vm *vm) loadThis(v Value) {
if v != nil {
vm.push(v)
} else {
vm.throw(vm.r.newError(vm.r.getReferenceError(), "Must call super constructor in derived class before accessing 'this'"))
return
}
vm.pc++
}
type loadThisStash uint32
func (l loadThisStash) exec(vm *vm) {
vm.loadThis(*vm.getStashPtr(uint32(l)))
}
type loadThisStack struct{}
func (loadThisStack) exec(vm *vm) {
vm.loadThis(vm.stack[vm.sb])
}
func (vm *vm) getStashPtr(s uint32) *Value {
level := int(s) >> 24
idx := s & 0x00FFFFFF
stash := vm.stash
for i := 0; i < level; i++ {
stash = stash.outer
}
return &stash.values[idx]
}
type getThisDynamic struct{}
func (getThisDynamic) exec(vm *vm) {
for stash := vm.stash; stash != nil; stash = stash.outer {
if stash.obj == nil {
if v, exists := stash.getByName(thisBindingName); exists {
vm.push(v)
vm.pc++
return
}
}
}
vm.push(vm.r.globalObject)
vm.pc++
}
type throwConst struct {
v interface{}
}
func (t throwConst) exec(vm *vm) {
vm.throw(t.v)
}
type resolveThisStack struct{}
func (r resolveThisStack) exec(vm *vm) {
vm.refStack = append(vm.refStack, &thisRef{v: (*[]Value)(&vm.stack), idx: vm.sb})
vm.pc++
}
type resolveThisStash uint32
func (r resolveThisStash) exec(vm *vm) {
level := int(r) >> 24
idx := r & 0x00FFFFFF
stash := vm.stash
for i := 0; i < level; i++ {
stash = stash.outer
}
vm.refStack = append(vm.refStack, &thisRef{v: &stash.values, idx: int(idx)})
vm.pc++
}
type resolveThisDynamic struct{}
func (resolveThisDynamic) exec(vm *vm) {
for stash := vm.stash; stash != nil; stash = stash.outer {
if stash.obj == nil {
if idx, exists := stash.names[thisBindingName]; exists {
vm.refStack = append(vm.refStack, &thisRef{v: &stash.values, idx: int(idx &^ maskTyp)})
vm.pc++
return
}
}
}
panic(vm.r.newError(vm.r.getReferenceError(), "Compiler bug: 'this' reference is not found in resolveThisDynamic"))
}
type defineComputedKey int
func (offset defineComputedKey) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-int(offset)])
if h, ok := obj.self.(*classFuncObject); ok {
key := toPropertyKey(vm.stack[vm.sp-1])
h.computedKeys = append(h.computedKeys, key)
vm.sp--
vm.pc++
return
}
panic(vm.r.NewTypeError("Compiler bug: unexpected target for defineComputedKey: %v", obj))
}
type loadComputedKey int
func (idx loadComputedKey) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sb-1])
if h, ok := obj.self.(*classFuncObject); ok {
vm.push(h.computedKeys[idx])
vm.pc++
return
}
panic(vm.r.NewTypeError("Compiler bug: unexpected target for loadComputedKey: %v", obj))
}
type initStaticElements struct {
privateFields, privateMethods []unistring.String
}
func (i *initStaticElements) exec(vm *vm) {
cls := vm.stack[vm.sp-1]
staticInit := vm.r.toObject(vm.stack[vm.sp-3])
vm.sp -= 2
if h, ok := staticInit.self.(*classFuncObject); ok {
h._putProp("prototype", cls, true, true, true) // so that 'super' resolution work
h.privEnv = vm.privEnv
if h.privateEnvType != nil {
vm.privEnv.staticType = h.privateEnvType
vm.fillPrivateNamesMap(h.privateEnvType, i.privateFields, i.privateMethods)
}
h._initFields(vm.r.toObject(cls))
vm.stack[vm.sp-1] = cls
vm.pc++
return
}
panic(vm.r.NewTypeError("Compiler bug: unexpected target for initStaticElements: %v", staticInit))
}
type definePrivateMethod struct {
idx int
targetOffset int
}
func (d *definePrivateMethod) getPrivateMethods(vm *vm) []Value {
obj := vm.r.toObject(vm.stack[vm.sp-d.targetOffset])
if cls, ok := obj.self.(*classFuncObject); ok {
return cls.privateMethods
} else {
panic(vm.r.NewTypeError("Compiler bug: wrong target type for definePrivateMethod: %T", obj.self))
}
}
func (d *definePrivateMethod) exec(vm *vm) {
methods := d.getPrivateMethods(vm)
methods[d.idx] = vm.stack[vm.sp-1]
vm.sp--
vm.pc++
}
type definePrivateGetter struct {
definePrivateMethod
}
func (d *definePrivateGetter) exec(vm *vm) {
methods := d.getPrivateMethods(vm)
val := vm.stack[vm.sp-1]
method := vm.r.toObject(val)
p, _ := methods[d.idx].(*valueProperty)
if p == nil {
p = &valueProperty{
accessor: true,
}
methods[d.idx] = p
}
if p.getterFunc != nil {
vm.throw(vm.r.NewTypeError("Private getter has already been declared"))
return
}
p.getterFunc = method
vm.sp--
vm.pc++
}
type definePrivateSetter struct {
definePrivateMethod
}
func (d *definePrivateSetter) exec(vm *vm) {
methods := d.getPrivateMethods(vm)
val := vm.stack[vm.sp-1]
method := vm.r.toObject(val)
p, _ := methods[d.idx].(*valueProperty)
if p == nil {
p = &valueProperty{
accessor: true,
}
methods[d.idx] = p
}
if p.setterFunc != nil {
vm.throw(vm.r.NewTypeError("Private setter has already been declared"))
return
}
p.setterFunc = method
vm.sp--
vm.pc++
}
type definePrivateProp struct {
idx int
}
func (d *definePrivateProp) exec(vm *vm) {
f := vm.r.toObject(vm.stack[vm.sb-1]).self.(*classFuncObject)
obj := vm.r.toObject(vm.stack[vm.sp-2])
penv := obj.self.getPrivateEnv(f.privateEnvType, false)
penv.fields[d.idx] = vm.stack[vm.sp-1]
vm.sp--
vm.pc++
}
type getPrivatePropRes resolvedPrivateName
func (vm *vm) getPrivateType(level uint8, isStatic bool) *privateEnvType {
e := vm.privEnv
for i := uint8(0); i < level; i++ {
e = e.outer
}
if isStatic {
return e.staticType
}
return e.instanceType
}
func (g *getPrivatePropRes) _get(base Value, vm *vm) Value {
return vm.getPrivateProp(base, g.name, vm.getPrivateType(g.level, g.isStatic), g.idx, g.isMethod)
}
func (g *getPrivatePropRes) exec(vm *vm) {
vm.stack[vm.sp-1] = g._get(vm.stack[vm.sp-1], vm)
vm.pc++
}
type getPrivatePropId privateId
func (g *getPrivatePropId) exec(vm *vm) {
vm.stack[vm.sp-1] = vm.getPrivateProp(vm.stack[vm.sp-1], g.name, g.typ, g.idx, g.isMethod)
vm.pc++
}
type getPrivatePropIdCallee privateId
func (g *getPrivatePropIdCallee) exec(vm *vm) {
prop := vm.getPrivateProp(vm.stack[vm.sp-1], g.name, g.typ, g.idx, g.isMethod)
if prop == nil {
prop = memberUnresolved{valueUnresolved{r: vm.r, ref: (*privateId)(g).string()}}
}
vm.push(prop)
vm.pc++
}
func (vm *vm) getPrivateProp(base Value, name unistring.String, typ *privateEnvType, idx uint32, isMethod bool) Value {
obj := vm.r.toObject(base)
penv := obj.self.getPrivateEnv(typ, false)
var v Value
if penv != nil {
if isMethod {
v = penv.methods[idx]
} else {
v = penv.fields[idx]
if v == nil {
panic(vm.r.NewTypeError("Private member #%s is accessed before it is initialized", name))
}
}
} else {
panic(vm.r.NewTypeError("Cannot read private member #%s from an object whose class did not declare it", name))
}
if prop, ok := v.(*valueProperty); ok {
if prop.getterFunc == nil {
panic(vm.r.NewTypeError("'#%s' was defined without a getter", name))
}
v = prop.get(obj)
}
return v
}
type getPrivatePropResCallee getPrivatePropRes
func (g *getPrivatePropResCallee) exec(vm *vm) {
prop := (*getPrivatePropRes)(g)._get(vm.stack[vm.sp-1], vm)
if prop == nil {
prop = memberUnresolved{valueUnresolved{r: vm.r, ref: (*resolvedPrivateName)(g).string()}}
}
vm.push(prop)
vm.pc++
}
func (vm *vm) setPrivateProp(base Value, name unistring.String, typ *privateEnvType, idx uint32, isMethod bool, val Value) {
obj := vm.r.toObject(base)
penv := obj.self.getPrivateEnv(typ, false)
if penv != nil {
if isMethod {
v := penv.methods[idx]
if prop, ok := v.(*valueProperty); ok {
if prop.setterFunc != nil {
prop.set(base, val)
} else {
panic(vm.r.NewTypeError("Cannot assign to read only property '#%s'", name))
}
} else {
panic(vm.r.NewTypeError("Private method '#%s' is not writable", name))
}
} else {
ptr := &penv.fields[idx]
if *ptr == nil {
panic(vm.r.NewTypeError("Private member #%s is accessed before it is initialized", name))
}
*ptr = val
}
} else {
panic(vm.r.NewTypeError("Cannot write private member #%s from an object whose class did not declare it", name))
}
}
func (vm *vm) exceptionFromValue(x interface{}) *Exception {
var ex *Exception
switch x1 := x.(type) {
case *Object:
ex = &Exception{
val: x1,
}
if er, ok := x1.self.(*errorObject); ok {
ex.stack = er.stack
}
case Value:
ex = &Exception{
val: x1,
}
case *Exception:
ex = x1
case typeError:
ex = &Exception{
val: vm.r.NewTypeError(string(x1)),
}
case referenceError:
ex = &Exception{
val: vm.r.newError(vm.r.getReferenceError(), string(x1)),
}
case rangeError:
ex = &Exception{
val: vm.r.newError(vm.r.getRangeError(), string(x1)),
}
case syntaxError:
ex = &Exception{
val: vm.r.newError(vm.r.getSyntaxError(), string(x1)),
}
default:
/*
if vm.prg != nil {
vm.prg.dumpCode(log.Printf)
}
log.Print("Stack: ", string(debug.Stack()))
panic(fmt.Errorf("Panic at %d: %v", vm.pc, x))
*/
return nil
}
if ex.stack == nil {
ex.stack = vm.captureStack(make([]StackFrame, 0, len(vm.callStack)+1), 0)
}
return ex
}
type setPrivatePropRes resolvedPrivateName
func (p *setPrivatePropRes) _set(base Value, val Value, vm *vm) {
vm.setPrivateProp(base, p.name, vm.getPrivateType(p.level, p.isStatic), p.idx, p.isMethod, val)
}
func (p *setPrivatePropRes) exec(vm *vm) {
v := vm.stack[vm.sp-1]
p._set(vm.stack[vm.sp-2], v, vm)
vm.stack[vm.sp-2] = v
vm.sp--
vm.pc++
}
type setPrivatePropResP setPrivatePropRes
func (p *setPrivatePropResP) exec(vm *vm) {
v := vm.stack[vm.sp-1]
(*setPrivatePropRes)(p)._set(vm.stack[vm.sp-2], v, vm)
vm.sp -= 2
vm.pc++
}
type setPrivatePropId privateId
func (p *setPrivatePropId) exec(vm *vm) {
v := vm.stack[vm.sp-1]
vm.setPrivateProp(vm.stack[vm.sp-2], p.name, p.typ, p.idx, p.isMethod, v)
vm.stack[vm.sp-2] = v
vm.sp--
vm.pc++
}
type setPrivatePropIdP privateId
func (p *setPrivatePropIdP) exec(vm *vm) {
v := vm.stack[vm.sp-1]
vm.setPrivateProp(vm.stack[vm.sp-2], p.name, p.typ, p.idx, p.isMethod, v)
vm.sp -= 2
vm.pc++
}
type popPrivateEnv struct{}
func (popPrivateEnv) exec(vm *vm) {
vm.privEnv = vm.privEnv.outer
vm.pc++
}
type privateInRes resolvedPrivateName
func (i *privateInRes) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-1])
pe := obj.self.getPrivateEnv(vm.getPrivateType(i.level, i.isStatic), false)
if pe != nil && (i.isMethod && pe.methods[i.idx] != nil || !i.isMethod && pe.fields[i.idx] != nil) {
vm.stack[vm.sp-1] = valueTrue
} else {
vm.stack[vm.sp-1] = valueFalse
}
vm.pc++
}
type privateInId privateId
func (i *privateInId) exec(vm *vm) {
obj := vm.r.toObject(vm.stack[vm.sp-1])
pe := obj.self.getPrivateEnv(i.typ, false)
if pe != nil && (i.isMethod && pe.methods[i.idx] != nil || !i.isMethod && pe.fields[i.idx] != nil) {
vm.stack[vm.sp-1] = valueTrue
} else {
vm.stack[vm.sp-1] = valueFalse
}
vm.pc++
}
type getPrivateRefRes resolvedPrivateName
func (r *getPrivateRefRes) exec(vm *vm) {
vm.refStack = append(vm.refStack, &privateRefRes{
base: vm.stack[vm.sp-1].ToObject(vm.r),
name: (*resolvedPrivateName)(r),
})
vm.sp--
vm.pc++
}
type getPrivateRefId privateId
func (r *getPrivateRefId) exec(vm *vm) {
vm.refStack = append(vm.refStack, &privateRefId{
base: vm.stack[vm.sp-1].ToObject(vm.r),
id: (*privateId)(r),
})
vm.sp--
vm.pc++
}
func (y *yieldMarker) exec(vm *vm) {
vm.pc = -vm.pc // this will terminate the run loop
vm.push(y) // marker so the caller knows it's a yield, not a return
}
func (y *yieldMarker) String() string {
if y == yieldEmpty {
return "empty"
}
switch y.resultType {
case resultYield:
return "yield"
case resultYieldRes:
return "yieldRes"
case resultYieldDelegate:
return "yield*"
case resultYieldDelegateRes:
return "yield*Res"
case resultAwait:
return "await"
default:
return "unknown"
}
}
1
https://gitee.com/quant1x/pkg.git
git@gitee.com:quant1x/pkg.git
quant1x
pkg
pkg
v0.2.8

搜索帮助

53164aa7 5694891 3bd8fe86 5694891